<?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: UserWageFactory.class.php 2158 2008-09-15 23:26:15Z ipso $
 * $Date: 2008-09-15 16:26:15 -0700 (Mon, 15 Sep 2008) $
 */

/**
 * @package Module_Users
 */
class UserWageFactory extends Factory {
	protected $table = 'user_wage';
	protected $pk_sequence_name = 'user_wage_id_seq'; //PK Sequence name

	var $user_obj = NULL;
	var $labor_standard_obj = NULL;
	var $holiday_obj = NULL;

	function _getFactoryOptions( $name ) {

		$retval = NULL;
		switch( $name ) {
			case 'type':
				$retval = array(
											10 	=> TTi18n::gettext('Hourly'),
											12	=> TTi18n::gettext('Salary (Weekly)'),
											13	=> TTi18n::gettext('Salary (Bi-Weekly)'),
											15	=> TTi18n::gettext('Salary (Monthly)'),
											20	=> TTi18n::gettext('Salary (Annual)'),
//											30	=> TTi18n::gettext('Min. Wage + Bonus (Salary)')
									);
				break;

		}

		return $retval;
	}


	function getUserObject() {
		if ( is_object($this->user_obj) ) {
			return $this->user_obj;
		} else {
			$ulf = new UserListFactory();
			$this->user_obj = $ulf->getById( $this->getUser() )->getCurrent();

			return $this->user_obj;
		}
	}

	function getUser() {
		return $this->data['user_id'];
	}
	function setUser($id) {
		$id = trim($id);

		$ulf = new UserListFactory();

		if ( $id == 0
				OR $this->Validator->isResultSetWithRows(	'user',
															$ulf->getByID($id),
															TTi18n::gettext('Invalid User')
															) ) {
			$this->data['user_id'] = $id;

			return TRUE;
		}

		return FALSE;
	}

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

		return FALSE;
	}
	function setType($type) {
		$type = trim($type);

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

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

			$this->data['type_id'] = $type;

			return TRUE;
		}

		return FALSE;
	}

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

		return FALSE;
	}
	function setWage($wage) {
		$wage = trim($wage);

		//Pull out only digits and periods.
		$wage = $this->Validator->stripNonFloat($wage);

		if (	$this->Validator->isFloat(	'wage',
											$wage,
											TTi18n::gettext('Incorrect Wage')) ) {

			$this->data['wage'] = $wage;

			return TRUE;
		}

		return FALSE;
	}

	function getWeeklyTime() {
		if ( isset($this->data['weekly_time']) ) {
			//Debug::Text('Weekly Time: '. $this->data['weekly_time'], __FILE__, __LINE__, __METHOD__,10);

			return $this->data['weekly_time'];
		}

		return FALSE;

	}
	function setWeeklyTime($value) {
		//$value = $value;

		if (	$value == NULL
				OR
				$this->Validator->isNumeric(	'weekly_time',
											$value,
											TTi18n::gettext('Incorrect Weekly Time')) ) {

			$this->data['weekly_time'] = $value;

			return TRUE;
		}

		return FALSE;
	}

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

		return FALSE;
	}
	function setLaborBurdenPercent($value) {
		$value = trim($value);

		//Pull out only digits and periods.
		$value = $this->Validator->stripNonFloat($value);

		if (	$this->Validator->isFloat(	'labor_burden_percent',
											$value,
											TTi18n::gettext('Incorrect Labor Burden Percent')) ) {

			$this->data['labor_burden_percent'] = $value;

			return TRUE;
		}

		return FALSE;
	}


	function isValidEffectiveDate($epoch) {
		return TRUE;
	}

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

		return FALSE;
	}
	function setEffectiveDate($epoch) {
		$epoch = TTDate::getBeginDayEpoch( trim($epoch) );

		Debug::Text('Effective Date: '. TTDate::getDate('DATE+TIME', $epoch ) , __FILE__, __LINE__, __METHOD__,10);

		if 	(	$this->Validator->isDate(		'effective_date',
												$epoch,
												TTi18n::gettext('Incorrect Effective Date'))
				AND
				$this->Validator->isTrue(		'effective_date',
												$this->isValidEffectiveDate($epoch),
												TTi18n::gettext('Effective Date must not be in the middle of a pay period'))
			) {

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

			return TRUE;
		}

		return FALSE;
	}

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

		return FALSE;
	}
	function setNote($value) {
		$value = trim($value);

		if (	$value == ''
				OR
						$this->Validator->isLength(		'note',
														$value,
														TTi18n::gettext('Note is too long'),
														1,
														2048)
			) {

			$this->data['note'] = $value;

			return FALSE;
		}

		return FALSE;
	}

	function getLaborBurdenHourlyRate( $rate ) {
		$retval = bcmul( $rate, bcadd( bcdiv( $this->getLaborBurdenPercent(), 100 ), 1) );

		return Misc::MoneyFormat($retval, FALSE);
	}

	function getBaseCurrencyHourlyRate( $rate ) {
		if ( $rate == '' ) {
			return FALSE;
		}

		$clf = new CurrencyListFactory();
		$clf->getByCompanyIdAndBase( $this->getUserObject()->getCompany(), TRUE );
		if ( $clf->getRecordCount() > 0 ) {
			$base_currency_obj = $clf->getCurrent();

			//If current currency is the base currency, just return the rate.
			if ( $base_currency_obj->getId() == $this->getUserObject()->getCurrency() ) {
				return $rate;
			} else {
				//Debug::text(' Base Currency Rate: '. $base_currency_obj->getConversionRate() .' Hourly Rate: '. $rate , __FILE__, __LINE__, __METHOD__,10);
				return CurrencyFactory::convertCurrency( $this->getUserObject()->getCurrency(), $base_currency_obj->getId(), $rate );
			}
		}

		return FALSE;
	}

	function getAnnualWage() {
		$annual_wage = 0;

		//Debug::text(' Type: '. $this->getType() .' Wage: '. $this->getWage() , __FILE__, __LINE__, __METHOD__,10);
		switch ( $this->getType() ) {
			case 10: //Hourly
				//Hourly wage type, can't have an annual wage.
				$annual_wage = 0;
				break;
			case 12: //Salary (Weekly)
				$annual_wage = bcmul( $this->getWage(), 52 );
				break;
			case 13: //Salary (Bi-Weekly)
				$annual_wage = bcmul( $this->getWage(), 26 );
				break;
			case 15: //Salary (Monthly)
				$annual_wage = bcmul( $this->getWage(), 12 );
				break;
			case 20: //Salary (Annual)
				//FIXME: make sure this is correct. With stat days/vacation days stuff.
				$annual_wage = $this->getWage();
				break;
		}

		return $annual_wage;
	}

	function getHourlyRate( $exclude_stats = FALSE, $exclude_vacation = FALSE, $epoch = FALSE ) {
		$hourly_wage = 0;

		if ( $this->getType() == 10 ) {
			$hourly_wage = $this->getWage();
		} else {
			$hourly_wage = $this->getAnnualHourlyRate( $this->getAnnualWage(), $exclude_stats, $exclude_vacation, $epoch );
		}

		return Misc::MoneyFormat($hourly_wage, FALSE);
	}

	function getAnnualHourlyRate( $annual_wage, $exclude_stats = FALSE, $exclude_vacation = FALSE, $epoch = FALSE ) {
		if ( $epoch == FALSE ) {
			$epoch = TTDate::getTime();
		}

		if( $annual_wage == '' ) {
			return FALSE;
		}
		//Debug::text('EPOCH: '. $epoch , __FILE__, __LINE__, __METHOD__,10);

		$annual_week_days = TTDate::getAnnualWeekDays( $epoch );
		//Debug::text('Annual Week Days: '. $annual_week_days , __FILE__, __LINE__, __METHOD__,10);

		//Calculate weeks from adjusted annual weekdays
		//We could use just 52 weeks in a year, but that isn't as accurate.
		$annual_work_weeks = bcdiv( $annual_week_days, 5);
		//Debug::text('Adjusted annual work weeks : '. $annual_work_weeks , __FILE__, __LINE__, __METHOD__,10);

		$average_weekly_hours = TTDate::getHours( $this->getWeeklyTime() );
		//Debug::text('Average Weekly Hours: '. $average_weekly_hours , __FILE__, __LINE__, __METHOD__,10);

		if ( $average_weekly_hours == 0 ) {
			//No default schedule, can't pay them.
			$hourly_wage = 0;
		} else {
			//Divide by average hours/day from default schedule?
			$hours_per_year = bcmul($annual_work_weeks, $average_weekly_hours);
			if ( $hours_per_year > 0 ) {
				$hourly_wage = bcdiv( $annual_wage, $hours_per_year );
			}
			unset($hours_per_year);
		}
		//Debug::text('User Wage: '. $this->getWage() , __FILE__, __LINE__, __METHOD__,10);
		//Debug::text('Annual Hourly Rate: '. $hourly_wage , __FILE__, __LINE__, __METHOD__,10);

		return $hourly_wage;
	}

	static function proRateSalary($salary, $wage_effective_date, $prev_wage_effective_date, $pp_start_date, $pp_end_date ) {
		$prev_wage_effective_date = (int)$prev_wage_effective_date;

		if ( $wage_effective_date < $pp_start_date ) {
			$wage_effective_date = $pp_start_date;
		}

		$total_pay_period_days = ceil( TTDate::getDayDifference( $pp_start_date, $pp_end_date) );

		if ( $prev_wage_effective_date == 0 ) {
			Debug::text(' Using Pay Period End Date: '. TTDate::GetDate('DATE', $pp_end_date) , __FILE__, __LINE__, __METHOD__,10);
			$total_wage_effective_days = ceil( TTDate::getDayDifference( $wage_effective_date, $pp_end_date) );
		} else {
			Debug::text(' Using Prev Effective Date: '. TTDate::GetDate('DATE', $prev_wage_effective_date ) , __FILE__, __LINE__, __METHOD__,10);
			$total_wage_effective_days = ceil( TTDate::getDayDifference( $wage_effective_date, $prev_wage_effective_date ) );
		}

		Debug::text('Salary: '. $salary .' Total Pay Period Days: '. $total_pay_period_days .' Wage Effective Days: '. $total_wage_effective_days , __FILE__, __LINE__, __METHOD__,10);

		//$pro_rate_salary = $salary * ($total_wage_effective_days / $total_pay_period_days);
		$pro_rate_salary = bcmul( $salary, bcdiv($total_wage_effective_days, $total_pay_period_days) );

		Debug::text('Pro Rate Salary: '. $pro_rate_salary, __FILE__, __LINE__, __METHOD__,10);
		return $pro_rate_salary;
	}

	static function getWageFromArray( $date, $wage_arr ) {
		if ( !is_array($wage_arr) ) {
			return FALSE;
		}

		if ( $date == '' ) {
			return FALSE;
		}

		//Debug::Arr($wage_arr, 'Wage Array: ', __FILE__, __LINE__, __METHOD__,10);

		foreach( $wage_arr as $effective_date => $wage ) {
			if ( $effective_date <= $date ) {
				Debug::Text('Effective Date: '. TTDate::getDate('DATE+TIME', $effective_date) .' Is Less Than: '. TTDate::getDate('DATE+TIME', $date)  , __FILE__, __LINE__, __METHOD__,10);
				return $wage;
			}
		}

		return FALSE;
	}

	//Takes the employees
	static function calculateLaborBurdenPercent( $company_id, $user_id ) {
		if ( $company_id == '' ) {
			return FALSE;
		}
		if ( $user_id == '' ) {
			return FALSE;
		}

		$end_epoch = TTDate::getTime();
		$start_epoch = TTDate::getTime()-(86400*180); //6mths

		$retval = FALSE;

		$pseallf = new PayStubEntryAccountLinkListFactory();
		$pseallf->getByCompanyID( $company_id );
		if ( $pseallf->getRecordCount() > 0 ) {
			$pself = new PayStubEntryListFactory();
			$total_gross = $pself->getAmountSumByUserIdAndEntryNameIdAndStartDateAndEndDate($user_id, $pseallf->getCurrent()->getTotalGross(), $start_epoch, $end_epoch );
			$total_employer_deductions = $pself->getAmountSumByUserIdAndEntryNameIdAndStartDateAndEndDate($user_id, $pseallf->getCurrent()->getTotalEmployerDeduction(), $start_epoch, $end_epoch );

			if ( isset($total_employer_deductions['amount']) AND isset($total_gross['amount']) ) {
				$retval = bcmul( bcdiv( $total_employer_deductions['amount'], $total_gross['amount']), 100, 2);
			}
		}

		return $retval;
	}

	function preSave() {
		if ( $this->getType() == 10 ) { //Hourly
			$this->setWeeklyTime( NULL );
		}

		return TRUE;
	}

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

		return TRUE;
	}

	function addLog( $log_action ) {
		return TTLog::addEntry( $this->getId(), $log_action, TTi18n::getText('Employee Wage'), NULL, $this->getTable() );
	}
}
?>
