getByUserId( $user_id ); if ( $ppslf->getRecordCount() == 1 ) { $pps_obj = $ppslf->getCurrent(); $maximum_shift_time = $pps_obj->getMaximumShiftTime(); //Debug::Text(' aPay Period Schedule Maximum Shift Time: '. $maximum_shift_time, __FILE__, __LINE__, __METHOD__, 10); } else { //Debug::Text(' bPay Period Schedule Not Found! Using 4hrs as default', __FILE__, __LINE__, __METHOD__, 10); $maximum_shift_time = ( 3600 * 16 ); } } Debug::Text( ' cPay Period Schedule Maximum Shift Time: ' . $maximum_shift_time, __FILE__, __LINE__, __METHOD__, 10 ); return $maximum_shift_time; } /** * @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|PunchListFactory */ 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 $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|PunchListFactory */ function getByPunchControlId( $id, $where = null, $order = null ) { if ( $id == '' ) { return false; } if ( $order == null ) { $order = [ 'time_stamp' => 'desc' ]; $strict = false; } else { $strict = true; } $ph = [ 'id' => TTUUID::castUUID( $id ), ]; $query = ' select * from ' . $this->getTable() . ' as a where punch_control_id = ? AND deleted = 0'; $query .= $this->getWhereSQL( $where ); $query .= $this->getSortSQL( $order, $strict ); $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|PunchListFactory */ function getByCompanyId( $company_id, $limit = null, $page = null, $where = null, $order = null ) { if ( $company_id == '' ) { return false; } if ( $order == null ) { $order = [ 'a.time_stamp' => 'asc', 'a.status_id' => 'desc', 'a.punch_control_id' => 'asc' ]; $strict = false; } else { $strict = true; } $uf = new UserFactory(); $pcf = new PunchControlFactory(); $ph = [ 'company_id' => TTUUID::castUUID( $company_id ), ]; $query = ' select a.* from ' . $this->getTable() . ' as a, ' . $pcf->getTable() . ' as b, ' . $uf->getTable() . ' as d where a.punch_control_id = b.id AND b.user_id = d.id AND d.company_id = ? AND ( a.deleted = 0 AND b.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|PunchListFactory */ function getByIdAndCompanyId( $id, $company_id ) { return $this->getByCompanyIDAndId( $company_id, $id ); } /** * @param string $company_id UUID * @param string $id UUID * @return bool|PunchListFactory */ function getByCompanyIDAndId( $company_id, $id ) { if ( $company_id == '' ) { return false; } if ( $id == '' ) { return false; } $uf = new UserFactory(); $pcf = new PunchControlFactory(); $ph = [ 'company_id' => TTUUID::castUUID( $company_id ), ]; //Status sorting MUST be desc first, otherwise transfer punches are completely out of order. //We can't have extra columns displayed here as this is the function called before a delete, and if extra columns exist it will create a SQL error on getEmptyRecordSet() $query = ' select a.* from ' . $this->getTable() . ' as a, ' . $pcf->getTable() . ' as b, ' . $uf->getTable() . ' as d where a.punch_control_id = b.id AND b.user_id = d.id AND d.company_id = ? AND a.id in (' . $this->getListSQL( $id, $ph, 'uuid' ) . ') AND ( a.deleted = 0 AND b.deleted = 0 ) ORDER BY a.time_stamp asc, a.status_id desc, a.punch_control_id asc '; $this->rs = $this->ExecuteSQL( $query, $ph ); return $this; } /** * @param string $id UUID * @param string $company_id UUID * @return bool|PunchListFactory */ function getAPIByIdAndCompanyId( $id, $company_id ) { if ( $company_id == '' ) { return false; } if ( $id == '' ) { return false; } $uf = new UserFactory(); $pcf = new PunchControlFactory(); $ph = [ 'company_id' => TTUUID::castUUID( $company_id ), ]; //Status sorting MUST be desc first, otherwise transfer punches are completely out of order. //This function returns additional columns needed by the API to Mass Edit punches, however it CAN NOT be used to deleted //data, as the additional records cause a syntax error. $query = ' select a.*, b.branch_id as branch_id, b.department_id as department_id, b.job_id as job_id, b.job_item_id as job_item_id, b.note as note, b.user_id as user_id, b.date_stamp as date_stamp, b.pay_period_id as pay_period_id from ' . $this->getTable() . ' as a, ' . $pcf->getTable() . ' as b, ' . $uf->getTable() . ' as d where a.punch_control_id = b.id AND b.user_id = d.id AND d.company_id = ? AND a.id in (' . $this->getListSQL( $id, $ph, 'uuid' ) . ') AND ( a.deleted = 0 AND b.deleted = 0 ) ORDER BY a.time_stamp asc, a.status_id desc, a.punch_control_id asc '; $this->rs = $this->ExecuteSQL( $query, $ph ); return $this; } /** * @param string $punch_control_id UUID * @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|PunchListFactory */ function getByPunchControlIdAndStatusId( $punch_control_id, $status_id, $where = null, $order = null ) { if ( $punch_control_id == '' ) { return false; } if ( $status_id == '' ) { return false; } $pcf = new PunchControlFactory(); $ph = [ 'punch_control_id' => TTUUID::castUUID( $punch_control_id ), 'status_id' => (int)$status_id, ]; $query = ' select a.* from ' . $this->getTable() . ' as a, ' . $pcf->getTable() . ' as b where a.punch_control_id = b.id AND b.id = ? AND a.status_id = ? AND ( a.deleted = 0 AND b.deleted = 0 ) ORDER BY a.time_stamp asc, a.status_id desc, a.punch_control_id asc '; $query .= $this->getSortSQL( $order ); $this->rs = $this->ExecuteSQL( $query, $ph ); return $this; } /** * @param string $user_id UUID * @param int $date_stamp EPOCH * @param array $order Sort order passed to SQL in format of array( $column => 'asc', 'name' => 'desc', ... ). ie: array( 'id' => 'asc', 'name' => 'desc', ... ) * @return bool|PunchListFactory */ function getByUserIdAndDateStamp( $user_id, $date_stamp, $order = null ) { if ( $user_id == '' ) { return false; } if ( $date_stamp == '' ) { return false; } $pcf = new PunchControlFactory(); $ph = [ 'user_id' => TTUUID::castUUID( $user_id ), 'date_stamp' => $this->db->BindDate( $date_stamp ), ]; $query = ' select a.* from ' . $this->getTable() . ' as a, ' . $pcf->getTable() . ' as b where a.punch_control_id = b.id AND b.user_id = ? AND b.date_stamp = ? AND ( a.deleted = 0 AND b.deleted = 0 ) ORDER BY a.time_stamp asc, a.status_id desc, a.punch_control_id asc '; $query .= $this->getSortSQL( $order ); $this->rs = $this->ExecuteSQL( $query, $ph ); return $this; } /** * @param string $user_id UUID * @param $time_stamp * @param int $actual_time_stamp * @return bool|PunchListFactory */ function getDuplicatePunchByUserIdAndDateStampAndActualTime( $user_id, $time_stamp, $actual_time_stamp = 0 ) { if ( $user_id == '' ) { return false; } if ( $time_stamp == '' ) { return false; } $pcf = new PunchControlFactory(); $ph = [ 'user_id' => TTUUID::castUUID( $user_id ), 'date_stamp1' => $this->db->BindDate( ( $time_stamp - 86400 ) ), //Check one day in the past. This helps use a index and speed up the query. 'date_stamp2' => $this->db->BindDate( ( $time_stamp + 86400 ) ), //Check one day in the future. This helps use a index and speed up the query. 'time_stamp' => $this->db->BindTimeStamp( $time_stamp ), 'actual_stamp' => $this->db->BindTimeStamp( $actual_time_stamp ), ]; $query = ' select a.* from ' . $this->getTable() . ' as a, ' . $pcf->getTable() . ' as b where a.punch_control_id = b.id AND b.user_id = ? AND ( b.date_stamp >= ? AND b.date_stamp <= ? ) AND ( a.time_stamp = ? OR a.actual_time_stamp = ? ) AND ( a.deleted = 0 AND b.deleted = 0 ) LIMIT 1 '; $this->rs = $this->ExecuteSQL( $query, $ph ); //Debug::Query($query, $ph, __FILE__, __LINE__, __METHOD__, 10); return $this; } /** * @param string $user_id UUID * @param int $date_stamp EPOCH * @param int $type_id * @param array $order Sort order passed to SQL in format of array( $column => 'asc', 'name' => 'desc', ... ). ie: array( 'id' => 'asc', 'name' => 'desc', ... ) * @return bool|PunchListFactory */ function getByUserIdAndDateStampAndType( $user_id, $date_stamp, $type_id, $order = null ) { if ( $user_id == '' ) { return false; } if ( $date_stamp == '' ) { return false; } if ( $type_id == '' ) { return false; } $pcf = new PunchControlFactory(); $ph = [ 'user_id' => TTUUID::castUUID( $user_id ), 'date_stamp' => $this->db->BindDate( $date_stamp ), 'type_id' => (int)$type_id, ]; $query = ' select a.* from ' . $this->getTable() . ' as a, ' . $pcf->getTable() . ' as b where a.punch_control_id = b.id AND b.user_id = ? AND b.date_stamp = ? AND a.type_id = ? AND ( a.deleted = 0 AND b.deleted = 0 ) ORDER BY a.time_stamp asc, a.status_id desc, a.punch_control_id asc '; $query .= $this->getSortSQL( $order ); $this->rs = $this->ExecuteSQL( $query, $ph ); return $this; } /** * @param string $user_id UUID * @param int $date_stamp EPOCH * @param string|string[] $punch_control_id UUID * @param array $order Sort order passed to SQL in format of array( $column => 'asc', 'name' => 'desc', ... ). ie: array( 'id' => 'asc', 'name' => 'desc', ... ) * @return bool|PunchListFactory */ function getByUserIdAndDateStampAndNotPunchControlId( $user_id, $date_stamp, $punch_control_id, $order = null ) { if ( $user_id == '' ) { return false; } if ( $date_stamp == '' ) { return false; } $pcf = new PunchControlFactory(); $ph = [ 'user_id' => TTUUID::castUUID( $user_id ), 'date_stamp' => $this->db->BindDate( $date_stamp ), ]; $query = ' select a.* from ' . $this->getTable() . ' as a, ' . $pcf->getTable() . ' as b where a.punch_control_id = b.id AND b.user_id = ? AND b.date_stamp = ? AND a.punch_control_id not in (' . $this->getListSQL( $punch_control_id, $ph, 'uuid' ) . ') AND ( a.deleted = 0 AND b.deleted = 0 ) ORDER BY a.time_stamp asc, a.status_id desc, a.punch_control_id asc '; $query .= $this->getSortSQL( $order ); $this->rs = $this->ExecuteSQL( $query, $ph ); return $this; } /** * @param string $user_id UUID * @param int $epoch EPOCH * @param array $order Sort order passed to SQL in format of array( $column => 'asc', 'name' => 'desc', ... ). ie: array( 'id' => 'asc', 'name' => 'desc', ... ) * @return bool|PunchListFactory */ function getNextPunchByUserIdAndEpoch( $user_id, $epoch, $order = null ) { if ( $user_id == '' ) { return false; } if ( $epoch == '' ) { return false; } $pcf = new PunchControlFactory(); $ph = [ 'user_id' => TTUUID::castUUID( $user_id ), 'time_stamp' => $this->db->BindTimeStamp( $epoch ), ]; //Status order matters, because if its a.status_id desc, OUT comes first, but if the last //punch doesn't have OUT yet, it defaults to IN // with a.status_id asc... $query = ' select a.* from ' . $this->getTable() . ' as a, ' . $pcf->getTable() . ' as b where a.punch_control_id = b.id AND b.user_id = ? AND a.time_stamp >= ? AND ( a.deleted = 0 AND b.deleted = 0 ) ORDER BY a.time_stamp asc LIMIT 1 '; $query .= $this->getSortSQL( $order ); $this->rs = $this->ExecuteSQL( $query, $ph ); return $this; } /** * @param $has_image * @param int $date_stamp 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|PunchListFactory */ function getByHasImageAndCreatedDate( $has_image, $date_stamp, $limit = null, $page = null, $where = null, $order = null ) { $has_image = (bool)$has_image; if ( $date_stamp == '' ) { return false; } if ( $order == null ) { $order = [ 'time_stamp' => 'asc', 'status_id' => 'desc', 'punch_control_id' => 'asc' ]; $strict = false; } else { $strict = true; } $pcf = new PunchControlFactory(); $ph = [ 'has_image' => (int)$has_image, 'date_stamp' => (int)$date_stamp, ]; $query = ' select a.*, b.user_id as user_id from ' . $this->getTable() . ' as a LEFT JOIN ' . $pcf->getTable() . ' as b ON ( a.punch_control_id = b.id ) where a.has_image = ? AND a.created_date < ? AND ( a.deleted = 0 AND b.deleted = 0 ) '; $query .= $this->getWhereSQL( $where ); $query .= $this->getSortSQL( $order, $strict ); $this->rs = $this->ExecuteSQL( $query, $ph, $limit, $page ); return $this; } function getCompletePunchControlIdByUserIdAndEpoch( $user_id, $epoch, $maximum_shift_time = null ) { if ( $user_id == '' ) { return false; } if ( $epoch == '' ) { return false; } if ( $maximum_shift_time == '' ) { $maximum_shift_time = $this->getPayPeriodMaximumShiftTime( $user_id, $maximum_shift_time ); } $pcf = new PunchControlFactory(); $ph = [ 'user_id' => TTUUID::castUUID( $user_id ), 'time_stamp1_start' => $this->db->BindTimeStamp( $epoch ), 'time_stamp1_end' => $this->db->BindTimeStamp( ( $epoch - $maximum_shift_time ) ), 'time_stamp2' => $this->db->BindTimeStamp( $epoch ), ]; //Find a punch immediately before the current epoch (within maximum shift time), // then using that punch_control_id (within the same punch pair) find a punch immediately after the current epoch. // This is required to make sure we find a complete punch pair that encapsulates the current epoch. $query = ' SELECT pf_b.punch_control_id FROM ' . $this->getTable() . ' as pf_b WHERE pf_b.punch_control_id = ( SELECT pf.punch_control_id as punch_control_id FROM ' . $this->getTable() . ' as pf LEFT JOIN '. $pcf->getTable() .' as pcf ON ( pf.punch_control_id = pcf.id ) WHERE pcf.user_id = ? AND pf.time_stamp < ? AND pf.time_stamp > ? AND ( pf.deleted = 0 AND pcf.deleted = 0 ) ORDER BY pf.time_stamp desc, pf.status_id asc, pf.punch_control_id, pf.id LIMIT 1 ) AND pf_b.time_stamp > ? AND ( pf_b.deleted = 0 ) '; //Debug::Query( $query, $ph, __FILE__, __LINE__, __METHOD__, 10); $rows = $this->db->getCol( $query, $ph ); if ( count( $rows ) == 1 ) { $retval = $rows[0]; Debug::Text( ' Found complete Punch Control ID: '. $retval, __FILE__, __LINE__, __METHOD__, 10); return $retval; } else { Debug::Text( ' Incorrect number of rows found: '. count( $rows ), __FILE__, __LINE__, __METHOD__, 10); } return false; } /** * @param string $user_id UUID * @param int $epoch EPOCH * @param int $punch_control_id * @param null $maximum_shift_time * @param bool $ignore_future_punches * @return bool|PunchListFactory */ function getShiftPunchesByUserIDAndEpoch( $user_id, $epoch, $punch_control_id = 0, $maximum_shift_time = null, $ignore_future_punches = false ) { if ( $user_id == '' ) { return false; } if ( $epoch == '' ) { return false; } if ( $punch_control_id === 0 ) { $punch_control_id = TTUUID::getZeroID(); } if ( $maximum_shift_time == '' ) { $maximum_shift_time = $this->getPayPeriodMaximumShiftTime( $user_id, $maximum_shift_time ); } //Make sure that we get all punches surrounding the EPOCH within the maximum shift time, //We also need to take into account punch pairs, for example: // Punch Pair: 10-Mar-09 @ 11:30PM -> 11-Mar-09 @ 2:30PM. If the maximum shift time ends at 11:45PM // we need to include the out punch as well. $start_time_stamp = ( $epoch - $maximum_shift_time ); if ( $ignore_future_punches == true ) { Debug::Text( 'Ignoring Future Punches...', __FILE__, __LINE__, __METHOD__, 10 ); $end_time_stamp = $epoch; } else { $end_time_stamp = ( $epoch + $maximum_shift_time ); } $pcf = new PunchControlFactory(); $ph = [ 'user_id' => TTUUID::castUUID( $user_id ), 'start_date_stamp' => $this->db->BindDate( $start_time_stamp ), 'end_date_stamp' => $this->db->BindDate( $end_time_stamp ), 'start_time_stamp2' => $this->db->BindTimeStamp( $start_time_stamp ), 'end_time_stamp2' => $this->db->BindTimeStamp( $end_time_stamp ), ]; //Order by a.punch_control_id is extremely important here so two punches at the same time, one paired already, and one not paired don't come in the wrong order, and cause getShiftData() to handle them incorrectly. //Order by time_stamp asc, status_id desc, so when transfer punches exist at the same time, the out punch comes first, then the in punch (proper order on the timesheet). // Ordering by timestamp first means only if identical times exist it will matter anyways. // This is needed when handing getDefaultPunchSettings() when there are auto-punch schedule shifts in the future, and transfer punches in the past. $query = ' SELECT DISTINCT a.* FROM ' . $this->getTable() . ' as a INNER JOIN ( select \'' . TTUUID::castUUID( $punch_control_id ) . '\' as punch_control_id UNION ALL select x.punch_control_id from ' . $this->getTable() . ' as x LEFT JOIN ' . $pcf->getTable() . ' as y ON x.punch_control_id = y.id where y.user_id = ? AND y.date_stamp >= ? AND y.date_stamp <= ? AND x.time_stamp >= ? AND x.time_stamp <= ? AND ( x.deleted = 0 AND y.deleted=0 ) ) as z ON a.punch_control_id = z.punch_control_id WHERE a.deleted = 0 ORDER BY a.time_stamp asc, a.status_id desc, a.punch_control_id, a.id '; //$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 $start_date EPOCH * @param int $end_date EPOCH * @param int $punch_control_id * @param null $maximum_shift_time * @return bool|PunchListFactory */ function getShiftPunchesByUserIDAndStartDateAndEndDate( $user_id, $start_date, $end_date, $punch_control_id = 0, $maximum_shift_time = null ) { if ( $user_id == '' ) { return false; } if ( $start_date == '' ) { return false; } if ( $end_date == '' ) { return false; } if ( $punch_control_id === 0 ) { $punch_control_id = TTUUID::getZeroID(); } if ( $maximum_shift_time == '' ) { $maximum_shift_time = $this->getPayPeriodMaximumShiftTime( $user_id, $maximum_shift_time ); } //Make sure that we get all punches surrounding the EPOCH within the maximum shift time, //We also need to take into account punch pairs, for example: // Punch Pair: 10-Mar-09 @ 11:30PM -> 11-Mar-09 @ 2:30PM. If the maximum shift time ends at 11:45PM // we need to include the out punch as well. $start_time_stamp = ( $start_date - $maximum_shift_time ); $end_time_stamp = ( $end_date + $maximum_shift_time ); $pcf = new PunchControlFactory(); $ph = [ 'user_id' => TTUUID::castUUID( $user_id ), 'start_date_stamp' => $this->db->BindDate( $start_time_stamp ), 'end_date_stamp' => $this->db->BindDate( $end_time_stamp ), //'start_time_stamp2' => $this->db->BindTimeStamp( $start_time_stamp ), //Always include all punches on the entire day, so we don't split shifts on lunch punches. //'end_time_stamp2' => $this->db->BindTimeStamp( $end_time_stamp ), ]; // AND x.time_stamp >= ? // AND x.time_stamp <= ? $query = ' select distinct a.*, pcf.date_stamp from ' . $this->getTable() . ' as a INNER JOIN ( select \'' . TTUUID::castUUID( $punch_control_id ) . '\' as punch_control_id UNION ALL select x.punch_control_id from ' . $this->getTable() . ' as x LEFT JOIN ' . $pcf->getTable() . ' as y ON x.punch_control_id = y.id where y.user_id = ? AND y.date_stamp >= ? AND y.date_stamp <= ? AND ( x.deleted = 0 AND y.deleted = 0 ) ) as z ON a.punch_control_id = z.punch_control_id LEFT JOIN ' . $pcf->getTable() . ' as pcf ON ( a.punch_control_id = pcf.id ) WHERE a.deleted = 0 ORDER BY a.time_stamp asc, a.punch_control_id, a.status_id asc '; //$query .= $this->getSortSQL( $order ); $this->rs = $this->ExecuteSQL( $query, $ph ); //Debug::Query( $query, $ph, __FILE__, __LINE__, __METHOD__, 10); return $this; } /** * Used by premium policies to filter punches based on shift differential so we can then pass them into getShiftData(). * Mainly used for Minimum Shift time premium policies that are restricted by shift differential criteria. * @param string $user_id UUID * @param int $epoch EPOCH * @param $filter_data * @param int $punch_control_id * @param null $maximum_shift_time * @return bool|PunchListFactory */ function getShiftPunchesByUserIDAndEpochAndArrayCriteria( $user_id, $epoch, $filter_data, $punch_control_id = 0, $maximum_shift_time = null ) { if ( $user_id == '' ) { return false; } if ( $epoch == '' ) { return false; } if ( $punch_control_id === 0 ) { $punch_control_id = TTUUID::getZeroID(); } if ( $maximum_shift_time == '' ) { $maximum_shift_time = $this->getPayPeriodMaximumShiftTime( $user_id, $maximum_shift_time ); } //Make sure that we get all punches surrounding the EPOCH within the maximum shift time, //We also need to take into account punch pairs, for example: // Punch Pair: 10-Mar-09 @ 11:30PM -> 11-Mar-09 @ 2:30PM. If the maximum shift time ends at 11:45PM // we need to include the out punch as well. $start_time_stamp = ( $epoch - $maximum_shift_time ); $end_time_stamp = ( $epoch + $maximum_shift_time ); $pcf = new PunchControlFactory(); $ppbf = new PremiumPolicyBranchFactory(); $ppdf = new PremiumPolicyDepartmentFactory(); if ( getTTProductEdition() >= TT_PRODUCT_CORPORATE ) { $jf = new JobFactory(); $jif = new JobItemFactory(); $ppjgf = new PremiumPolicyJobGroupFactory(); $ppjf = new PremiumPolicyJobFactory(); $ppjigf = new PremiumPolicyJobItemGroupFactory(); $ppjif = new PremiumPolicyJobItemFactory(); } $ph = [ 'user_id' => TTUUID::castUUID( $user_id ), 'start_date_stamp' => $this->db->BindDate( $start_time_stamp ), 'end_date_stamp' => $this->db->BindDate( $end_time_stamp ), 'start_time_stamp2' => $this->db->BindTimeStamp( $start_time_stamp ), 'end_time_stamp2' => $this->db->BindTimeStamp( $end_time_stamp ), ]; $query = ' select distinct a.* from ' . $this->getTable() . ' as a INNER JOIN ( select \'' . TTUUID::castUUID( $punch_control_id ) . '\' as punch_control_id UNION ALL select x.punch_control_id from ' . $this->getTable() . ' as x LEFT JOIN ' . $pcf->getTable() . ' as pcf ON x.punch_control_id = pcf.id '; if ( getTTProductEdition() >= TT_PRODUCT_CORPORATE ) { $query .= ' LEFT JOIN ' . $jf->getTable() . ' as jf ON (pcf.job_id = jf.id AND jf.deleted = 0 )'; $query .= ' LEFT JOIN ' . $jif->getTable() . ' as jif ON (pcf.job_item_id = jif.id AND jf.deleted = 0 )'; } $query .= ' where pcf.user_id = ? AND pcf.date_stamp >= ? AND pcf.date_stamp <= ? AND x.time_stamp >= ? AND x.time_stamp <= ? '; //Branch criteria if ( isset( $filter_data['exclude_default_branch'] ) && $filter_data['exclude_default_branch'] == true && isset( $filter_data['default_branch_id'] ) ) { $query .= $this->getWhereClauseSQL( 'pcf.branch_id', $filter_data['default_branch_id'], 'not_uuid_list', $ph ); } if ( isset( $filter_data['branch_selection_type_id'] ) && $filter_data['branch_selection_type_id'] == 20 && isset( $filter_data['premium_policy_id'] ) ) { $query .= ' AND pcf.branch_id in ( select zz.branch_id from ' . $ppbf->getTable() . ' as zz WHERE zz.premium_policy_id = \'' . TTUUID::castUUID( $filter_data['premium_policy_id'] ) . '\' ) '; } else if ( isset( $filter_data['branch_selection_type_id'] ) && $filter_data['branch_selection_type_id'] == 30 && isset( $filter_data['premium_policy_id'] ) ) { $query .= ' AND pcf.branch_id not in ( select zz.branch_id from ' . $ppbf->getTable() . ' as zz WHERE zz.premium_policy_id = \'' . TTUUID::castUUID( $filter_data['premium_policy_id'] ) . '\' ) '; } //Department criteria if ( isset( $filter_data['exclude_default_department'] ) && $filter_data['exclude_default_department'] == true && isset( $filter_data['default_department_id'] ) ) { $query .= $this->getWhereClauseSQL( 'pcf.department_id', $filter_data['default_department_id'], 'not_uuid_list', $ph ); } if ( isset( $filter_data['department_selection_type_id'] ) && $filter_data['department_selection_type_id'] == 20 && isset( $filter_data['premium_policy_id'] ) ) { $query .= ' AND pcf.department_id in ( select zz.department_id from ' . $ppdf->getTable() . ' as zz WHERE zz.premium_policy_id = \'' . TTUUID::castUUID( $filter_data['premium_policy_id'] ) . '\' ) '; } else if ( isset( $filter_data['department_selection_type_id'] ) && $filter_data['department_selection_type_id'] == 30 && isset( $filter_data['premium_policy_id'] ) ) { $query .= ' AND pcf.department_id not in ( select zz.department_id from ' . $ppdf->getTable() . ' as zz WHERE zz.premium_policy_id = \'' . TTUUID::castUUID( $filter_data['premium_policy_id'] ) . '\' ) '; } if ( getTTProductEdition() >= TT_PRODUCT_CORPORATE ) { //Job Group Criteria if ( isset( $filter_data['job_group_selection_type_id'] ) && $filter_data['job_group_selection_type_id'] == 20 && isset( $filter_data['premium_policy_id'] ) ) { $query .= ' AND jf.group_id in ( select zz.job_group_id from ' . $ppjgf->getTable() . ' as zz WHERE zz.premium_policy_id = \'' . TTUUID::castUUID( $filter_data['premium_policy_id'] ) . '\' ) '; } else if ( isset( $filter_data['job_group_selection_type_id'] ) && $filter_data['job_group_selection_type_id'] == 30 && isset( $filter_data['premium_policy_id'] ) ) { $query .= ' AND jf.group_id not in ( select zz.job_group_id from ' . $ppjgf->getTable() . ' as zz WHERE zz.premium_policy_id = \'' . TTUUID::castUUID( $filter_data['premium_policy_id'] ) . '\' ) '; } //Job Criteria if ( isset( $filter_data['job_selection_type_id'] ) && $filter_data['job_selection_type_id'] == 20 && isset( $filter_data['premium_policy_id'] ) ) { $query .= ' AND pcf.job_id in ( select zz.job_id from ' . $ppjf->getTable() . ' as zz WHERE zz.premium_policy_id = \'' . TTUUID::castUUID( $filter_data['premium_policy_id'] ) . '\' ) '; } else if ( isset( $filter_data['job_selection_type_id'] ) && $filter_data['job_selection_type_id'] == 30 && isset( $filter_data['premium_policy_id'] ) ) { $query .= ' AND pcf.job_id not in ( select zz.job_id from ' . $ppjf->getTable() . ' as zz WHERE zz.premium_policy_id = \'' . TTUUID::castUUID( $filter_data['premium_policy_id'] ) . '\' ) '; } //Task Group Criteria if ( isset( $filter_data['job_item_group_selection_type_id'] ) && $filter_data['job_item_group_selection_type_id'] == 20 && isset( $filter_data['premium_policy_id'] ) ) { $query .= ' AND jif.group_id in ( select zz.job_item_group_id from ' . $ppjigf->getTable() . ' as zz WHERE zz.premium_policy_id = \'' . TTUUID::castUUID( $filter_data['premium_policy_id'] ) . '\' ) '; } else if ( isset( $filter_data['job_item_group_selection_type_id'] ) && $filter_data['job_item_group_selection_type_id'] == 30 && isset( $filter_data['premium_policy_id'] ) ) { $query .= ' AND jif.group_id not in ( select zz.job_item_group_id from ' . $ppjigf->getTable() . ' as zz WHERE zz.premium_policy_id = \'' . TTUUID::castUUID( $filter_data['premium_policy_id'] ) . '\' ) '; } //Task Criteria if ( isset( $filter_data['job_item_selection_type_id'] ) && $filter_data['job_item_selection_type_id'] == 20 && isset( $filter_data['premium_policy_id'] ) ) { $query .= ' AND pcf.job_item_id in ( select zz.job_item_id from ' . $ppjif->getTable() . ' as zz WHERE zz.premium_policy_id = \'' . TTUUID::castUUID( $filter_data['premium_policy_id'] ) . '\' ) '; } else if ( isset( $filter_data['job_item_selection_type_id'] ) && $filter_data['job_item_selection_type_id'] == 30 && isset( $filter_data['premium_policy_id'] ) ) { $query .= ' AND pcf.job_item_id not in ( select zz.job_item_id from ' . $ppjif->getTable() . ' as zz WHERE zz.premium_policy_id = \'' . TTUUID::castUUID( $filter_data['premium_policy_id'] ) . '\' ) '; } } $query .= ' AND ( x.deleted = 0 AND pcf.deleted = 0 ) ) as z ON a.punch_control_id = z.punch_control_id WHERE a.deleted = 0 ORDER BY a.time_stamp asc, a.punch_control_id, a.status_id asc '; //$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 * @param null $maximum_shift_time * @return bool|PunchListFactory */ function getFirstPunchByUserIDAndEpoch( $user_id, $epoch, $maximum_shift_time = null ) { if ( $user_id == '' ) { return false; } if ( $epoch == '' ) { return false; } if ( $maximum_shift_time == '' ) { $maximum_shift_time = $this->getPayPeriodMaximumShiftTime( $user_id, $maximum_shift_time ); } $user_date_stamp = TTDate::getBeginDayEpoch( $epoch - $maximum_shift_time ); $pcf = new PunchControlFactory(); $ph = [ 'user_id' => TTUUID::castUUID( $user_id ), 'user_date_stamp' => $this->db->BindDate( $user_date_stamp ), ]; $query = ' select a.* from ' . $this->getTable() . ' as a, ' . $pcf->getTable() . ' as b where a.punch_control_id = b.id AND b.user_id = ? AND b.date_stamp = ? AND ( a.deleted = 0 AND b.deleted = 0 ) ORDER BY a.time_stamp asc, a.status_id asc LIMIT 1 '; //$query .= $this->getSortSQL( $order ); $this->rs = $this->ExecuteSQL( $query, $ph ); return $this; } /** * @param string $user_id UUID * @param int $epoch EPOCH * @param array $order Sort order passed to SQL in format of array( $column => 'asc', 'name' => 'desc', ... ). ie: array( 'id' => 'asc', 'name' => 'desc', ... ) * @return bool|PunchListFactory */ function getPreviousPunchByUserIdAndEpoch( $user_id, $epoch, $order = null ) { Debug::Text( ' User ID: ' . $user_id . ' Epoch: ' . $epoch, __FILE__, __LINE__, __METHOD__, 10 ); if ( $user_id == '' ) { return false; } if ( $epoch == '' ) { return false; } //Punches are always rounded to the nearest minute, so in cases like the mobile app where the punch is saved then immediately refreshed //it may not get the proper data because the actual punch time is 12:41:45 but the punch was saved as 12:42:00. //Therefore round the epoch time up to the next minute to help avoid this. However if punch times are ever rounded up more than 1 minute the issue still persists. // However this can cause other problems, like with duplicate punch detection when automatic punch status is enabled. // If the same punch is submitted twice, it will be recorded as an IN then an OUT rather than be rejected. // Therefore we just need to account for this when processing punches from the timeclock. $epoch = TTDate::roundTime( $epoch, 60, 30 ); $maximum_shift_time = $this->getPayPeriodMaximumShiftTime( $user_id ); $start_time = ( $epoch - $maximum_shift_time ); Debug::Text( ' Start Time: ' . TTDate::getDate( 'DATE+TIME', $start_time ), __FILE__, __LINE__, __METHOD__, 10 ); $pcf = new PunchControlFactory(); $ph = [ 'user_id' => TTUUID::castUUID( $user_id ), 'start_date' => $this->db->BindDate( $start_time ), 'end_date' => $this->db->BindDate( $epoch ), 'start_time' => $this->db->BindTimeStamp( $start_time ), 'end_time' => $this->db->BindTimeStamp( $epoch ), ]; //Status order matters, because if its a.status_id desc, OUT comes first, but if the last //punch doesn't have OUT yet, it defaults to IN // with a.status_id asc... //Include date_stamp filter on user_date table as this greatly speeds up the query when its not already cached. $query = ' select a.* from ' . $this->getTable() . ' as a, ' . $pcf->getTable() . ' as b where a.punch_control_id = b.id AND b.user_id = ? AND b.date_stamp >= ? AND b.date_stamp <= ? AND a.time_stamp >= ? AND a.time_stamp <= ? AND ( a.deleted = 0 AND b.deleted = 0 ) ORDER BY a.time_stamp desc, a.status_id asc LIMIT 1 '; $query .= $this->getSortSQL( $order ); //Debug::Text(' Query: '. $query, __FILE__, __LINE__, __METHOD__, 10); $this->rs = $this->ExecuteSQL( $query, $ph ); return $this; } /** * @param string $user_id UUID * @param int $epoch EPOCH * @param string $punch_id UUID * @param null $maximum_shift_time * @param array $order Sort order passed to SQL in format of array( $column => 'asc', 'name' => 'desc', ... ). ie: array( 'id' => 'asc', 'name' => 'desc', ... ) * @return bool|PunchListFactory */ function getPreviousPunchByUserIdAndEpochAndNotPunchIDAndMaximumShiftTime( $user_id, $epoch, $punch_id, $maximum_shift_time = null, $order = null ) { Debug::Text( ' User ID: ' . $user_id . ' Epoch: ' . $epoch, __FILE__, __LINE__, __METHOD__, 10 ); if ( $user_id == '' ) { return false; } if ( $epoch == '' || $epoch <= 0 ) { return false; } $maximum_shift_time = $this->getPayPeriodMaximumShiftTime( $user_id, $maximum_shift_time ); $start_time = ( $epoch - $maximum_shift_time ); Debug::Text( ' Start Time: ' . TTDate::getDate( 'DATE+TIME', $start_time ), __FILE__, __LINE__, __METHOD__, 10 ); $pcf = new PunchControlFactory(); $ph = [ 'user_id' => TTUUID::castUUID( $user_id ), 'start_date' => $this->db->BindDate( $start_time ), 'end_date' => $this->db->BindDate( $epoch ), 'start_time' => $this->db->BindTimeStamp( $start_time ), 'end_time' => $this->db->BindTimeStamp( $epoch ), 'punch_id' => TTUUID::castUUID( $punch_id ), ]; //Status order matters, because if its a.status_id desc, OUT comes first, but if the last //punch doesn't have OUT yet, it defaults to IN // with a.status_id asc... $query = ' select a.* from ' . $this->getTable() . ' as a, ' . $pcf->getTable() . ' as b where a.punch_control_id = b.id AND b.user_id = ? AND b.date_stamp >= ? AND b.date_stamp <= ? AND a.time_stamp >= ? AND a.time_stamp <= ? AND a.id != ? AND ( a.deleted = 0 AND b.deleted = 0 ) ORDER BY a.time_stamp desc, a.status_id asc LIMIT 1 '; $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 $status_id * @param int|int[] $type_id * @param int $epoch EPOCH * @param array $order Sort order passed to SQL in format of array( $column => 'asc', 'name' => 'desc', ... ). ie: array( 'id' => 'asc', 'name' => 'desc', ... ) * @return bool|PunchListFactory */ function getPreviousPunchByUserIdAndStatusAndTypeAndEpoch( $user_id, $status_id, $type_id, $epoch, $order = null ) { if ( $user_id == '' ) { return false; } if ( $status_id == '' ) { return false; } if ( $type_id == '' ) { return false; } if ( $epoch == '' ) { return false; } $pcf = new PunchControlFactory(); $ph = [ 'user_id' => TTUUID::castUUID( $user_id ), 'date_stamp1' => $this->db->BindDate( ( TTDate::getMiddleDayEpoch( $epoch ) - 86400 ) ), 'date_stamp2' => $this->db->BindDate( ( TTDate::getMiddleDayEpoch( $epoch ) + 86400 ) ), 'time_stamp' => $this->db->BindTimeStamp( $epoch ), 'status_id' => (int)$status_id, //'type_id' => (int)$type_id, ]; //Narrow down the c.date_stamp column to speed this query up, as sometimes it can be so slow that connections timeout. //Status order matters, because if its a.status_id desc, OUT comes first, but if the last //punch doesn't have OUT yet, it defaults to IN // with a.status_id asc... $query = ' select a.* from ' . $this->getTable() . ' as a, ' . $pcf->getTable() . ' as b where a.punch_control_id = b.id AND b.user_id = ? AND ( b.date_stamp >= ? AND b.date_stamp <= ? ) AND a.time_stamp <= ? AND a.status_id = ? AND a.type_id in ( ' . $this->getListSQL( $type_id, $ph, 'int' ) . ' ) AND ( a.deleted = 0 AND b.deleted = 0 ) ORDER BY a.time_stamp desc LIMIT 1 '; $query .= $this->getSortSQL( $order ); //Debug::Query( $query, $ph, __FILE__, __LINE__, __METHOD__, 10); $this->rs = $this->ExecuteSQL( $query, $ph ); return $this; } /** * @param string $punch_id UUID * @param array $order Sort order passed to SQL in format of array( $column => 'asc', 'name' => 'desc', ... ). ie: array( 'id' => 'asc', 'name' => 'desc', ... ) * @return bool|PunchListFactory */ function getPreviousPunchByPunchId( $punch_id, $order = null ) { if ( $punch_id == '' ) { return false; } $pcf = new PunchControlFactory(); $ph = [ 'punch_id' => TTUUID::castUUID( $punch_id ), ]; $query = ' select a.* from ' . $this->getTable() . ' as a, ' . $pcf->getTable() . ' as b where a.punch_control_id = b.id AND b.user_id = (select z.user_id from ' . $pcf->getTable() . ' as z where z.id = b.punch_control_id) AND b.date_stamp = (select z.date_stamp from ' . $pcf->getTable() . ' as z where z.id = b.punch_control_id) AND a.id = ? AND ( a.deleted = 0 AND b.deleted=0 ) ORDER BY a.time_stamp asc, a.status_id desc, a.punch_control_id asc LIMIT 1 '; $query .= $this->getSortSQL( $order ); $this->rs = $this->ExecuteSQL( $query, $ph ); return $this; } /** * @param string $punch_control_id UUID * @param array $order Sort order passed to SQL in format of array( $column => 'asc', 'name' => 'desc', ... ). ie: array( 'id' => 'asc', 'name' => 'desc', ... ) * @return bool|PunchListFactory */ function getPreviousPunchByPunchControlId( $punch_control_id, $order = null ) { if ( $punch_control_id == '' ) { return false; } $pcf = new PunchControlFactory(); $ph = [ 'punch_control_id' => TTUUID::castUUID( $punch_control_id ), ]; $query = ' select a.* from ' . $this->getTable() . ' as a, ' . $pcf->getTable() . ' as b where a.punch_control_id = b.id AND b.id = ? AND ( a.deleted = 0 AND b.deleted=0 ) ORDER BY a.time_stamp asc, a.status_id desc, a.punch_control_id asc LIMIT 1 '; $query .= $this->getSortSQL( $order ); $this->rs = $this->ExecuteSQL( $query, $ph ); return $this; } /** * @param string $company_id UUID * @param string $user_id UUID * @param int $type_id * @param int $status_id * @param int $start_date EPOCH * @param int $end_date EPOCH * @return bool */ function getMostCommonPunchDataByCompanyIdAndUserAndTypeAndStatusAndStartDateAndEndDate( $company_id, $user_id, $type_id, $status_id, $start_date, $end_date, $exclude_transfer_punches = null ) { if ( $company_id == '' ) { return false; } if ( $user_id == '' ) { return false; } if ( $type_id == '' ) { return false; } if ( $status_id == '' ) { return false; } if ( $start_date == '' ) { return false; } if ( $end_date == '' ) { return false; } $uf = new UserFactory(); $pcf = new PunchControlFactory(); $ph = [ 'company_id' => TTUUID::castUUID( $company_id ), 'user_id' => TTUUID::castUUID( $user_id ), 'type_id' => (int)$type_id, 'status_id' => (int)$status_id, 'start_date' => $this->db->BindDate( $start_date ), 'end_date' => $this->db->BindDate( $end_date ), ]; $query = ' SELECT ' . $this->getSQLToTimeFunction( 'a.time_stamp' ) . ' as time_stamp FROM ' . $this->getTable() . ' as a, ' . $pcf->getTable() . ' as b, ' . $uf->getTable() . ' as d WHERE a.punch_control_id = b.id AND b.user_id = d.id AND d.company_id = ? AND b.user_id = ? AND a.type_id = ? AND a.status_id = ? AND b.date_stamp >= ? AND b.date_stamp <= ? '; $query .= ( isset( $exclude_transfer_punches ) && $exclude_transfer_punches === true ) ? $this->getWhereClauseSQL( 'a.transfer', 0, 'int', $ph ) : null; $query .= ' AND ( a.deleted = 0 AND b.deleted = 0 ) GROUP BY ' . $this->getSQLToTimeFunction( 'a.time_stamp' ) . ' ORDER BY count(*) DESC LIMIT 1'; $result = $this->db->GetRow( $query, $ph ); //Debug::Query( $query, $ph, __FILE__, __LINE__, __METHOD__, 10); return $result; } /** * @param string $company_id UUID * @param string $user_id UUID * @param int $start_date EPOCH * @param int $end_date EPOCH * @return bool|PunchListFactory */ function getByCompanyIDAndUserIdAndStartDateAndEndDate( $company_id, $user_id, $start_date, $end_date ) { if ( $company_id == '' ) { return false; } if ( $user_id == '' ) { return false; } if ( $start_date == '' ) { return false; } if ( $end_date == '' ) { return false; } $uf = new UserFactory(); $pcf = new PunchControlFactory(); $ph = [ 'company_id' => TTUUID::castUUID( $company_id ), 'user_id' => TTUUID::castUUID( $user_id ), 'start_date' => $this->db->BindDate( $start_date ), 'end_date' => $this->db->BindDate( $end_date ), ]; //Status sorting MUST be desc first, otherwise transfer punches are completely out of order. $query = ' select a.*, b.date_stamp as user_date_stamp, b.note as note from ' . $this->getTable() . ' as a, ' . $pcf->getTable() . ' as b, ' . $uf->getTable() . ' as d where a.punch_control_id = b.id AND b.user_id = d.id AND d.company_id = ? AND b.user_id = ? AND b.date_stamp >= ? AND b.date_stamp <= ? AND ( a.deleted = 0 AND b.deleted = 0 ) ORDER BY a.time_stamp asc, a.status_id desc, a.punch_control_id asc '; $this->rs = $this->ExecuteSQL( $query, $ph ); return $this; } /** * @param string $user_id UUID * @param array $order Sort order passed to SQL in format of array( $column => 'asc', 'name' => 'desc', ... ). ie: array( 'id' => 'asc', 'name' => 'desc', ... ) * @return bool|PunchListFactory */ function getLastPunchByUserId( $user_id, $order = null ) { if ( $user_id == '' ) { return false; } $pcf = new PunchControlFactory(); $uf = new UserFactory(); $ph = [ 'user_id' => TTUUID::castUUID( $user_id ), ]; //Status order matters, because if its a.status_id desc, OUT comes first, but if the last //punch doesn't have OUT yet, it defaults to IN // with a.status_id asc... $query = ' select a.* from ' . $this->getTable() . ' as a, ' . $pcf->getTable() . ' as b, ' . $uf->getTable() . ' as d where a.punch_control_id = b.id AND b.user_id = d.id AND d.id = ? AND ( a.deleted = 0 AND b.deleted = 0 ) ORDER BY a.time_stamp desc LIMIT 1 '; $query .= $this->getSortSQL( $order ); $this->rs = $this->ExecuteSQL( $query, $ph ); return $this; } /** * @param string $pay_period_id UUID * @param array $order Sort order passed to SQL in format of array( $column => 'asc', 'name' => 'desc', ... ). ie: array( 'id' => 'asc', 'name' => 'desc', ... ) * @return bool|PunchListFactory */ function getByPayPeriodId( $pay_period_id, $order = null ) { if ( $pay_period_id == '' ) { return false; } $pcf = new PunchControlFactory(); $ph = [ 'pay_period_id' => TTUUID::castUUID( $pay_period_id ), ]; $query = ' select a.* from ' . $this->getTable() . ' as a, ' . $pcf->getTable() . ' as b where a.punch_control_id = b.id AND b.pay_period_id = ? AND ( a.deleted = 0 AND b.deleted = 0 ) '; $query .= $this->getSortSQL( $order ); $this->rs = $this->ExecuteSQL( $query, $ph ); 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|PunchListFactory */ function getSearchByCompanyIdAndArrayCriteria( $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 = [ 'pay_period_id', 'first_name', 'last_name', 'date_stamp', 'time_stamp', 'type_id', 'status_id' ]; if ( $order == null ) { $order = [ 'b.pay_period_id' => 'asc', 'b.user_id' => 'asc', 'a.time_stamp' => 'asc', 'a.punch_control_id' => 'asc', 'a.status_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['pay_period_ids'] ) ) { $filter_data['pay_period_id'] = $filter_data['pay_period_ids']; } if ( isset( $filter_data['exclude_user_ids'] ) ) { $filter_data['exclude_id'] = $filter_data['exclude_user_ids']; } if ( isset( $filter_data['user_id'] ) ) { $filter_data['id'] = $filter_data['user_id']; } 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['user_status_ids'] ) ) { $filter_data['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['branch_ids'] ) ) { $filter_data['default_branch_id'] = $filter_data['branch_ids']; } if ( isset( $filter_data['department_ids'] ) ) { $filter_data['default_department_id'] = $filter_data['department_ids']; } if ( isset( $filter_data['punch_branch_ids'] ) ) { $filter_data['punch_branch_id'] = $filter_data['punch_branch_ids']; } if ( isset( $filter_data['punch_department_ids'] ) ) { $filter_data['punch_department_id'] = $filter_data['punch_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(); $pcf = new PunchControlFactory(); $uwf = new UserWageFactory(); $sf = new StationFactory(); if ( getTTProductEdition() >= TT_PRODUCT_CORPORATE ) { $jf = new JobFactory(); $jif = new JobItemFactory(); } $ph = [ 'company_id' => TTUUID::castUUID( $company_id ), ]; $query = ' select a.id as punch_id, a.punch_control_id as punch_control_id, a.type_id as type_id, a.status_id as status_id, a.time_stamp as time_stamp, a.actual_time_stamp as actual_time_stamp, b.branch_id as branch_id, b.department_id as department_id, b.job_id as job_id, b.job_item_id as job_item_id, b.quantity as quantity, b.bad_quantity as bad_quantity, b.total_time as total_time, b.actual_total_time as actual_total_time, b.custom_field as custom_field, b.note as note, b.user_id as user_id, b.date_stamp as date_stamp, b.pay_period_id as pay_period_id, e.type_id as station_type_id, e.station_id as station_station_id, e.source as station_source, e.description as station_description, z.id as user_wage_id, z.effective_date as user_wage_effective_date '; if ( getTTProductEdition() >= TT_PRODUCT_CORPORATE ) { $query .= ', x.name as job_name, x.description as job_description, x.status_id as job_status_id, x.manual_id as job_manual_id, x.branch_id as job_branch_id, x.department_id as job_department_id, x.group_id as job_group_id'; } $query .= ' from ' . $this->getTable() . ' as a LEFT JOIN ' . $pcf->getTable() . ' as b ON a.punch_control_id = b.id LEFT JOIN ' . $uf->getTable() . ' as d ON b.user_id = d.id LEFT JOIN ' . $sf->getTable() . ' as e ON a.station_id = e.id LEFT JOIN ' . $uwf->getTable() . ' as z ON z.id = (select z.id from ' . $uwf->getTable() . ' as z where z.user_id = b.user_id and z.effective_date <= b.date_stamp and z.wage_group_id = \'' . TTUUID::getZeroID() . '\' and z.deleted = 0 order by z.effective_date desc LiMiT 1) '; if ( getTTProductEdition() >= TT_PRODUCT_CORPORATE ) { $query .= ' LEFT JOIN ' . $jf->getTable() . ' as x ON b.job_id = x.id'; $query .= ' LEFT JOIN ' . $jif->getTable() . ' as y ON b.job_item_id = y.id'; } $query .= ' WHERE d.company_id = ?'; if ( isset( $filter_data['permission_children_ids'] ) && isset( $filter_data['permission_children_ids'][0] ) && !in_array( TTUUID::getNotExistID(), (array)$filter_data['permission_children_ids'] ) ) { $query .= ' AND d.id in (' . $this->getListSQL( $filter_data['permission_children_ids'], $ph ) . ') '; } if ( isset( $filter_data['id'] ) && isset( $filter_data['id'][0] ) && !in_array( TTUUID::getNotExistID(), (array)$filter_data['id'] ) ) { $query .= ' AND d.id in (' . $this->getListSQL( $filter_data['id'], $ph ) . ') '; } if ( isset( $filter_data['exclude_id'] ) && isset( $filter_data['exclude_id'][0] ) && !in_array( TTUUID::getNotExistID(), (array)$filter_data['exclude_id'] ) ) { $query .= ' AND d.id not in (' . $this->getListSQL( $filter_data['exclude_id'], $ph ) . ') '; } if ( isset( $filter_data['status_id'] ) && isset( $filter_data['status_id'][0] ) && !in_array( -1, (array)$filter_data['status_id'] ) ) { $query .= ' AND d.status_id in (' . $this->getListSQL( $filter_data['status_id'], $ph ) . ') '; } if ( isset( $filter_data['group_id'] ) && isset( $filter_data['group_id'][0] ) && !in_array( TTUUID::getNotExistID(), (array)$filter_data['group_id'] ) ) { if ( isset( $filter_data['include_subgroups'] ) && (bool)$filter_data['include_subgroups'] == true ) { $uglf = new UserGroupListFactory(); $filter_data['group_id'] = $uglf->getByCompanyIdAndGroupIdAndSubGroupsArray( $company_id, $filter_data['group_id'], true ); } $query .= ' AND d.group_id in (' . $this->getListSQL( $filter_data['group_id'], $ph ) . ') '; } if ( isset( $filter_data['default_branch_id'] ) && isset( $filter_data['default_branch_id'][0] ) && !in_array( TTUUID::getNotExistID(), (array)$filter_data['default_branch_id'] ) ) { $query .= ' AND d.default_branch_id in (' . $this->getListSQL( $filter_data['default_branch_id'], $ph ) . ') '; } if ( isset( $filter_data['default_department_id'] ) && isset( $filter_data['default_department_id'][0] ) && !in_array( TTUUID::getNotExistID(), (array)$filter_data['default_department_id'] ) ) { $query .= ' AND d.default_department_id in (' . $this->getListSQL( $filter_data['default_department_id'], $ph ) . ') '; } if ( isset( $filter_data['title_id'] ) && isset( $filter_data['title_id'][0] ) && !in_array( TTUUID::getNotExistID(), (array)$filter_data['title_id'] ) ) { $query .= ' AND d.title_id in (' . $this->getListSQL( $filter_data['title_id'], $ph ) . ') '; } if ( isset( $filter_data['punch_branch_id'] ) && isset( $filter_data['punch_branch_id'][0] ) && !in_array( TTUUID::getNotExistID(), (array)$filter_data['punch_branch_id'] ) ) { $query .= ' AND b.branch_id in (' . $this->getListSQL( $filter_data['punch_branch_id'], $ph ) . ') '; } if ( isset( $filter_data['punch_department_id'] ) && isset( $filter_data['punch_department_id'][0] ) && !in_array( TTUUID::getNotExistID(), (array)$filter_data['punch_department_id'] ) ) { $query .= ' AND b.department_id in (' . $this->getListSQL( $filter_data['punch_department_id'], $ph ) . ') '; } if ( isset( $filter_data['punch_status_id'] ) && isset( $filter_data['punch_status_id'][0] ) && !in_array( -1, (array)$filter_data['punch_status_id'] ) ) { $query .= ' AND a.status_id in (' . $this->getListSQL( $filter_data['punch_status_id'], $ph ) . ') '; } if ( isset( $filter_data['punch_type_id'] ) && isset( $filter_data['punch_type_id'][0] ) && !in_array( -1, (array)$filter_data['punch_type_id'] ) ) { $query .= ' AND a.type_id in (' . $this->getListSQL( $filter_data['punch_type_id'], $ph ) . ') '; } if ( isset( $filter_data['pay_period_id'] ) && isset( $filter_data['pay_period_id'][0] ) && !in_array( TTUUID::getNotExistID(), (array)$filter_data['pay_period_id'] ) ) { $query .= ' AND b.pay_period_id in (' . $this->getListSQL( $filter_data['pay_period_id'], $ph ) . ') '; } //Use the job_id in the punch_control table so we can filter by '0' or No Job if ( isset( $filter_data['include_job_id'] ) && isset( $filter_data['include_job_id'][0] ) && !in_array( TTUUID::getNotExistID(), (array)$filter_data['include_job_id'] ) ) { $query .= ' AND b.job_id in (' . $this->getListSQL( $filter_data['include_job_id'], $ph ) . ') '; } if ( isset( $filter_data['exclude_job_id'] ) && isset( $filter_data['exclude_job_id'][0] ) && !in_array( TTUUID::getNotExistID(), (array)$filter_data['exclude_job_id'] ) ) { $query .= ' AND b.job_id not in (' . $this->getListSQL( $filter_data['exclude_job_id'], $ph ) . ') '; } if ( isset( $filter_data['job_group_id'] ) && isset( $filter_data['job_group_id'][0] ) && !in_array( TTUUID::getNotExistID(), (array)$filter_data['job_group_id'] ) ) { if ( isset( $filter_data['include_job_subgroups'] ) && (bool)$filter_data['include_job_subgroups'] == true ) { $uglf = new UserGroupListFactory(); $filter_data['job_group_id'] = $uglf->getByCompanyIdAndGroupIdAndjob_subgroupsArray( $company_id, $filter_data['job_group_id'], true ); } $query .= ' AND x.group_id in (' . $this->getListSQL( $filter_data['job_group_id'], $ph ) . ') '; } if ( isset( $filter_data['job_item_id'] ) && isset( $filter_data['job_item_id'][0] ) && !in_array( TTUUID::getNotExistID(), (array)$filter_data['job_item_id'] ) ) { $query .= ' AND b.job_item_id in (' . $this->getListSQL( $filter_data['job_item_id'], $ph ) . ') '; } 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'] ) ); $query .= ' AND b.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'] ) ); $query .= ' AND b.date_stamp <= ?'; } $query .= ' AND (a.deleted = 0 AND b.deleted = 0 AND d.deleted = 0) '; $query .= $this->getWhereSQL( $where ); $query .= $this->getSortSQL( $order, $strict, $additional_order_fields ); //Debug::Query( $query, $ph, __FILE__, __LINE__, __METHOD__, 10); $this->rs = $this->ExecuteSQL( $query, $ph, $limit, $page ); 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 $this */ function getPunchSummaryReportByCompanyIdAndArrayCriteria( $company_id, $filter_data, $limit = null, $page = null, $where = null, $order = null ) { //$order = array( 'b.pay_period_id' => 'asc', 'b.user_id' => 'asc' ); //$order = array( 'b.pay_period_id' => 'asc', 'uf.last_name' => 'asc', 'b.date_stamp' => 'asc' ); /* if ( $order == NULL ) { $order = array( 'b.pay_period_id' => 'asc', 'b.user_id' => 'asc' ); $strict = FALSE; } else { $strict = TRUE; } */ if ( $order == null ) { $order = []; $strict = false; } else { $strict = true; } if ( isset( $filter_data['punch_branch_ids'] ) ) { $filter_data['punch_branch_id'] = $filter_data['punch_branch_ids']; } if ( isset( $filter_data['punch_department_ids'] ) ) { $filter_data['punch_department_id'] = $filter_data['punch_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']; } //Debug::Arr($filter_data, 'Filter Data:', __FILE__, __LINE__, __METHOD__, 10); $uf = new UserFactory(); $bf = new BranchFactory(); $df = new DepartmentFactory(); $ugf = new UserGroupFactory(); $ppf_b = new PayPeriodFactory(); $uwf = new UserWageFactory(); $pcf = new PunchControlFactory(); $sf = new StationFactory(); if ( getTTProductEdition() >= TT_PRODUCT_CORPORATE ) { $jf = new JobFactory(); $jgf = new JobGroupFactory(); $jif = new JobItemFactory(); $jigf = new JobItemGroupFactory(); } $ph = [ 'company_id' => TTUUID::castUUID( $company_id ), ]; //Make it so employees with 0 hours still show up!! Very important! //Order dock hours first, so it can be deducted from regular time. $query = ' select a.id as punch_id, a.punch_control_id as punch_control_id, a.type_id as type_id, a.status_id as status_id, a.time_stamp as punch_time_stamp, a.actual_time_stamp as punch_actual_time_stamp, a.has_image as punch_has_image, a.created_date as punch_created_date, uf_b.first_name as punch_created_by_first_name, uf_b.middle_name as punch_created_by_middle_name, uf_b.last_name as punch_created_by_last_name, a.updated_date as punch_updated_date, uf_c.first_name as punch_updated_by_first_name, uf_c.middle_name as punch_updated_by_middle_name, uf_c.last_name as punch_updated_by_last_name, pcf.branch_id as branch_id, pcf.department_id as department_id, pcf.job_id as job_id, pcf.job_item_id as job_item_id, pcf.quantity as quantity, pcf.bad_quantity as bad_quantity, a.longitude as longitude, a.latitude as latitude, a.position_accuracy as position_accuracy, pcf.total_time as total_time, pcf.actual_total_time as actual_total_time, pcf.custom_field as punch_control_custom_field, pcf.note as note, pcf.user_id as user_id, pcf.date_stamp as date_stamp, pcf.pay_period_id as pay_period_id, ppf.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, CASE WHEN pcf.user_id != a.created_by OR a.created_by != a.updated_by OR ( a.created_by is NULL AND a.updated_by is NOT NULL ) THEN 1 ELSE 0 END as tainted, bf.name as branch, df.name as department, ugf.name as group, a.status_id as status_id, a.type_id as type_id, z.id as user_wage_id, z.effective_date as user_wage_effective_date, z.hourly_rate as hourly_rate, z.labor_burden_percent as labor_burden_percent, sf.type_id as station_type_id, sf.station_id as station_station_id, sf.source as station_source, sf.description as station_description'; if ( getTTProductEdition() >= TT_PRODUCT_CORPORATE ) { $query .= ', 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, 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 ' . $this->getTable() . ' as a LEFT JOIN ' . $pcf->getTable() . ' as pcf ON a.punch_control_id = pcf.id LEFT JOIN ' . $ppf_b->getTable() . ' as ppf ON pcf.pay_period_id = ppf.id LEFT JOIN ' . $uf->getTable() . ' as uf ON pcf.user_id = uf.id LEFT JOIN ' . $uf->getTable() . ' as uf_b ON a.created_by = uf_b.id LEFT JOIN ' . $uf->getTable() . ' as uf_c ON a.updated_by = uf_c.id LEFT JOIN ' . $bf->getTable() . ' as bf ON pcf.branch_id = bf.id LEFT JOIN ' . $df->getTable() . ' as df ON pcf.department_id = df.id LEFT JOIN ' . $ugf->getTable() . ' as ugf ON ( uf.company_id = ugf.company_id AND uf.group_id = ugf.id AND ugf.deleted = 0 ) LEFT JOIN ' . $sf->getTable() . ' as sf ON a.station_id = sf.id LEFT JOIN ' . $uwf->getTable() . ' as z ON z.id = (select z.id from ' . $uwf->getTable() . ' as z where z.user_id = pcf.user_id and z.effective_date <= pcf.date_stamp and z.wage_group_id = \'' . TTUUID::getZeroID() . '\' and z.deleted = 0 order by z.effective_date desc limit 1) '; if ( getTTProductEdition() >= TT_PRODUCT_CORPORATE ) { $query .= ' LEFT JOIN ' . $jf->getTable() . ' as jf ON pcf.job_id = jf.id LEFT JOIN ' . $jif->getTable() . ' as jif ON pcf.job_item_id = jif.id LEFT JOIN ' . $bf->getTable() . ' as jbf ON jf.branch_id = jbf.id LEFT JOIN ' . $df->getTable() . ' as jdf ON jf.department_id = jdf.id LEFT JOIN ' . $jgf->getTable() . ' as jgf ON jf.group_id = jgf.id LEFT JOIN ' . $jigf->getTable() . ' as jigf ON jif.group_id = jigf.id '; } $query .= ' where uf.company_id = ? '; $query .= ( isset( $filter_data['permission_children_ids'] ) ) ? $this->getWhereClauseSQL( 'uf.id', $filter_data['permission_children_ids'], 'uuid_list', $ph ) : null; $query .= ( isset( $filter_data['include_user_id'] ) ) ? $this->getWhereClauseSQL( 'uf.id', $filter_data['include_user_id'], 'uuid_list', $ph ) : null; $query .= ( isset( $filter_data['exclude_user_id'] ) ) ? $this->getWhereClauseSQL( 'uf.id', $filter_data['exclude_user_id'], 'not_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; if ( isset( $filter_data['include_user_subgroups'] ) && (bool)$filter_data['include_user_subgroups'] == true ) { $uglf = new UserGroupListFactory(); $filter_data['user_group_id'] = $uglf->getByCompanyIdAndGroupIdAndSubGroupsArray( $company_id, $filter_data['user_group_id'], true ); } $query .= ( isset( $filter_data['user_group_id'] ) ) ? $this->getWhereClauseSQL( 'uf.group_id', $filter_data['user_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['user_title_id'] ) ) ? $this->getWhereClauseSQL( 'uf.title_id', $filter_data['user_title_id'], 'uuid_list', $ph ) : null; $query .= ( isset( $filter_data['punch_branch_id'] ) ) ? $this->getWhereClauseSQL( 'pcf.branch_id', $filter_data['punch_branch_id'], 'uuid_list', $ph ) : null; $query .= ( isset( $filter_data['punch_department_id'] ) ) ? $this->getWhereClauseSQL( 'pcf.department_id', $filter_data['punch_department_id'], 'uuid_list', $ph ) : null; $query .= ( isset( $filter_data['pay_period_id'] ) ) ? $this->getWhereClauseSQL( 'pcf.pay_period_id', $filter_data['pay_period_id'], 'uuid_list', $ph ) : null; if ( isset( $filter_data['job_status'] ) && !is_array( $filter_data['job_status'] ) && trim( $filter_data['job_status'] ) != '' && !isset( $filter_data['job_status_id'] ) ) { $filter_data['job_status_id'] = Option::getByFuzzyValue( $filter_data['job_status'], $jf->getOptions( 'status' ) ); } $query .= ( isset( $filter_data['job_status_id'] ) ) ? $this->getWhereClauseSQL( 'jf.status_id', $filter_data['job_status_id'], 'numeric_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['include_job_id'] ) ) ? $this->getWhereClauseSQL( 'pcf.job_id', $filter_data['include_job_id'], 'uuid_list', $ph ) : null; $query .= ( isset( $filter_data['exclude_job_id'] ) ) ? $this->getWhereClauseSQL( 'pcf.job_id', $filter_data['exclude_job_id'], 'not_uuid_list', $ph ) : null; $query .= ( isset( $filter_data['job_item_group_id'] ) ) ? $this->getWhereClauseSQL( 'jif.group_id', $filter_data['job_item_group_id'], 'uuid_list', $ph ) : null; $query .= ( isset( $filter_data['include_job_item_id'] ) ) ? $this->getWhereClauseSQL( 'pcf.job_item_id', $filter_data['include_job_item_id'], 'uuid_list', $ph ) : null; $query .= ( isset( $filter_data['exclude_job_item_id'] ) ) ? $this->getWhereClauseSQL( 'pcf.job_item_id', $filter_data['exclude_job_item_id'], 'not_uuid_list', $ph ) : null; if ( getTTProductEdition() >= TT_PRODUCT_CORPORATE ) { $query .= ( isset( $filter_data['punch_tag_id'] ) ) ? $this->getWhereClauseSQL( 'pcf.punch_tag_id', $filter_data['punch_tag_id'], 'jsonb_uuid_array', $ph ) : null; } $query .= ( isset( $filter_data['tag'] ) ) ? $this->getWhereClauseSQL( 'uf.id', [ 'company_id' => TTUUID::castUUID( $company_id ), 'object_type_id' => 200, 'tag' => $filter_data['tag'] ], 'tag', $ph ) : null; 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'] ) ); $query .= ' AND pcf.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'] ) ); $query .= ' AND pcf.date_stamp <= ?'; } $query .= ( isset( $filter_data['date_stamp'] ) ) ? $this->getWhereClauseSQL( 'pcf.date_stamp', $filter_data['date_stamp'], 'date_range_datestamp', $ph ) : null; $query .= ( isset( $filter_data['time_stamp'] ) ) ? $this->getWhereClauseSQL( 'a.time_stamp', $filter_data['time_stamp'], 'date_range_timestamp', $ph ) : null; $query .= ( isset( $filter_data['created_date'] ) ) ? $this->getWhereClauseSQL( 'a.created_date', $filter_data['created_date'], 'date_range', $ph ) : null; $query .= ( isset( $filter_data['updated_date'] ) ) ? $this->getWhereClauseSQL( 'a.updated_date', $filter_data['updated_date'], 'date_range', $ph ) : null; $query .= ' AND ( a.deleted = 0 AND pcf.deleted = 0 ) '; $query .= $this->getSortSQL( $order, $strict ); $this->rs = $this->ExecuteSQL( $query, $ph, $limit, $page ); 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|PunchListFactory */ function getAPIActiveShiftReportByCompanyIdAndArrayCriteria( $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 = [ 'first_name', 'last_name', 'date_stamp', 'time_stamp', 'type_id', 'status_id', 'branch', 'department', 'default_branch', 'default_department', 'group', 'title' ]; $sort_column_aliases = [ 'status' => 'a.status_id', 'type' => 'a.type_id', 'group' => 'd.group_id', 'first_name' => 'd.first_name', 'last_name' => 'd.last_name', 'date_stamp' => 'b.date_stamp', 'station_station_id' => 'l.station_id', 'station_type' => 'l.type_id', 'station_source' => 'l.source', 'station_description' => 'l.description', ]; $order = $this->getColumnsFromAliases( $order, $sort_column_aliases ); if ( $order == null ) { $order = [ 'a.status_id' => 'asc', 'a.time_stamp' => 'asc', 'd.last_name' => 'asc', 'd.first_name' => '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['include_user_id'] ) ) { $filter_data['user_id'] = $filter_data['include_user_id']; } if ( isset( $filter_data['exclude_user_id'] ) ) { $filter_data['exclude_id'] = $filter_data['exclude_user_id']; } if ( isset( $filter_data['user_status_ids'] ) ) { $filter_data['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['branch_ids'] ) ) { $filter_data['default_branch_id'] = $filter_data['branch_ids']; } if ( isset( $filter_data['department_ids'] ) ) { $filter_data['default_department_id'] = $filter_data['department_ids']; } if ( isset( $filter_data['punch_branch_ids'] ) ) { $filter_data['punch_branch_id'] = $filter_data['punch_branch_ids']; } if ( isset( $filter_data['punch_department_ids'] ) ) { $filter_data['punch_department_id'] = $filter_data['punch_department_ids']; } $uf = new UserFactory(); $pcf = new PunchControlFactory(); $uwf = new UserWageFactory(); $sf = new StationFactory(); $bf = new BranchFactory(); $df = new DepartmentFactory(); $ugf = new UserGroupFactory(); $utf = new UserTitleFactory(); if ( getTTProductEdition() >= TT_PRODUCT_CORPORATE ) { $jf = new JobFactory(); $jif = new JobItemFactory(); } $ph = []; $query = ' select a.id as id, a.punch_control_id as punch_control_id, a.type_id as type_id, a.status_id as status_id, a.time_stamp as time_stamp, a.actual_time_stamp as actual_time_stamp, a.original_time_stamp as original_time_stamp, a.created_by as created_by, a.created_date as created_date, a.updated_by as updated_by, a.updated_date as updated_date, b.branch_id as branch_id, j.name as branch, b.department_id as department_id, k.name as department, b.job_id as job_id, b.job_item_id as job_item_id, b.quantity as quantity, b.bad_quantity as bad_quantity, b.total_time as total_time, b.actual_total_time as actual_total_time, b.custom_field as custom_field, b.note as note, b.user_id as user_id, b.date_stamp as date_stamp, b.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, l.type_id as station_type_id, l.station_id as station_station_id, l.source as station_source, l.description as station_description, w.id as user_wage_id, w.effective_date as user_wage_effective_date, 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 .= ', r.name as job, r.name as job_name, r.status_id as job_status_id, r.manual_id as job_manual_id, r.branch_id as job_branch_id, r.department_id as job_department_id, r.group_id as job_group_id, s.name as job_item'; } //There was a bug here where if an employee punched out at 5:00PM, then an Admin entered a 8:00AM IN punch manually, it return the 8AM punch because it has the higher punch_id, rather than grouping on the timestamp directly. $query .= ' FROM ' . $uf->getTable() . ' as d LEFT JOIN ' . $this->getTable() . ' as a ON ( a.id = ( SELECT tmp2_a.id as punch_id FROM ' . $this->getTable() . ' as tmp2_a LEFT JOIN ' . $pcf->getTable() . ' as tmp2_b ON ( tmp2_a.punch_control_id = tmp2_b.id ) WHERE tmp2_b.user_id = d.id AND tmp2_a.time_stamp IS NOT NULL '; 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'] ) ); $query .= ' AND tmp2_b.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'] ) ); $query .= ' AND tmp2_b.date_stamp <= ?'; } if ( isset( $filter_data['punch_end_date'] ) && !is_array( $filter_data['punch_end_date'] ) && trim( $filter_data['punch_end_date'] ) != '' ) { $ph[] = $ph[] = $this->db->BindTimeStamp( TTDate::parseDateTime( $filter_data['punch_end_date'] ) ); $query .= ' AND ( tmp2_a.time_stamp <= ? OR tmp2_a.actual_time_stamp <= ? ) '; //Check actual time as well so rounded punches past wall-clock time don't cause confusion. This is also checked around line: 2238 } $query .= ' AND ( tmp2_a.deleted = 0 AND tmp2_b.deleted = 0 ) ORDER BY tmp2_a.time_stamp desc, tmp2_a.status_id asc LIMIT 1 ) ) LEFT JOIN ' . $pcf->getTable() . ' as b ON ( a.punch_control_id = b.id ) 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 ( b.branch_id = j.id AND j.deleted = 0) LEFT JOIN ' . $df->getTable() . ' as k ON ( b.department_id = k.id AND k.deleted = 0) LEFT JOIN ' . $sf->getTable() . ' as l ON a.station_id = l.id LEFT JOIN ' . $uwf->getTable() . ' as w ON w.id = (select w.id from ' . $uwf->getTable() . ' as w where w.user_id = b.user_id and w.effective_date <= b.date_stamp and w.wage_group_id = \'' . TTUUID::getZeroID() . '\' and w.deleted = 0 order by w.effective_date desc LiMiT 1) 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 ) '; if ( getTTProductEdition() >= TT_PRODUCT_CORPORATE ) { $query .= ' LEFT JOIN ' . $jf->getTable() . ' as r ON b.job_id = r.id'; $query .= ' LEFT JOIN ' . $jif->getTable() . ' as s ON b.job_item_id = s.id'; } $ph[] = TTUUID::castUUID( $company_id ); $query .= ' WHERE d.company_id = ?'; if ( isset( $filter_data['permission_children_ids'] ) && isset( $filter_data['permission_children_ids'][0] ) && !in_array( TTUUID::getNotExistID(), (array)$filter_data['permission_children_ids'] ) ) { $query .= ' AND d.id in (' . $this->getListSQL( $filter_data['permission_children_ids'], $ph, 'uuid' ) . ') '; } if ( isset( $filter_data['id'] ) && isset( $filter_data['id'][0] ) && !in_array( TTUUID::getNotExistID(), (array)$filter_data['id'] ) ) { $query .= ' AND a.id in (' . $this->getListSQL( $filter_data['id'], $ph, 'uuid' ) . ') '; } if ( isset( $filter_data['exclude_id'] ) && isset( $filter_data['exclude_id'][0] ) && !in_array( TTUUID::getNotExistID(), (array)$filter_data['exclude_id'] ) ) { $query .= ' AND d.id not in (' . $this->getListSQL( $filter_data['exclude_id'], $ph, 'uuid' ) . ') '; } if ( isset( $filter_data['user_id'] ) && isset( $filter_data['user_id'][0] ) && !in_array( TTUUID::getNotExistID(), (array)$filter_data['user_id'] ) ) { $query .= ' AND b.user_id in (' . $this->getListSQL( $filter_data['user_id'], $ph, 'uuid' ) . ') '; } if ( isset( $filter_data['user_status_id'] ) && isset( $filter_data['user_status_id'][0] ) && !in_array( -1, (array)$filter_data['user_status_id'] ) ) { $query .= ' AND d.status_id in (' . $this->getListSQL( $filter_data['user_status_id'], $ph, 'int' ) . ') '; } if ( isset( $filter_data['group_id'] ) && isset( $filter_data['group_id'][0] ) && !in_array( TTUUID::getNotExistID(), (array)$filter_data['group_id'] ) ) { if ( isset( $filter_data['include_subgroups'] ) && (bool)$filter_data['include_subgroups'] == true ) { $uglf = new UserGroupListFactory(); $filter_data['group_id'] = $uglf->getByCompanyIdAndGroupIdAndSubGroupsArray( $company_id, $filter_data['group_id'], true ); } $query .= ' AND d.group_id in (' . $this->getListSQL( $filter_data['group_id'], $ph, 'uuid' ) . ') '; } if ( isset( $filter_data['default_branch_id'] ) && isset( $filter_data['default_branch_id'][0] ) && !in_array( TTUUID::getNotExistID(), (array)$filter_data['default_branch_id'] ) ) { $query .= ' AND d.default_branch_id in (' . $this->getListSQL( $filter_data['default_branch_id'], $ph, 'uuid' ) . ') '; } if ( isset( $filter_data['default_department_id'] ) && isset( $filter_data['default_department_id'][0] ) && !in_array( TTUUID::getNotExistID(), (array)$filter_data['default_department_id'] ) ) { $query .= ' AND d.default_department_id in (' . $this->getListSQL( $filter_data['default_department_id'], $ph, 'uuid' ) . ') '; } if ( isset( $filter_data['title_id'] ) && isset( $filter_data['title_id'][0] ) && !in_array( TTUUID::getNotExistID(), (array)$filter_data['title_id'] ) ) { $query .= ' AND d.title_id in (' . $this->getListSQL( $filter_data['title_id'], $ph, 'uuid' ) . ') '; } if ( isset( $filter_data['branch_id'] ) && isset( $filter_data['branch_id'][0] ) && !in_array( TTUUID::getNotExistID(), (array)$filter_data['branch_id'] ) ) { $query .= ' AND b.branch_id in (' . $this->getListSQL( $filter_data['branch_id'], $ph, 'uuid' ) . ') '; } if ( isset( $filter_data['department_id'] ) && isset( $filter_data['department_id'][0] ) && !in_array( TTUUID::getNotExistID(), (array)$filter_data['department_id'] ) ) { $query .= ' AND b.department_id in (' . $this->getListSQL( $filter_data['department_id'], $ph, 'uuid' ) . ') '; } if ( isset( $filter_data['status_id'] ) && isset( $filter_data['status_id'][0] ) && !in_array( -1, (array)$filter_data['status_id'] ) ) { $query .= ' AND a.status_id in (' . $this->getListSQL( $filter_data['status_id'], $ph, 'int' ) . ') '; } if ( isset( $filter_data['type_id'] ) && isset( $filter_data['type_id'][0] ) && !in_array( -1, (array)$filter_data['type_id'] ) ) { $query .= ' AND a.type_id in (' . $this->getListSQL( $filter_data['type_id'], $ph, 'int' ) . ') '; } if ( isset( $filter_data['pay_period_ids'] ) && isset( $filter_data['pay_period_ids'][0] ) && !in_array( TTUUID::getNotExistID(), (array)$filter_data['pay_period_ids'] ) ) { $query .= ' AND b.pay_period_id in (' . $this->getListSQL( $filter_data['pay_period_ids'], $ph, 'int' ) . ') '; } //Use the job_id in the punch_control table so we can filter by '0' or No Job if ( isset( $filter_data['include_job_id'] ) && isset( $filter_data['include_job_id'][0] ) && !in_array( TTUUID::getNotExistID(), (array)$filter_data['include_job_id'] ) ) { $query .= ' AND b.job_id in (' . $this->getListSQL( $filter_data['include_job_id'], $ph, 'uuid' ) . ') '; } if ( isset( $filter_data['exclude_job_id'] ) && isset( $filter_data['exclude_job_id'][0] ) && !in_array( TTUUID::getNotExistID(), (array)$filter_data['exclude_job_id'] ) ) { $query .= ' AND b.job_id not in (' . $this->getListSQL( $filter_data['exclude_job_id'], $ph, 'uuid' ) . ') '; } if ( isset( $filter_data['job_group_id'] ) && isset( $filter_data['job_group_id'][0] ) && !in_array( TTUUID::getNotExistID(), (array)$filter_data['job_group_id'] ) ) { if ( isset( $filter_data['include_job_subgroups'] ) && (bool)$filter_data['include_job_subgroups'] == true ) { $uglf = new UserGroupListFactory(); $filter_data['job_group_id'] = $uglf->getByCompanyIdAndGroupIdAndjob_subgroupsArray( $company_id, $filter_data['job_group_id'], true ); } $query .= ' AND r.group_id in (' . $this->getListSQL( $filter_data['job_group_id'], $ph, 'uuid' ) . ') '; } if ( isset( $filter_data['job_item_id'] ) && isset( $filter_data['job_item_id'][0] ) && !in_array( TTUUID::getNotExistID(), (array)$filter_data['job_item_id'] ) ) { $query .= ' AND b.job_item_id in (' . $this->getListSQL( $filter_data['job_item_id'], $ph, 'uuid' ) . ') '; } 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'] ) ); $query .= ' AND b.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'] ) ); $query .= ' AND b.date_stamp <= ?'; } if ( isset( $filter_data['punch_end_date'] ) && !is_array( $filter_data['punch_end_date'] ) && trim( $filter_data['punch_end_date'] ) != '' ) { $ph[] = $ph[] = $this->db->BindTimeStamp( (int)TTDate::parseDateTime( $filter_data['punch_end_date'] ) ); $query .= ' AND ( a.time_stamp <= ? OR a.actual_time_stamp <= ? )'; //Check actual time as well so rounded punches past wall-clock time don't cause confusion. This is also checked around line: 2120 } $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 AND b.deleted = 0 AND d.deleted = 0) '; $query .= $this->getWhereSQL( $where ); $query .= $this->getSortSQL( $order, $strict, $additional_order_fields ); Debug::Query( $query, $ph, __FILE__, __LINE__, __METHOD__, 10); $this->rs = $this->ExecuteSQL( $query, $ph, $limit, $page ); 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|PunchListFactory */ 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 = [ 'first_name', 'last_name', 'date_stamp', 'time_stamp', 'type_id', 'status_id', 'branch', 'department', 'default_branch', 'default_department', 'default_job', 'default_job_item', 'group', 'title', 'actual_time_diff', 'tainted', 'l.source', 'l.description', 'b.pay_period_id', 'b.user_id', 'b.punch_tag_id' ]; $sort_column_aliases = [ 'status' => 'a.status_id', 'type' => 'a.type_id', 'first_name' => 'd.first_name', 'last_name' => 'd.last_name', 'date_stamp' => 'b.date_stamp', 'station_station_id' => 'l.station_id', 'station_type' => 'l.type_id', 'station_source' => 'l.source', 'station_description' => 'l.description', 'punch_tag' => 'b.punch_tag_id', ]; if ( getTTProductEdition() >= TT_PRODUCT_CORPORATE ) { //Needed for unit tests to pass when doing pure edition tests. $additional_order_fields = array_merge( [ 'r.name', 's.name' ], $additional_order_fields ); $sort_column_aliases = array_merge( [ 'job' => 'r.name', 'job_item' => 's.name', ], $sort_column_aliases ); } $order = $this->getColumnsFromAliases( $order, $sort_column_aliases ); if ( $order == null ) { $order = [ 'a.time_stamp' => 'desc', 'd.last_name' => 'asc', 'd.first_name' => 'asc', 'b.user_id' => 'asc', 'a.status_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['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['branch_ids'] ) ) { $filter_data['default_branch_id'] = $filter_data['branch_ids']; } if ( isset( $filter_data['department_ids'] ) ) { $filter_data['default_department_id'] = $filter_data['department_ids']; } if ( isset( $filter_data['punch_branch_ids'] ) ) { $filter_data['branch_id'] = $filter_data['punch_branch_ids']; } if ( isset( $filter_data['punch_department_ids'] ) ) { $filter_data['department_id'] = $filter_data['punch_department_ids']; } if ( isset( $filter_data['pay_period_ids'] ) ) { $filter_data['pay_period_id'] = $filter_data['pay_period_ids']; } $uf = new UserFactory(); $pcf = new PunchControlFactory(); $uwf = new UserWageFactory(); $sf = new StationFactory(); $bf = new BranchFactory(); $df = new DepartmentFactory(); $ugf = new UserGroupFactory(); $utf = new UserTitleFactory(); if ( getTTProductEdition() >= TT_PRODUCT_CORPORATE ) { $jf = new JobFactory(); $jif = new JobItemFactory(); } $ph = [ 'company_id' => TTUUID::castUUID( $company_id ), ]; //Tainted: Determine if the punch was manually created (without punching in/out) or modified by someone other than the person who punched in/out. $query = ' select a.id as id, a.punch_control_id as punch_control_id, a.type_id as type_id, a.status_id as status_id, a.time_stamp as time_stamp, a.actual_time_stamp as actual_time_stamp, EXTRACT(EPOCH FROM ( a.time_stamp - a.actual_time_stamp ) ) as actual_time_diff, a.original_time_stamp as original_time_stamp, a.longitude, a.latitude, a.position_accuracy, a.transfer, a.has_image, a.created_by as created_by, a.created_date as created_date, a.updated_by as updated_by, a.updated_date as updated_date, b.branch_id as branch_id, j.name as branch, b.department_id as department_id, k.name as department, b.job_id as job_id, b.job_item_id as job_item_id, b.punch_tag_id as punch_tag_id, b.quantity as quantity, b.bad_quantity as bad_quantity, b.total_time as total_time, b.actual_total_time as actual_total_time, b.custom_field as custom_field, b.note as note, b.user_id as user_id, b.date_stamp as date_stamp, b.pay_period_id as pay_period_id, CASE WHEN b.user_id != a.created_by OR a.created_by != a.updated_by OR ( a.created_by is NULL AND a.updated_by is NOT NULL ) THEN 1 ELSE 0 END as tainted, 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, l.id as station_id, l.type_id as station_type_id, l.station_id as station_station_id, l.source as station_source, l.description as station_description, w.id as user_wage_id, w.effective_date as user_wage_effective_date, 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 .= ', r.name as job, r.name as job_name, d.default_job_id as default_job_id, r2.name as default_job, r.status_id as job_status_id, r.manual_id as job_manual_id, r.branch_id as job_branch_id, r.department_id as job_department_id, r.group_id as job_group_id, s.name as job_item, d.default_job_item_id as default_job_item_id, s2.name as default_job_item, s.manual_id as job_item_manual_id'; } $query .= ' from ' . $this->getTable() . ' as a LEFT JOIN ' . $pcf->getTable() . ' as b ON a.punch_control_id = b.id LEFT JOIN ' . $uf->getTable() . ' as d ON b.user_id = d.id 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 ( b.branch_id = j.id AND j.deleted = 0) LEFT JOIN ' . $df->getTable() . ' as k ON ( b.department_id = k.id AND k.deleted = 0) LEFT JOIN ' . $sf->getTable() . ' as l ON ( a.station_id = l.id AND l.deleted = 0 ) LEFT JOIN ' . $uwf->getTable() . ' as w ON w.id = (select w.id from ' . $uwf->getTable() . ' as w where w.user_id = b.user_id and w.effective_date <= b.date_stamp and w.wage_group_id = \'' . TTUUID::getZeroID() . '\' and w.deleted = 0 order by w.effective_date desc LiMiT 1) 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 ) '; if ( getTTProductEdition() >= TT_PRODUCT_CORPORATE ) { $query .= ' LEFT JOIN ' . $jf->getTable() . ' as r ON b.job_id = r.id'; $query .= ' LEFT JOIN ' . $jif->getTable() . ' as s ON b.job_item_id = s.id'; $query .= ' LEFT JOIN ' . $jf->getTable() . ' as r2 ON d.default_job_id = r2.id'; $query .= ' LEFT JOIN ' . $jif->getTable() . ' as s2 ON d.default_job_item_id = s2.id'; } $query .= ' WHERE d.company_id = ?'; $query .= ( isset( $filter_data['permission_children_ids'] ) ) ? $this->getWhereClauseSQL( 'd.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( 'd.id', $filter_data['exclude_id'], 'not_uuid_list', $ph ) : null; $query .= ( isset( $filter_data['user_id'] ) ) ? $this->getWhereClauseSQL( 'b.user_id', $filter_data['user_id'], '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['legal_entity_id'] ) ) ? $this->getWhereClauseSQL( 'd.legal_entity_id', $filter_data['legal_entity_id'], 'uuid_list', $ph ) : null; if ( isset( $filter_data['include_subgroups'] ) && (bool)$filter_data['include_subgroups'] == true ) { $uglf = new UserGroupListFactory(); $filter_data['user_group_id'] = $uglf->getByCompanyIdAndGroupIdAndSubGroupsArray( $company_id, $filter_data['user_group_id'], true ); } $query .= ( isset( $filter_data['user_group_id'] ) ) ? $this->getWhereClauseSQL( 'd.group_id', $filter_data['user_group_id'], 'uuid_list', $ph ) : null; $query .= ( isset( $filter_data['user_group'] ) ) ? $this->getWhereClauseSQL( 'g.name', $filter_data['user_group'], 'text', $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['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['status_id'] ) ) ? $this->getWhereClauseSQL( 'a.status_id', $filter_data['status_id'], 'numeric_list', $ph ) : null; $query .= ( isset( $filter_data['type_id'] ) ) ? $this->getWhereClauseSQL( 'a.type_id', $filter_data['type_id'], 'numeric_list', $ph ) : null; $query .= ( isset( $filter_data['pay_period_id'] ) ) ? $this->getWhereClauseSQL( 'b.pay_period_id', $filter_data['pay_period_id'], 'uuid_list', $ph ) : null; $query .= ( isset( $filter_data['branch_id'] ) ) ? $this->getWhereClauseSQL( 'b.branch_id', $filter_data['branch_id'], 'uuid_list', $ph ) : null; $query .= ( isset( $filter_data['department_id'] ) ) ? $this->getWhereClauseSQL( 'b.department_id', $filter_data['department_id'], 'uuid_list', $ph ) : null; $query .= ( isset( $filter_data['created_by'] ) ) ? $this->getWhereClauseSQL( 'a.created_by', $filter_data['created_by'], 'uuid_list', $ph ) : null; $query .= ( isset( $filter_data['updated_by'] ) ) ? $this->getWhereClauseSQL( 'a.updated_by', $filter_data['updated_by'], 'uuid_list', $ph ) : null; if ( getTTProductEdition() >= TT_PRODUCT_CORPORATE ) { $query .= $this->getCustomFieldWhereSQL( $company_id, 'b.custom_field', $filter_data, $ph ); $query .= ( isset( $filter_data['job_id'] ) ) ? $this->getWhereClauseSQL( 'b.job_id', $filter_data['job_id'], 'uuid_list', $ph ) : null; $query .= ( isset( $filter_data['include_job_id'] ) ) ? $this->getWhereClauseSQL( 'b.job_id', $filter_data['include_job_id'], 'uuid_list', $ph ) : null; $query .= ( isset( $filter_data['exclude_job_id'] ) ) ? $this->getWhereClauseSQL( 'b.job_id', $filter_data['exclude_job_id'], 'not_uuid_list', $ph ) : null; $query .= ( isset( $filter_data['job_group_id'] ) ) ? $this->getWhereClauseSQL( 'r.group_id', $filter_data['job_group_id'], 'uuid_list', $ph ) : null; $query .= ( isset( $filter_data['job_item_id'] ) ) ? $this->getWhereClauseSQL( 'b.job_item_id', $filter_data['job_item_id'], 'uuid_list', $ph ) : null; $query .= ( isset( $filter_data['include_job_item_id'] ) ) ? $this->getWhereClauseSQL( 'b.job_item_id', $filter_data['include_job_item_id'], 'uuid_list', $ph ) : null; $query .= ( isset( $filter_data['exclude_job_item_id'] ) ) ? $this->getWhereClauseSQL( 'b.job_item_id', $filter_data['exclude_job_item_id'], 'not_uuid_list', $ph ) : null; $query .= ( isset( $filter_data['punch_tag_id'] ) ) ? $this->getWhereClauseSQL( 'b.punch_tag_id', $filter_data['punch_tag_id'], 'jsonb_uuid_array', $ph ) : null; } $query .= ( isset( $filter_data['date_stamp'] ) ) ? $this->getWhereClauseSQL( 'b.date_stamp', $filter_data['date_stamp'], 'date_range_datestamp', $ph ) : null; $query .= ( isset( $filter_data['start_date'] ) ) ? $this->getWhereClauseSQL( 'b.date_stamp', TTDate::parseDateTime( $filter_data['start_date'] ), 'start_datestamp', $ph ) : null; $query .= ( isset( $filter_data['end_date'] ) ) ? $this->getWhereClauseSQL( 'b.date_stamp', TTDate::parseDateTime( $filter_data['end_date'] ), 'end_datestamp', $ph ) : null; $query .= ( isset( $filter_data['time_stamp'] ) ) ? $this->getWhereClauseSQL( 'a.time_stamp', $filter_data['time_stamp'], 'date_range_timestamp', $ph ) : null; $query .= ( isset( $filter_data['created_date'] ) ) ? $this->getWhereClauseSQL( 'a.created_date', $filter_data['created_date'], 'date_range', $ph ) : null; $query .= ( isset( $filter_data['updated_date'] ) ) ? $this->getWhereClauseSQL( 'a.updated_date', $filter_data['updated_date'], 'date_range', $ph ) : null; $query .= ' AND (a.deleted = 0 AND b.deleted = 0 AND d.deleted = 0) '; $query .= $this->getWhereSQL( $where ); $query .= $this->getSortSQL( $order, $strict, $additional_order_fields ); //Debug::Query($query, $ph, __FILE__, __LINE__, __METHOD__, 10); $this->rs = $this->ExecuteSQL( $query, $ph, $limit, $page ); 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|PunchListFactory */ function getLastPunchByCompanyIdAndArrayCriteria( $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 = array('b.name', 'c.name', 'd.name', 'e.name'); $additional_order_fields = [ 'b.branch_id', 'b.date_stamp', 'd.last_name', 'a.time_stamp', 'a.status_id', 'b.branch_id', 'b.department_id', 'e.type_id' ]; if ( $order == null ) { $order = [ 'b.branch_id' => 'asc', 'd.last_name' => 'asc', 'a.time_stamp' => 'desc', 'a.punch_control_id' => 'asc', 'a.status_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['user_status_ids'] ) ) { $filter_data['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['branch_ids'] ) ) { $filter_data['default_branch_id'] = $filter_data['branch_ids']; } if ( isset( $filter_data['department_ids'] ) ) { $filter_data['default_department_id'] = $filter_data['department_ids']; } if ( isset( $filter_data['punch_branch_ids'] ) ) { $filter_data['punch_branch_id'] = $filter_data['punch_branch_ids']; } if ( isset( $filter_data['punch_department_ids'] ) ) { $filter_data['punch_department_id'] = $filter_data['punch_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(); $pcf = new PunchControlFactory(); $sf = new StationFactory(); if ( getTTProductEdition() >= TT_PRODUCT_CORPORATE ) { $jf = new JobFactory(); $jif = new JobItemFactory(); } $ph = [ 'company_id' => TTUUID::castUUID( $company_id ), ]; $query = ' select a.id as punch_id, a.punch_control_id as punch_control_id, a.type_id as type_id, a.status_id as status_id, a.time_stamp as time_stamp, a.actual_time_stamp as actual_time_stamp, b.date_stamp as date_stamp, b.branch_id as branch_id, b.department_id as department_id, b.job_id as job_id, b.job_item_id as job_item_id, b.note as note, b.user_id as user_id, e.type_id as station_type_id, e.station_id as station_station_id, e.source as station_source, e.description as station_description from ' . $this->getTable() . ' as a LEFT JOIN ' . $pcf->getTable() . ' as b ON a.punch_control_id = b.id LEFT JOIN ' . $uf->getTable() . ' as d ON b.user_id = d.id LEFT JOIN ' . $sf->getTable() . ' as e ON a.station_id = e.id LEFT JOIN ( select tmp2_d.id, max(tmp2_a.time_stamp) as max_punch_time_stamp from ' . $this->getTable() . ' as tmp2_a LEFT JOIN ' . $pcf->getTable() . ' as tmp2_b ON tmp2_a.punch_control_id = tmp2_b.id LEFT JOIN ' . $uf->getTable() . ' as tmp2_d ON tmp2_b.user_id = tmp2_d.id WHERE tmp2_d.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'] ) ); $query .= ' AND tmp2_b.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'] ) ); $query .= ' AND tmp2_b.date_stamp <= ?'; } $query .= ' AND tmp2_a.time_stamp is not null AND ( tmp2_a.deleted = 0 AND tmp2_b.deleted = 0 ) group by tmp2_d.id ) as tmp2 ON b.user_id = tmp2.id AND a.time_stamp = tmp2.max_punch_time_stamp '; if ( getTTProductEdition() >= TT_PRODUCT_CORPORATE ) { $query .= ' LEFT JOIN ' . $jf->getTable() . ' as x ON b.job_id = x.id'; $query .= ' LEFT JOIN ' . $jif->getTable() . ' as y ON b.job_item_id = y.id'; } $ph[] = $company_id; $query .= ' WHERE tmp2.id IS NOT NULL AND d.company_id = ?'; if ( isset( $filter_data['permission_children_ids'] ) && isset( $filter_data['permission_children_ids'][0] ) && !in_array( TTUUID::getNotExistID(), (array)$filter_data['permission_children_ids'] ) ) { $query .= ' AND d.id in (' . $this->getListSQL( $filter_data['permission_children_ids'], $ph ) . ') '; } if ( isset( $filter_data['id'] ) && isset( $filter_data['id'][0] ) && !in_array( TTUUID::getNotExistID(), (array)$filter_data['id'] ) ) { $query .= ' AND d.id in (' . $this->getListSQL( $filter_data['id'], $ph ) . ') '; } if ( isset( $filter_data['exclude_id'] ) && isset( $filter_data['exclude_id'][0] ) && !in_array( TTUUID::getNotExistID(), (array)$filter_data['exclude_id'] ) ) { $query .= ' AND d.id not in (' . $this->getListSQL( $filter_data['exclude_id'], $ph ) . ') '; } if ( isset( $filter_data['status_id'] ) && isset( $filter_data['status_id'][0] ) && !in_array( -1, (array)$filter_data['status_id'] ) ) { $query .= ' AND d.status_id in (' . $this->getListSQL( $filter_data['status_id'], $ph ) . ') '; } if ( isset( $filter_data['group_id'] ) && isset( $filter_data['group_id'][0] ) && !in_array( TTUUID::getNotExistID(), (array)$filter_data['group_id'] ) ) { if ( isset( $filter_data['include_subgroups'] ) && (bool)$filter_data['include_subgroups'] == true ) { $uglf = new UserGroupListFactory(); $filter_data['group_id'] = $uglf->getByCompanyIdAndGroupIdAndSubGroupsArray( $company_id, $filter_data['group_id'], true ); } $query .= ' AND d.group_id in (' . $this->getListSQL( $filter_data['group_id'], $ph ) . ') '; } if ( isset( $filter_data['default_branch_id'] ) && isset( $filter_data['default_branch_id'][0] ) && !in_array( TTUUID::getNotExistID(), (array)$filter_data['default_branch_id'] ) ) { $query .= ' AND d.default_branch_id in (' . $this->getListSQL( $filter_data['default_branch_id'], $ph ) . ') '; } if ( isset( $filter_data['default_department_id'] ) && isset( $filter_data['default_department_id'][0] ) && !in_array( TTUUID::getNotExistID(), (array)$filter_data['default_department_id'] ) ) { $query .= ' AND d.default_department_id in (' . $this->getListSQL( $filter_data['default_department_id'], $ph ) . ') '; } if ( isset( $filter_data['title_id'] ) && isset( $filter_data['title_id'][0] ) && !in_array( TTUUID::getNotExistID(), (array)$filter_data['title_id'] ) ) { $query .= ' AND d.title_id in (' . $this->getListSQL( $filter_data['title_id'], $ph ) . ') '; } if ( isset( $filter_data['punch_branch_id'] ) && isset( $filter_data['punch_branch_id'][0] ) && !in_array( TTUUID::getNotExistID(), (array)$filter_data['punch_branch_id'] ) ) { $query .= ' AND b.branch_id in (' . $this->getListSQL( $filter_data['punch_branch_id'], $ph ) . ') '; } if ( isset( $filter_data['punch_department_id'] ) && isset( $filter_data['punch_department_id'][0] ) && !in_array( TTUUID::getNotExistID(), (array)$filter_data['punch_department_id'] ) ) { $query .= ' AND b.department_id in (' . $this->getListSQL( $filter_data['punch_department_id'], $ph ) . ') '; } //Use the job_id in the punch_control table so we can filter by '0' or No Job if ( isset( $filter_data['include_job_id'] ) && isset( $filter_data['include_job_id'][0] ) && !in_array( TTUUID::getNotExistID(), (array)$filter_data['include_job_id'] ) ) { $query .= ' AND b.job_id in (' . $this->getListSQL( $filter_data['include_job_id'], $ph ) . ') '; } if ( isset( $filter_data['exclude_job_id'] ) && isset( $filter_data['exclude_job_id'][0] ) && !in_array( TTUUID::getNotExistID(), (array)$filter_data['exclude_job_id'] ) ) { $query .= ' AND b.job_id not in (' . $this->getListSQL( $filter_data['exclude_job_id'], $ph ) . ') '; } if ( isset( $filter_data['job_group_id'] ) && isset( $filter_data['job_group_id'][0] ) && !in_array( TTUUID::getNotExistID(), (array)$filter_data['job_group_id'] ) ) { if ( isset( $filter_data['include_job_subgroups'] ) && (bool)$filter_data['include_job_subgroups'] == true ) { $uglf = new UserGroupListFactory(); $filter_data['job_group_id'] = $uglf->getByCompanyIdAndGroupIdAndjob_subgroupsArray( $company_id, $filter_data['job_group_id'], true ); } $query .= ' AND x.group_id in (' . $this->getListSQL( $filter_data['job_group_id'], $ph ) . ') '; } if ( isset( $filter_data['job_item_id'] ) && isset( $filter_data['job_item_id'][0] ) && !in_array( TTUUID::getNotExistID(), (array)$filter_data['job_item_id'] ) ) { $query .= ' AND b.job_item_id in (' . $this->getListSQL( $filter_data['job_item_id'], $ph ) . ') '; } if ( isset( $filter_data['start_date'] ) && !is_array( $filter_data['start_date'] ) && trim( $filter_data['start_date'] ) != '' ) { /* $ph[] = $this->db->BindDate($filter_data['start_date']); $query .= ' AND c.date_stamp >= ?'; */ $ph[] = $this->db->BindTimeStamp( (int)TTDate::parseDateTime( $filter_data['start_date'] ) ); $query .= ' AND a.time_stamp >= ?'; } if ( isset( $filter_data['end_date'] ) && !is_array( $filter_data['end_date'] ) && trim( $filter_data['end_date'] ) != '' ) { $ph[] = $this->db->BindTimeStamp( (int)TTDate::parseDateTime( $filter_data['end_date'] ) ); $query .= ' AND a.time_stamp <= ?'; } //The Transfer where clause is an attempt to keep transferred punches from appearing twice. $query .= ' AND ( a.transfer = 0 OR ( a.transfer = 1 AND a.status_id = 10) ) AND ( a.deleted = 0 AND b.deleted = 0 AND d.deleted = 0 ) '; $query .= $this->getWhereSQL( $where ); $query .= $this->getSortSQL( $order, $strict, $additional_order_fields ); $this->rs = $this->ExecuteSQL( $query, $ph, $limit, $page ); return $this; } } ?>