<?php
/*********************************************************************************
 * The contents of this file are subject to the TimeTrex Public License Version
 * 1.1.0 ("License"); You may not use this file except in compliance with the
 * License. You may obtain a copy of the License at http://www.TimeTrex.com/TPL
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied.  See the License
 * for the specific language governing rights and limitations under the
 * License.
 *
 * All copies of the Covered Code must include on each user interface screen:
 *    (i) the "Powered by TimeTrex" logo and
 *    (ii) the TimeTrex copyright notice
 * in the same form as they appear in the distribution.  See full license for
 * requirements.
 *
 * The Original Code is: TimeTrex Open Source
 * The Initial Developer of the Original Code is TimeTrex Payroll Services
 * Portions created by TimeTrex are Copyright (C) 2004-2007 TimeTrex Payroll Services;
 * All Rights Reserved.
 *
 ********************************************************************************/
/*
 * $Revision: 2158 $
 * $Id: PayPeriodFactory.class.php 2158 2008-09-15 23:26:15Z ipso $
 * $Date: 2008-09-15 16:26:15 -0700 (Mon, 15 Sep 2008) $
 */

/**
 * @package Module_PayPeriod
 */
class PayPeriodFactory extends Factory {
	protected $table = 'pay_period';
	protected $pk_sequence_name = 'pay_period_id_seq'; //PK Sequence name

	var $pay_period_schedule_obj = NULL;

	function _getFactoryOptions( $name ) {

		$retval = NULL;
		switch( $name ) {
			case 'status':
				$retval = array(
										10 => TTi18n::gettext('OPEN'),
										12 => TTi18n::gettext('Locked - Pending Approval'), //Go to this state as soon as date2 is passed
										15 => TTi18n::gettext('Locked - Pending Transaction'), //Go to this as soon as approved, or 48hrs before transaction date.
										20 => TTi18n::gettext('CLOSED'), //Once paid
										30 => TTi18n::gettext('Post Adjustment')
									);
				break;

		}

		return $retval;
	}

	function getPayPeriodScheduleObject() {
		if ( is_object($this->pay_period_schedule_obj) ) {
			return $this->pay_period_schedule_obj;
		} else {
			$ppslf = new PayPeriodScheduleListFactory();
			//$this->pay_period_schedule_obj = $ppslf->getById( $this->getPayPeriodSchedule() )->getCurrent();
			$ppslf->getById( $this->getPayPeriodSchedule() );
			if ( $ppslf->getRecordCount() > 0 ) {
				$this->pay_period_schedule_obj = $ppslf->getCurrent();
				return $this->pay_period_schedule_obj;
			}

			return FALSE;

		}
	}

	function getCompany() {
		return $this->data['company_id'];
	}
	function setCompany($id) {
		$id = trim($id);

		$clf = new CompanyListFactory();

		if ( $this->Validator->isResultSetWithRows(	'company',
													$clf->getByID($id),
													TTi18n::gettext('Company is invalid')
													) ) {

			$this->data['company_id'] = $id;

			return TRUE;
		}

		return FALSE;
	}

	function getStatus() {
		if ( isset($this->data['status_id']) ) {
			return $this->data['status_id'];
		}

		return FALSE;
	}
	function setStatus($status) {
		$status = trim($status);

		$key = Option::getByValue($status, $this->getOptions('status') );
		if ($key !== FALSE) {
			$status = $key;
		}

		if ( $this->Validator->inArrayKey(	'status',
											$status,
											TTi18n::gettext('Incorrect Status'),
											$this->getOptions('status')) ) {

			$this->data['status_id'] = $status;

			return FALSE;
		}

		return FALSE;
	}

	function getPayPeriodSchedule() {
		if ( isset($this->data['pay_period_schedule_id']) ) {
			return $this->data['pay_period_schedule_id'];
		}

		return FALSE;
	}
	function setPayPeriodSchedule($id) {
		$id = trim($id);

		$ppslf = new PayPeriodScheduleListFactory();

		if ( $id == 0
				OR $this->Validator->isResultSetWithRows(	'pay_period_schedule',
															$ppslf->getByID($id),
															TTi18n::gettext('Incorrect Pay Period Schedule')
															) ) {
			$this->data['pay_period_schedule_id'] = $id;

			return TRUE;
		}

		return FALSE;
	}

	function isValidStartDate($epoch) {
		if ( $this->isNew() ) {
			$id = 0;
		} else {
			$id = $this->getId();
		}

		$ph = array(
					'pay_period_schedule_id' => $this->getPayPeriodSchedule(),
					'start_date' => $this->db->BindTimeStamp($epoch),
					'end_date' => $this->db->BindTimeStamp($epoch),
					'id' => $id,
					);

		//Used to have LIMIT 1 at the end, but GetOne() should do that for us.
		$query = 'select id from '. $this->getTable() .'
					where	pay_period_schedule_id = ?
						AND start_date <= ?
						AND end_date >= ?
						AND deleted=0
						AND id != ?
					';
		$id = $this->db->GetOne($query, $ph);
		Debug::Arr($id,'Pay Period ID of conflicting pay period: '. $epoch, __FILE__, __LINE__, __METHOD__,10);

		if ( $id === FALSE ) {
			Debug::Text('aReturning TRUE!', __FILE__, __LINE__, __METHOD__,10);
			return TRUE;
		} else {
			if ($id == $this->getId() ) {
				Debug::Text('bReturning TRUE!', __FILE__, __LINE__, __METHOD__,10);
				return TRUE;
			}
		}

		Debug::Text('Returning FALSE!', __FILE__, __LINE__, __METHOD__,10);
		return FALSE;
	}

	function getStartDate( $raw = FALSE ) {
		if ( isset($this->data['start_date']) ) {
			if ( $raw === TRUE ) {
				return $this->data['start_date'];
			} else {
				//return $this->db->UnixTimeStamp( $this->data['start_date'] );
				//strtotime is MUCH faster than UnixTimeStamp
				//Must use ADODB for times pre-1970 though.
				return TTDate::strtotime( $this->data['start_date'] );
			}
		}

		return FALSE;
	}
	function setStartDate($epoch) {
		$epoch = trim($epoch);

		if 	(	$this->Validator->isDate(		'start_date',
												$epoch,
												TTi18n::gettext('Incorrect start date'))
				AND
				$this->Validator->isTrue(		'start_date',
												$this->isValidStartDate($epoch),
												TTi18n::gettext('Conflicting start date'))

			) {

			//$this->data['start_date'] = $epoch;
			$this->data['start_date'] = $epoch;

			return TRUE;
		}

		return FALSE;
	}

	function getEndDate( $raw = FALSE ) {
		if ( isset($this->data['end_date']) ) {
			if ( $raw === TRUE ) {
				return $this->data['end_date'];
			} else {
				return TTDate::strtotime( $this->data['end_date'] );
			}
		}

		return FALSE;
	}
	function setEndDate($epoch) {
		$epoch = trim($epoch);

		if 	(	$this->Validator->isDate(		'end_date',
												$epoch,
												TTi18n::gettext('Incorrect end date')) ) {

			//$this->data['end_date'] = $epoch;
			$this->data['end_date'] = $epoch;

			return TRUE;
		}

		return FALSE;
	}

	function getTransactionDate( $raw = FALSE ) {
		if ( isset($this->data['transaction_date']) ) {
			if ( $raw === TRUE ) {
				return $this->data['transaction_date'];
			} else {
				return TTDate::strtotime( $this->data['transaction_date'] );
			}
		}

		return FALSE;
	}
	function setTransactionDate($epoch) {
		$epoch = trim($epoch);

		if 	(	$this->Validator->isDate(		'transaction_date',
												$epoch,
												TTi18n::gettext('Incorrect transaction date')) ) {

			$this->data['transaction_date'] = $epoch;

			return TRUE;
		}

		return FALSE;
	}

	function getAdvanceEndDate( $raw = FALSE ) {
		if ( isset($this->data['advance_end_date']) ) {
			return TTDate::strtotime($this->data['advance_end_date']);
		}

		return FALSE;
	}
	function setAdvanceEndDate($epoch) {
		$epoch = trim($epoch);

		if 	(	$epoch == FALSE
				OR
				$this->Validator->isDate(		'advance_end_date',
												$epoch,
												TTi18n::gettext('Incorrect advance end date')) ) {

			$this->data['advance_end_date'] = $epoch;

			return TRUE;
		}

		return FALSE;
	}

	function getAdvanceTransactionDate() {
		if ( isset($this->data['advance_transaction_date']) ) {
			return TTDate::strtotime($this->data['advance_transaction_date']);
			/*
			if ( (int)$this->data['advance_transaction_date'] == 0 ) {
				return strtotime( $this->data['advance_transaction_date'] );
			} else {
				return $this->data['advance_transaction_date'];
			}
			*/
		}

		return FALSE;
	}
	function setAdvanceTransactionDate($epoch) {
		$epoch = trim($epoch);

		if 	(	$epoch == FALSE
				OR
				$this->Validator->isDate(		'advance_transaction_date',
												$epoch,
												TTi18n::gettext('Incorrect advance transaction date')) ) {

			$this->data['advance_transaction_date'] = $epoch;

			return TRUE;
		}

		return FALSE;
	}

	function getPrimary() {
		return $this->fromBool( $this->data['is_primary'] );
	}
	function setPrimary($bool) {
		$this->data['is_primary'] = $this->toBool($bool);

		return true;
	}

	function setPayStubStatus($status) {
		Debug::text('setPayStubStatus: '. $status, __FILE__, __LINE__, __METHOD__, 10);

		$this->StartTransaction();

		$pslf = new PayStubListFactory();
		$pslf->getByPayPeriodId( $this->getId() );
		foreach($pslf as $pay_stub) {
			//Only change status of advance pay stubs if we're in the advance part of the pay period.
			//What if the person is too late, set status anyways?
			if ( $pay_stub->getStatus() != $status
					/*
					AND (
							(
							$this->getPayPeriodScheduleObject()->getType() == 40
								AND TTDate::getTime() < $this->getAdvanceTransactionDate()
								AND $pay_stub->getAdvance() == TRUE
							)
						OR
							$pay_stub->getAdvance() == FALSE
						)
					*/
				) {

				Debug::text('Changing Status of Pay Stub ID: '. $pay_stub->getId(), __FILE__, __LINE__, __METHOD__, 10);
				$pay_stub->setStatus($status);
				$pay_stub->save();
			}
		}

		$this->CommitTransaction();

		return TRUE;
	}

	function getTainted() {
		return $this->fromBool( $this->data['tainted'] );
	}
	function setTainted($bool) {
		$this->data['tainted'] = $this->toBool($bool);

		return true;
	}

	function getTaintedDate() {
		if ( isset($this->data['tainted_date']) ) {
			return $this->data['tainted_date'];
		}

		return FALSE;
	}
	function setTaintedDate($epoch = NULL) {
		$epoch = trim($epoch);

		if ($epoch == NULL) {
			$epoch = TTDate::getTime();
		}

		if 	(	$this->Validator->isDate(		'tainted_date',
												$epoch,
												TTi18n::gettext('Incorrect tainted date') ) ) {

			$this->data['tainted_date'] = $epoch;

			return TRUE;
		}

		return FALSE;

	}
	function getTaintedBy() {
		if ( isset($this->data['tainted_by']) ) {
			return $this->data['tainted_by'];
		}

		return FALSE;
	}
	function setTaintedBy($id = NULL) {
		$id = trim($id);

		if ( empty($id) ) {
			global $current_user;

			if ( is_object($current_user) ) {
				$id = $current_user->getID();
			} else {
				return FALSE;
			}
		}

		$ulf = new UserListFactory();

		if ( $this->Validator->isResultSetWithRows(	'tainted_by',
													$ulf->getByID($id),
													TTi18n::gettext('Incorrect tainted employee')
													) ) {

			$this->data['tainted_by'] = $id;

			return TRUE;
		}

		return FALSE;
	}

	function getIsLocked() {
		if ( $this->getStatus() == 10 OR $this->getStatus() == 30 OR $this->isNew() == TRUE ) {
			return FALSE;
		}

		return TRUE;
	}

	function getName($include_schedule_name = FALSE) {
		$schedule_name = NULL;
		if ( $include_schedule_name == TRUE ) {
			$schedule_name = '('. $this->getPayPeriodScheduleObject()->getName() .') ';
		}

		$retval = $schedule_name . TTDate::getDate('DATE', $this->getStartDate() ).' -> '. TTDate::getDate('DATE', $this->getEndDate() );

		return $retval;
	}

	function getEnableImportData() {
		if ( isset($this->import_data) ) {
			return $this->import_data;
		}

		return FALSE;
	}
	function setEnableImportData($bool) {
		$this->import_data = $bool;

		return TRUE;
	}

	function importData() {
		$pps_obj = $this->getPayPeriodScheduleObject();

		if ( is_object( $pps_obj ) ) {
			//Get all users assigned to this pp schedule
			$udlf = new UserDateListFactory();
			$udlf->getByUserIdAndStartDateAndEndDateAndEmptyPayPeriod( $pps_obj->getUser(), $this->getStartDate(), $this->getEndDate() );
			Debug::text(' Pay Period ID: '. $this->getId() .' Pay Period orphaned User Date Rows: '. $udlf->getRecordCount() .' Start Date: '. TTDate::getDate('DATE+TIME', $this->getStartDate() ) .' End Date: '. TTDate::getDate('DATE+TIME', $this->getEndDate() ), __FILE__, __LINE__, __METHOD__,10);
			if ( $udlf->getRecordCount() > 0 ) {
				$udlf->StartTransaction();
				foreach( $udlf as $ud_obj ) {
					$ud_obj->setPayPeriod( $this->getId() );
					if ( $ud_obj->isValid() ) {
						$ud_obj->Save();
					}
				}
				$ud_obj->CommitTransaction();
			}

			return TRUE;
		}

		return FALSE;
	}

	function Validate() {
		//Make sure there aren't conflicting pay periods.
		//Start date checks that...

		//Make sure End Date is after Start Date, and transaction date is the same or after End Date.
		Debug::text('Start Date: '. $this->getStartDate() .' End Date: '. $this->getEndDate(), __FILE__, __LINE__, __METHOD__, 10);
		if ( $this->getEndDate() <= $this->getStartDate() ) {
			$this->Validator->isTrue(		'end_date',
											FALSE,
											TTi18n::gettext('Conflicting end date'));
		}

		if ( $this->getTransactionDate() < $this->getEndDate() ) {
			$this->Validator->isTrue(		'transaction_date',
											FALSE,
											TTi18n::gettext('Conflicting transaction date'));
		}

		//Make sure if this a monthly+advanc pay period, advance dates are set.
        $ppslf = new PayPeriodScheduleListFactory();
		$ppslf->getById( $this->getPayPeriodSchedule() );


		if ( $ppslf->getRecordCount() == 1 AND is_object($ppslf) AND $ppslf->getCurrent()->getType() == 40 ) {
			Debug::text('Pay Period Type IS Monthly + Advance: ', __FILE__, __LINE__, __METHOD__, 10);
			if ( $this->getAdvanceEndDate() === FALSE ) {
				$this->Validator->isTrue(		'advance_end_date',
												FALSE,
												TTi18n::gettext('Advance end date is not set') );
			}

			if ( $this->getAdvanceTransactionDate() === FALSE ) {
				$this->Validator->isTrue(		'advance_transaction_date',
												FALSE,
												TTi18n::gettext('Advance transaction date is not set') );
			}

			//Make sure advance dates are in the proper range.
			if ( $this->getAdvanceEndDate() > $this->getEndDate()
					OR  $this->getAdvanceEndDate() < $this->getStartDate() ) {
						$this->Validator->isDate(		'advance_end_date',
														FALSE,
														TTi18n::gettext('Incorrect advance end date'));
			}

			if ( $this->getAdvanceTransactionDate() > $this->getEndDate()
					OR  $this->getAdvanceTransactionDate() < $this->getAdvanceEndDate() ) {
						$this->Validator->isDate(		'advance_transaction_date',
														FALSE,
														TTi18n::gettext('Incorrect advance transaction date'));
			}

		} elseif ( $ppslf->getRecordCount() == 1 AND is_object($ppslf) ) {
			Debug::text('Pay Period Type is NOT Monthly + Advance... Advance End Date: '. $this->getAdvanceEndDate(), __FILE__, __LINE__, __METHOD__, 10);
			if ( $this->getAdvanceEndDate() != '' ) {
				$this->Validator->isTrue(		'advance_end_date',
												FALSE,
												TTi18n::gettext('Advance end date is set') );
			}

			if ( $this->getAdvanceTransactionDate() != '' ) {
				$this->Validator->isTrue(		'advance_transaction_date',
												FALSE,
												TTi18n::gettext('Advance transaction date is set') );
			}
		} else {
			Debug::text('Pay Period Schedule not found: '. $this->getPayPeriodSchedule(), __FILE__, __LINE__, __METHOD__, 10);
			$this->Validator->isTrue(		'pay_period_schedule',
											FALSE,
											TTi18n::gettext('Incorrect Pay Period Schedule') );
		}

		return TRUE;
	}

	function preSave() {
		$this->StartTransaction();

		if ( $this->getDeleted() == TRUE ) {
			Debug::text('Delete TRUE: ', __FILE__, __LINE__, __METHOD__, 10);
			//Remove all user_date rows, punch control, punches, and schedules
			$udlf = new UserDateListFactory();
			$udlf->getByPayPeriodID( $this->getId() );
			if ( $udlf->getRecordCount() > 0 ) {
				Debug::text('Delete User Date Rows: '. $udlf->getRecordCount(), __FILE__, __LINE__, __METHOD__, 10);
				foreach($udlf as $ud_obj ) {
					$ud_obj->setDeleted(TRUE);
					$ud_obj->Save();
				}
			} else {
				Debug::text('No User Date Rows to Delete', __FILE__, __LINE__, __METHOD__, 10);
			}
		}

		if ( $this->getStatus() == 30 ) {
			$this->setTainted(TRUE);
		}

		//Only update these when we are setting the pay period to Post-Adjustment status.
		if ( $this->getStatus() == 30 AND $this->getTainted() == TRUE ) {
			$this->setTaintedBy();
			$this->setTaintedDate();
		}

		return TRUE;
	}

	function postSave() {
		$this->removeCache( $this->getId() );

		if ( $this->getStatus() == 20 ) { //Closed
			//Mark pay stubs as PAID once the pay period is closed?
			TTLog::addEntry( $this->getId(), 'Edit',  TTi18n::getText('Setting Pay Period to Closed'), NULL, $this->getTable() );
			$this->setPayStubStatus(40);
		} elseif ( $this->getStatus() == 30 ) {
			TTLog::addEntry( $this->getId(), 'Edit',  TTi18n::getText('Setting Pay Period to Post-Adjustment'), NULL, $this->getTable() );
		}

		if ( $this->getEnableImportData() == TRUE ) {
			$this->importData();
		}

		$this->CommitTransaction();

		return TRUE;
	}

}
?>
