TimeTrex/classes/modules/users/UserDeductionFactory.class.php

2460 lines
108 KiB
PHP
Raw Permalink Normal View History

2022-12-13 07:10:06 +01:00
<?php
/*********************************************************************************
*
* TimeTrex is a Workforce Management program developed by
* TimeTrex Software Inc. Copyright (C) 2003 - 2021 TimeTrex Software Inc.
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU Affero General Public License version 3 as published by
* the Free Software Foundation with the addition of the following permission
* added to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED
* WORK IN WHICH THE COPYRIGHT IS OWNED BY TIMETREX, TIMETREX DISCLAIMS THE
* WARRANTY OF NON INFRINGEMENT OF THIRD PARTY RIGHTS.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
* details.
*
*
* You should have received a copy of the GNU Affero General Public License along
* with this program; if not, see http://www.gnu.org/licenses or write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301 USA.
*
*
* You can contact TimeTrex headquarters at Unit 22 - 2475 Dobbin Rd. Suite
* #292 West Kelowna, BC V4T 2E9, Canada or at email address info@timetrex.com.
*
*
* The interactive user interfaces in modified source and object code versions
* of this program must display Appropriate Legal Notices, as required under
* Section 5 of the GNU Affero General Public License version 3.
*
*
* In accordance with Section 7(b) of the GNU Affero General Public License
* version 3, these Appropriate Legal Notices must retain the display of the
* "Powered by TimeTrex" logo. If the display of the logo is not reasonably
* feasible for technical reasons, the Appropriate Legal Notices must display
* the words "Powered by TimeTrex".
*
********************************************************************************/
/**
* @package Modules\Users
*/
class UserDeductionFactory extends Factory {
protected $table = 'user_deduction';
protected $pk_sequence_name = 'user_deduction_id_seq'; //PK Sequence name
var $user_obj = null;
var $company_deduction_obj = null;
var $pay_stub_entry_account_link_obj = null;
/**
* @param $name
* @param null $parent
* @return array|null
*/
function _getFactoryOptions( $name, $parent = null ) {
$retval = null;
switch ( $name ) {
case 'columns':
$retval = [
'-1010-status' => TTi18n::gettext( 'Status' ),
'-1020-type' => TTi18n::gettext( 'Type' ),
'-1030-name' => TTi18n::gettext( 'Tax / Deduction' ),
'-1040-calculation' => TTi18n::gettext( 'Calculation' ),
'-1110-first_name' => TTi18n::gettext( 'First Name' ),
'-1120-last_name' => TTi18n::gettext( 'Last Name' ),
'-2000-created_by' => TTi18n::gettext( 'Created By' ),
'-2010-created_date' => TTi18n::gettext( 'Created Date' ),
'-2020-updated_by' => TTi18n::gettext( 'Updated By' ),
'-2030-updated_date' => TTi18n::gettext( 'Updated Date' ),
];
break;
case 'list_columns':
$retval = Misc::arrayIntersectByKey( $this->getOptions( 'default_display_columns' ), Misc::trimSortPrefix( $this->getOptions( 'columns' ) ) );
break;
case 'default_display_columns': //Columns that are displayed by default.
$retval = [
'status',
'type',
'name',
'calculation',
];
break;
}
return $retval;
}
/**
* @param $data
* @return array
*/
function _getVariableToFunctionMap( $data ) {
$variable_function_map = [
'id' => 'ID',
'user_id' => 'User',
'company_deduction_id' => 'CompanyDeduction',
//CompanyDeduction
'name' => false, //CompanyDeduction Name
'status_id' => false,
'status' => false,
'type_id' => false,
'type' => false,
'calculation_id' => false,
'calculation' => false,
'first_name' => false,
'last_name' => false,
'middle_name' => false,
'user_status_id' => false,
'user_status' => false,
'full_name' => false,
'employee_number'=> false,
'length_of_service_date' => 'LengthOfServiceDate',
'start_date' => 'StartDate',
'end_date' => 'EndDate',
'user_value1' => 'UserValue1',
'user_value2' => 'UserValue2',
'user_value3' => 'UserValue3',
'user_value4' => 'UserValue4',
'user_value5' => 'UserValue5',
'user_value6' => 'UserValue6',
'user_value7' => 'UserValue7',
'user_value8' => 'UserValue8',
'user_value9' => 'UserValue9',
'user_value10' => 'UserValue10',
'deleted' => 'Deleted',
];
return $variable_function_map;
}
/**
* @return bool
*/
function getUserObject() {
return $this->getGenericObject( 'UserListFactory', $this->getUser(), 'user_obj' );
}
/**
* @return bool
*/
function getCompanyDeductionObject() {
return $this->getGenericObject( 'CompanyDeductionListFactory', $this->getCompanyDeduction(), 'company_deduction_obj' );
}
/**
* Do not replace this with getGenericObject() as it uses the CompanyID not the ID itself.
* @return bool|null
*/
function getPayStubEntryAccountLinkObject() {
if ( is_object( $this->pay_stub_entry_account_link_obj ) ) {
return $this->pay_stub_entry_account_link_obj;
} else {
$pseallf = TTnew( 'PayStubEntryAccountLinkListFactory' ); /** @var PayStubEntryAccountLinkListFactory $pseallf */
$pseallf->getByCompanyID( $this->getUserObject()->getCompany() );
if ( $pseallf->getRecordCount() > 0 ) {
$this->pay_stub_entry_account_link_obj = $pseallf->getCurrent();
return $this->pay_stub_entry_account_link_obj;
}
return false;
}
}
/**
* @return bool|mixed
*/
function getUser() {
return $this->getGenericDataValue( 'user_id' );
}
/**
* @param string $value UUID
* @return bool
*/
function setUser( $value ) {
$value = TTUUID::castUUID( $value );
return $this->setGenericDataValue( 'user_id', $value );
}
/**
* @param string $deduction_id UUID
* @return bool
*/
function isUniqueCompanyDeduction( $deduction_id ) {
$ph = [
'user_id' => TTUUID::castUUID( $this->getUser() ),
'deduction_id' => TTUUID::castUUID( $deduction_id ),
];
$query = 'select id from ' . $this->getTable() . ' where user_id = ? AND company_deduction_id = ? AND deleted = 0';
$id = $this->db->GetOne( $query, $ph );
Debug::Arr( $id, 'Unique Company Deduction: ' . $deduction_id, __FILE__, __LINE__, __METHOD__, 10 );
if ( $id === false ) {
return true;
} else {
if ( $id == $this->getId() ) {
return true;
}
}
return false;
}
/**
* @return bool|mixed
*/
function getCompanyDeduction() {
return $this->getGenericDataValue( 'company_deduction_id' );
}
/**
* @param string $value UUID
* @return bool
*/
function setCompanyDeduction( $value ) {
$value = TTUUID::castUUID( $value );
Debug::Text( 'ID: ' . $value, __FILE__, __LINE__, __METHOD__, 10 );
return $this->setGenericDataValue( 'company_deduction_id', $value );
}
/**
* @param bool $raw
* @return bool|int|mixed
*/
function getLengthOfServiceDate( $raw = false ) {
$retval = false;
$value = $this->getGenericDataValue( 'length_of_service_date' );
if ( $value !== false ) {
if ( $raw === true ) {
$retval = $value;
} else {
$retval = TTDate::strtotime( $value );
}
}
if ( $retval == '' && $this->getColumn( 'hire_date' ) != '' ) {
if ( $raw === true ) {
return $this->getColumn( 'hire_date' );
} else {
return TTDate::strtotime( $this->getColumn( 'hire_date' ) );
}
} else {
return $retval;
}
}
/**
* @param int $value EPOCH
* @return bool
*/
function setLengthOfServiceDate( $value ) {
if ( $value != '' ) {
$value = TTDate::getBeginDayEpoch( trim( $value ) );
}
Debug::Arr( $value, 'Length of Service Date: ' . TTDate::getDate( 'DATE+TIME', $value ), __FILE__, __LINE__, __METHOD__, 10 );
return $this->setGenericDataValue( 'length_of_service_date', $value );
}
/**
* @param bool $raw
* @return bool|int|mixed
*/
function getStartDate( $raw = false ) {
$value = $this->getGenericDataValue( 'start_date' );
$retval = false;
if ( $value !== false ) {
if ( $raw === true ) {
$retval = $value;
} else {
$retval = TTDate::strtotime( $value );
}
}
if ( $retval == '' && $this->getColumn( 'company_deduction_start_date' ) != '' ) {
if ( $raw === true ) {
return $this->getColumn( 'company_deduction_start_date' );
} else {
return TTDate::strtotime( $this->getColumn( 'company_deduction_start_date' ) );
}
} else {
return $retval;
}
}
/**
* @param int $value EPOCH
* @return bool
*/
function setStartDate( $value ) {
if ( $value != '' ) {
$value = TTDate::getBeginDayEpoch( trim( $value ) );
}
Debug::Arr( $value, 'Start Date: ' . TTDate::getDate( 'DATE+TIME', $value ), __FILE__, __LINE__, __METHOD__, 10 );
return $this->setGenericDataValue( 'start_date', $value );
}
/**
* @param bool $raw
* @return bool|int|mixed
*/
function getEndDate( $raw = false ) {
$retval = false;
$value = $this->getGenericDataValue( 'end_date' );
if ( $value !== false ) {
if ( $raw === true ) {
$retval = $value;
} else {
$retval = TTDate::strtotime( $value );
}
}
if ( $retval == '' && $this->getColumn( 'company_deduction_end_date' ) != '' ) {
if ( $raw === true ) {
return $this->getColumn( 'company_deduction_end_date' );
} else {
return TTDate::strtotime( $this->getColumn( 'company_deduction_end_date' ) );
}
} else {
return $retval;
}
}
/**
* @param int $value EPOCH
* @return bool
*/
function setEndDate( $value ) {
if ( $value != '' ) {
$value = TTDate::getBeginDayEpoch( trim( $value ) );
}
Debug::Arr( $value, 'End Date: ' . TTDate::getDate( 'DATE+TIME', $value ), __FILE__, __LINE__, __METHOD__, 10 );
return $this->setGenericDataValue( 'end_date', $value );
}
/**
* @return bool
*/
function getUserValue1() {
return $this->getGenericDataValue( 'user_value1' );
}
/**
* @param $value
* @return bool
*/
function setUserValue1( $value ) {
$value = trim( $value );
return $this->setGenericDataValue( 'user_value1', $value );
}
/**
* @return bool
*/
function getUserValue2() {
return $this->getGenericDataValue( 'user_value2' );
}
/**
* @param $value
* @return bool
*/
function setUserValue2( $value ) {
$value = trim( $value );
return $this->setGenericDataValue( 'user_value2', $value );
}
/**
* @return bool
*/
function getUserValue3() {
return $this->getGenericDataValue( 'user_value3' );
}
/**
* @param $value
* @return bool
*/
function setUserValue3( $value ) {
$value = trim( $value );
return $this->setGenericDataValue( 'user_value3', $value );
}
/**
* @return bool
*/
function getUserValue4() {
return $this->getGenericDataValue( 'user_value4' );
}
/**
* @param $value
* @return bool
*/
function setUserValue4( $value ) {
$value = trim( $value );
return $this->setGenericDataValue( 'user_value4', $value );
}
/**
* @return bool
*/
function getUserValue5() {
return $this->getGenericDataValue( 'user_value5' );
}
/**
* @param $value
* @return bool
*/
function setUserValue5( $value ) {
$value = trim( $value );
return $this->setGenericDataValue( 'user_value5', $value );
}
/**
* @return bool
*/
function getUserValue6() {
return $this->getGenericDataValue( 'user_value6' );
}
/**
* @param $value
* @return bool
*/
function setUserValue6( $value ) {
$value = trim( $value );
return $this->setGenericDataValue( 'user_value6', $value );
}
/**
* @return bool
*/
function getUserValue7() {
return $this->getGenericDataValue( 'user_value7' );
}
/**
* @param $value
* @return bool
*/
function setUserValue7( $value ) {
$value = trim( $value );
return $this->setGenericDataValue( 'user_value7', $value );
}
/**
* @return bool
*/
function getUserValue8() {
return $this->getGenericDataValue( 'user_value8' );
}
/**
* @param $value
* @return bool
*/
function setUserValue8( $value ) {
$value = trim( $value );
return $this->setGenericDataValue( 'user_value8', $value );
}
/**
* @return bool
*/
function getUserValue9() {
return $this->getGenericDataValue( 'user_value9' );
}
/**
* @param $value
* @return bool
*/
function setUserValue9( $value ) {
$value = trim( $value );
return $this->setGenericDataValue( 'user_value9', $value );
}
/**
* @return bool
*/
function getUserValue10() {
return $this->getGenericDataValue( 'user_value10' );
}
/**
* @param $value
* @return bool
*/
function setUserValue10( $value ) {
$value = trim( $value );
return $this->setGenericDataValue( 'user_value10', $value );
}
/**
* Primarily used to display marital status/allowances/claim amounts on pay stubs.
* @param bool $transaction_date
* @return bool|string
* @noinspection PhpUnusedLocalVariableInspection
*/
function getDescription( $transaction_date = false ) {
$retval = false;
$calculation_id = $this->getColumn( 'calculation_id' );
if ( $calculation_id == '' ) {
//Calculates the deduction.
$cd_obj = $this->getCompanyDeductionObject();
$calculation_id = $cd_obj->getCalculation();
}
if ( !in_array( $calculation_id, [ 100, 200 ] ) ) { //Optimization.
return false;
}
if ( !isset( $cd_obj ) ) {
$cd_obj = $this->getCompanyDeductionObject();
}
$user_value1 = ( ( $this->getUserValue1() == '' ) ? $cd_obj->getUserValue1() : $this->getUserValue1() );
$user_value2 = ( ( $this->getUserValue2() == '' ) ? $cd_obj->getUserValue2() : $this->getUserValue2() );
$user_value3 = ( ( $this->getUserValue3() == '' ) ? $cd_obj->getUserValue3() : $this->getUserValue3() );
$user_value4 = ( ( $this->getUserValue4() == '' ) ? $cd_obj->getUserValue4() : $this->getUserValue4() );
$user_value5 = ( ( $this->getUserValue5() == '' ) ? $cd_obj->getUserValue5() : $this->getUserValue5() );
$user_value6 = ( ( $this->getUserValue6() == '' ) ? $cd_obj->getUserValue6() : $this->getUserValue6() );
$user_value7 = ( ( $this->getUserValue7() == '' ) ? $cd_obj->getUserValue7() : $this->getUserValue7() );
$user_value9 = ( ( $this->getUserValue9() == '' ) ? $cd_obj->getUserValue9() : $this->getUserValue9() );
if ( $transaction_date == '' ) {
$transaction_date = time();
}
if ( $cd_obj->getCountry() == 'CA' ) {
require_once( Environment::getBasePath() . DIRECTORY_SEPARATOR . 'classes' . DIRECTORY_SEPARATOR . 'payroll_deduction' . DIRECTORY_SEPARATOR . 'PayrollDeduction.class.php' );
$pd_obj = new PayrollDeduction( $cd_obj->getCountry(), $cd_obj->getProvince() );
$pd_obj->setDate( $transaction_date );
}
$calculation_type_column_meta_data = $cd_obj->getOptions( 'calculation_type_column_meta_data', [ 'calculation_id' => $cd_obj->getCalculation(), 'country' => $cd_obj->getCountry(), 'province' => $cd_obj->getProvince() ] );
//Debug::Text('UserDeduction ID: '. $this->getID() .' Calculation ID: '. $cd_obj->getCalculation(), __FILE__, __LINE__, __METHOD__, 10);
switch ( $cd_obj->getCalculation() ) {
case 100: //Federal
$country_label = strtoupper( $cd_obj->getCountry() );
if ( $cd_obj->getCountry() == 'CA' ) {
//Filter Claim Amount through PayrollDeduction class so it can be automatically adjusted if necessary.
$pd_obj->setFederalTotalClaimAmount( $user_value1 );
$retval = $country_label . ' - ' . $calculation_type_column_meta_data['user_value1']['name'] . ': $' . Misc::MoneyFormat( $pd_obj->getFederalTotalClaimAmount() );
} else if ( $cd_obj->getCountry() == 'US' ) {
$retval = $country_label . ' - ' . $calculation_type_column_meta_data['user_value1']['name'] . ': ' . Option::getByKey( $user_value1, $calculation_type_column_meta_data['user_value1']['multi_select_items'] );
if ( $user_value9 == 2020 ) {
$retval .= ' ' . $calculation_type_column_meta_data['user_value4']['name'] . ': ' . $user_value4;
} else {
$retval .= ' ' . $calculation_type_column_meta_data['user_value2']['name'] . ': ' . (int)$user_value2;
}
if ( (int)$this->getUserValue10() >= 1 ) {
$retval .= ' ' . TTI18n::getText( 'Exempt' );
}
}
break;
case 200:
$province_label = strtoupper( $cd_obj->getProvince() );
if ( $cd_obj->getCountry() == 'CA' ) {
//Filter Claim Amount through PayrollDeduction class so it can be automatically adjusted if necessary.
$pd_obj->setProvincialTotalClaimAmount( $user_value1 );
$retval = $province_label . ' - ' . TTI18n::getText( 'Claim Amount' ) . ': $' . Misc::MoneyFormat( $pd_obj->getProvincialTotalClaimAmount() );
} else if ( $cd_obj->getCountry() == 'US' ) {
$retval = $province_label;
if ( is_array( $calculation_type_column_meta_data ) ) {
$retval .= ' - ';
foreach ( $calculation_type_column_meta_data as $key => $meta_data ) {
$retval .= ' ' . $calculation_type_column_meta_data[$key]['name'] . ': ';
if ( $meta_data['type_id'] == 2100 ) { //Drop-down box.
$retval .= Option::getByKey( ${$key}, $meta_data['multi_select_items'] );
} else {
$retval .= ${$key};
if ( $meta_data['dynamic_field_id'] == 'df_0' ) { //Percent field.
$retval .= '%';
}
}
}
switch ( strtolower( $cd_obj->getProvince() ) ) {
case 'or':
//As of 01-Jan-2017, Oregon law ( ORS 652.610 ) requires 'the name and business registry number or business identification number of the employer'; displayed on pay stubs.
if ( is_object( $cd_obj->getPayrollRemittanceAgencyObject() ) && $cd_obj->getPayrollRemittanceAgencyObject()->getPrimaryIdentification() != '' ) {
$retval .= ' [#' . $cd_obj->getPayrollRemittanceAgencyObject()->getPrimaryIdentification() . ']';
}
break;
}
}
if ( (int)$this->getUserValue10() >= 1 ) {
if ( !is_array( $calculation_type_column_meta_data ) ) {
$retval .= ' -';
}
$retval .= ' ' . TTI18n::getText( 'Exempt' );
}
}
break;
}
return $retval;
}
/**
* Since some Tax/Deduction calculation types (ie: Canada Federal/Provincial) take into account specific amounts calculated by other Tax/Deduction records (ie: Canada CPP/EI),
* this provides a way to force additional required PSA's that affect just the dependancy tree.
* @return array
* @throws DBError
*/
function getAdditionalRequiredPayStubAccounts() {
$cd_obj = $this->getCompanyDeductionObject();
$retarr = [];
//For Canada Federal/Provincial Income Tax calculations, they require that Employee CPP/EI is calculated first, as they are taken into account when calculating the taxes,
// but we can't include the CPP/EI PSA's in the Tax/Deduction record as that would include the dollar values.
// So we need way to inject additional required PSA's into just the dependancy tree, to ensure consistent calculation order.
if ( in_array( $cd_obj->getCalculation(), [ 100, 200 ] ) && $this->getCompanyDeductionObject()->getCountry() == 'CA' ) {
$cdlf = TTnew( 'CompanyDeductionListFactory' ); /** @var CompanyDeductionListFactory $cdlf */
$cdlf->getByCompanyIdAndLegalEntityIdAndCalculationIdAndStatusId( $cd_obj->getCompany(), $cd_obj->getLegalEntity(), [ 90, 91 ], 10 ); //90=CPP,91=EI, 10=Enabled
if ( $cdlf->getRecordCount() > 0 ) {
foreach ( $cdlf as $tmp_cd_obj ) {
$retarr[] = $tmp_cd_obj->getPayStubEntryAccount();
Debug::Text( ' Found Additional Required Include Pay Stub Account: ' . $tmp_cd_obj->getPayStubEntryAccount() . ' Company Deduction: ' . $cd_obj->getName() . ' (' . $cd_obj->getId() . ')', __FILE__, __LINE__, __METHOD__, 10 );
}
}
}
return $retarr;
}
/**
* @param $user_obj
* @param PayStubFactory $pay_stub_obj
* @param PayPeriodFactory $pay_period_obj
* @param int $formula_type_id
* @param int $payroll_run_id
* @return int|string
* @throws DBError
*/
function getDeductionAmount( $user_obj, $pay_stub_obj, $pay_period_obj, $formula_type_id = 10, $payroll_run_id = 1 ) {
if ( !is_object( $user_obj ) ) {
Debug::Text( 'Missing User Object: ', __FILE__, __LINE__, __METHOD__, 10 );
return false;
}
if ( !is_object( $pay_stub_obj ) ) {
Debug::Text( 'Missing Pay Stub Object: ', __FILE__, __LINE__, __METHOD__, 10 );
return false;
}
if ( !is_object( $pay_period_obj ) ) {
Debug::Text( 'Missing Pay Period Object: ', __FILE__, __LINE__, __METHOD__, 10 );
return false;
}
$this->user_obj = $user_obj;
/** @var UserFactory $user_obj */
$user_id = $user_obj->getId();
//Calculates the deduction.
$cd_obj = $this->getCompanyDeductionObject();
/** @var CompanyDeductionFactory $cd_obj */
$pay_period_start_week_day = $pay_period_obj->getPayPeriodScheduleObject()->getStartWeekDay();
$annual_pay_periods = $pay_period_obj->getPayPeriodScheduleObject()->getAnnualPayPeriods();
if ( $annual_pay_periods <= 0 ) {
$annual_pay_periods = 1;
}
//Need to use pay stub dates rather than pay period dates for this, because if you are in the first pay period of 2016 (Transaction: 01-Jan) and
//you need to run a out-of-cycle bonus to be paid by 24-Dec, it will think its the 1st pay stub of the year when its really the last. This causes taxes to be incorrect.
$current_pay_period = $pay_period_obj->getPayPeriodScheduleObject()->getCurrentPayPeriodNumber( $pay_stub_obj->getTransactionDate(), $pay_stub_obj->getEndDate() );
if ( $current_pay_period <= 0 ) {
$current_pay_period = 1;
}
$hire_adjusted_annual_pay_periods = $pay_period_obj->getPayPeriodScheduleObject()->getHireAdjustedAnnualPayPeriods( $pay_stub_obj->getTransactionDate(), $this->getUserObject()->getHireDate() );
if ( $hire_adjusted_annual_pay_periods <= 0 ) {
$hire_adjusted_annual_pay_periods = 1;
}
$hire_adjusted_current_pay_period = $pay_period_obj->getPayPeriodScheduleObject()->getHireAdjustedCurrentPayPeriodNumber( $pay_stub_obj->getTransactionDate(), $pay_stub_obj->getEndDate(), $this->getUserObject()->getHireDate() );
if ( $hire_adjusted_current_pay_period <= 0 ) {
$hire_adjusted_current_pay_period = 1;
}
if ( !is_object( $cd_obj ) ) {
return false;
}
if ( in_array( $cd_obj->getCalculation(), [ 100, 200, 300 ] ) && (int)$cd_obj->getCompanyValue1() > 0 ) {
Debug::Text( 'Overriding Formula Type to: ' . (int)$cd_obj->getCompanyValue1() . ' From: ' . $formula_type_id, __FILE__, __LINE__, __METHOD__, 10 );
$formula_type_id = (int)$cd_obj->getCompanyValue1();
}
require_once( Environment::getBasePath() . DIRECTORY_SEPARATOR . 'classes' . DIRECTORY_SEPARATOR . 'payroll_deduction' . DIRECTORY_SEPARATOR . 'PayrollDeduction.class.php' );
$retval = 0;
Debug::Text( 'Company Deduction: ID: ' . $cd_obj->getID() . ' Name: ' . $cd_obj->getName() . ' Calculation ID: ' . $cd_obj->getCalculation(), __FILE__, __LINE__, __METHOD__, 10 );
switch ( $cd_obj->getCalculation() ) {
case 10: //Basic Percent
$percent = ( ( $this->getUserValue1() == '' ) ? $cd_obj->getUserValue1() : $this->getUserValue1() );
$percent = $this->Validator->stripNonFloat( $percent );
$amount = $cd_obj->getCalculationPayStubAmount( $pay_stub_obj );
$retval = bcmul( $amount, bcdiv( $percent, 100 ) );
break;
case 15: //Advanced Percent
$percent = ( ( $this->getUserValue1() == '' ) ? $cd_obj->getUserValue1() : $this->getUserValue1() );
$percent = $this->Validator->stripNonFloat( $percent );
$wage_base = ( ( $this->getUserValue2() == '' ) ? $cd_obj->getUserValue2() : $this->getUserValue2() );
$wage_base = $this->Validator->stripNonFloat( $wage_base );
$exempt_amount = ( ( $this->getUserValue3() == '' ) ? $cd_obj->getUserValue3() : $this->getUserValue3() );
$exempt_amount = $this->Validator->stripNonFloat( $exempt_amount );
//Annual Wage Base is the maximum earnings that an employee can earn before they are no longer eligible for this deduction
//Annual Deduction Amount
Debug::Text( 'Percent: ' . $percent . ' Wage Base: ' . $wage_base . ' Exempt Amount: ' . $exempt_amount, __FILE__, __LINE__, __METHOD__, 10 );
if ( $percent != '' && $percent != 0 ) {
if ( $exempt_amount > 0 ) {
$amount = bcsub( $cd_obj->getCalculationPayStubAmount( $pay_stub_obj ), bcdiv( $exempt_amount, $annual_pay_periods ) );
Debug::Text( 'Amount After Exemption: ' . $amount, __FILE__, __LINE__, __METHOD__, 10 );
} else {
$amount = $cd_obj->getCalculationPayStubAmount( $pay_stub_obj );
Debug::Text( 'Amount: ' . $amount, __FILE__, __LINE__, __METHOD__, 10 );
}
if ( $wage_base > 0 ) {
//*NOTE: If the first pay stub in TimeTrex is near the end of the year, and the employee has already exceeded the wage base amount
//the payroll admin needs to make sure they add a YTD Adjustment for each Include PS Accounts that this calculation is based on,
//NOT the total amount they have paid for the resulting calculation, as that has no effect whatsoever.
// The above is no longer the case since we switched to use opening balance pay stubs instead.
//getCalculationYTDAmount is the previous pay stub YTD amount, but it includes any YTD Adjustments in the current pay stub too.
$ytd_amount = $cd_obj->getCalculationYTDAmount( $pay_stub_obj );
Debug::Text( 'Wage Base is set: ' . $wage_base . ' Amount: ' . $amount . ' Current YTD: ' . $ytd_amount, __FILE__, __LINE__, __METHOD__, 10 );
//Possible calcations:
//
//Wage Base: 3000
//Amount: 500 YTD: 0 = 500
//Amount: 500 YTD: 2900 = 100
//Amount: 500 YTD: 3100 = 0
//Amount: 3500 YTD: 0 = 3000
//AMount: 3500 YTD: 2900 = 100
//Amount: 3500 YTD: 3100 = 0
//Check to see if YTD is less than wage base.
$remaining_wage_base = bcsub( $wage_base, $ytd_amount );
Debug::Text( 'Remaining Wage Base to be calculated: ' . $remaining_wage_base, __FILE__, __LINE__, __METHOD__, 10 );
if ( $remaining_wage_base > 0 ) {
if ( $amount > $remaining_wage_base ) {
$amount = $remaining_wage_base;
}
} else {
$amount = 0; //Exceeded wage base, nothing to calculate.
}
unset( $remaining_wage_base );
} else {
Debug::Text( 'Wage Base is NOT set: ' . $wage_base, __FILE__, __LINE__, __METHOD__, 10 );
}
$retval = bcmul( $amount, bcdiv( $percent, 100 ) );
} else {
$retval = 0;
}
if ( $percent >= 0 && $retval < 0 ) {
$retval = 0;
}
unset( $amount, $ytd_amount, $percent, $wage_base );
break;
case 16: //Advanced Percent (w/Target)
$percent = ( ( $this->getUserValue1() == '' ) ? $cd_obj->getUserValue1() : $this->getUserValue1() );
$percent = $this->Validator->stripNonFloat( $percent );
$target_amount = ( ( $this->getUserValue2() == '' ) ? $cd_obj->getUserValue2() : $this->getUserValue2() );
$target_amount = $this->Validator->stripNonFloat( $target_amount );
$target_ytd_amount = ( ( $this->getUserValue3() == '' ) ? $cd_obj->getUserValue3() : $this->getUserValue3() );
$target_ytd_amount = $this->Validator->stripNonFloat( $target_ytd_amount );
Debug::Text( 'Percent: ' . $percent . ' Target Amount: ' . $target_amount . ' YTD Amount: ' . $target_ytd_amount, __FILE__, __LINE__, __METHOD__, 10 );
$retval = 0;
if ( $percent != '' && $percent != 0 ) {
$amount = $cd_obj->getCalculationPayStubAmount( $pay_stub_obj );
//Make sure YTD amount includes any other amounts on the current pay stub, incase they have two calculations or PS amendments that affect the same account.
$ytd_amount = bcadd( $cd_obj->getPayStubEntryAmountSum( $pay_stub_obj, [ $cd_obj->getPayStubEntryAccount() ], 'current', 'amount' ), $cd_obj->getPayStubEntryAmountSum( $pay_stub_obj, [ $cd_obj->getPayStubEntryAccount() ], 'previous+ytd_adjustment', 'ytd_amount' ) );
Debug::Text( 'Amount: ' . $amount . ' YTD Amount: ' . $ytd_amount, __FILE__, __LINE__, __METHOD__, 10 );
$percent_amount = bcmul( $amount, bcdiv( $percent, 100 ) );
if ( $percent_amount != 0 ) {
$filtered_amount = Misc::getAmountToLimit( $percent_amount, $target_amount );
Debug::Text( ' Filtered Amount: ' . $filtered_amount . ' YTD Amount: ' . $ytd_amount, __FILE__, __LINE__, __METHOD__, 10 );
$filtered_ytd_amount = Misc::getAmountDifferenceToLimit( $ytd_amount, $target_ytd_amount );
Debug::Text( ' Filtered YTD Amount: ' . $filtered_ytd_amount . ' YTD Amount: ' . $ytd_amount, __FILE__, __LINE__, __METHOD__, 10 );
//Choose whichever filtered amount is lower.
if ( $filtered_ytd_amount < $filtered_amount ) {
$retval = $filtered_ytd_amount;
} else {
$retval = $filtered_amount;
}
}
}
if ( $percent >= 0 && $retval < 0 ) {
$retval = 0;
}
unset( $amount, $ytd_amount, $percent, $percent_amount, $filtered_amount, $filtered_ytd_amount, $target_amount, $target_ytd_amount );
break;
case 17: //Advanced Percent (Range Bracket)
$percent = ( ( $this->getUserValue1() == '' ) ? $cd_obj->getUserValue1() : $this->getUserValue1() );
$percent = $this->Validator->stripNonFloat( $percent );
$min_wage = ( ( $this->getUserValue2() == '' ) ? $cd_obj->getUserValue2() : $this->getUserValue2() );
$min_wage = $this->Validator->stripNonFloat( $min_wage );
$max_wage = ( ( $this->getUserValue3() == '' ) ? $cd_obj->getUserValue3() : $this->getUserValue3() );
$max_wage = $this->Validator->stripNonFloat( $max_wage );
$annual_deduction_amount = ( ( $this->getUserValue4() == '' ) ? $cd_obj->getUserValue4() : $this->getUserValue4() );
$annual_deduction_amount = $this->Validator->stripNonFloat( $annual_deduction_amount );
$annual_fixed_amount = ( ( $this->getUserValue5() == '' ) ? $cd_obj->getUserValue5() : $this->getUserValue5() );
$annual_fixed_amount = $this->Validator->stripNonFloat( $annual_fixed_amount );
$min_wage = bcdiv( $min_wage, $annual_pay_periods );
$max_wage = bcdiv( $max_wage, $annual_pay_periods );
$annual_deduction_amount = bcdiv( $annual_deduction_amount, $annual_pay_periods );
$annual_fixed_amount = bcdiv( $annual_fixed_amount, $annual_pay_periods );
Debug::Text( 'Percent: ' . $percent . ' Min Wage: ' . $min_wage . ' Max Wage: ' . $max_wage . ' Annual Deduction: ' . $annual_deduction_amount, __FILE__, __LINE__, __METHOD__, 10 );
if ( $percent != '' && $percent != 0 ) {
$amount = bcsub( $cd_obj->getCalculationPayStubAmount( $pay_stub_obj ), $annual_deduction_amount );
Debug::Text( 'Amount: ' . $amount, __FILE__, __LINE__, __METHOD__, 10 );
if ( $amount >= $min_wage && $amount <= $max_wage ) {
$retval = bcadd( bcmul( $amount, bcdiv( $percent, 100 ) ), $annual_fixed_amount );
}
} else {
$retval = 0;
}
if ( $percent >= 0 && $retval < 0 ) {
$retval = 0;
}
unset( $amount, $percent, $min_wage, $max_wage, $annual_deduction_amount, $annual_fixed_amount );
break;
case 18: //Advanced Percent (Tax Bracket)
$percent = ( ( $this->getUserValue1() == '' ) ? $cd_obj->getUserValue1() : $this->getUserValue1() );
$percent = $this->Validator->stripNonFloat( $percent );
$wage_base = ( ( $this->getUserValue2() == '' ) ? $cd_obj->getUserValue2() : $this->getUserValue2() );
$wage_base = $this->Validator->stripNonFloat( $wage_base );
$exempt_amount = ( ( $this->getUserValue3() == '' ) ? $cd_obj->getUserValue3() : $this->getUserValue3() );
$exempt_amount = $this->Validator->stripNonFloat( $exempt_amount );
$annual_deduction_amount = ( ( $this->getUserValue4() == '' ) ? $cd_obj->getUserValue4() : $this->getUserValue4() );
$annual_deduction_amount = $this->Validator->stripNonFloat( $annual_deduction_amount );
Debug::Text( 'Percent: ' . $percent . ' Wage Base: ' . $wage_base . ' Exempt Amount: ' . $exempt_amount, __FILE__, __LINE__, __METHOD__, 10 );
if ( $percent != '' && $percent != 0 ) {
if ( $exempt_amount > 0 ) {
$pp_exempt_amount = bcdiv( $exempt_amount, $annual_pay_periods );
} else {
$pp_exempt_amount = 0;
}
//Debug::Text('PP Exempt Amount: '. $pp_exempt_amount, __FILE__, __LINE__, __METHOD__, 10);
if ( $wage_base > 0 ) {
$pp_wage_base_amount = bcdiv( $wage_base, $annual_pay_periods );
} else {
$pp_wage_base_amount = 0;
}
if ( $annual_deduction_amount > 0 ) {
$pp_annual_deduction_amount = bcdiv( $annual_deduction_amount, $annual_pay_periods );
} else {
$pp_annual_deduction_amount = 0;
}
//Debug::Text('PP Wage Base Base Amount: '. $pp_wage_base_amount, __FILE__, __LINE__, __METHOD__, 10);
$amount = bcsub( $cd_obj->getCalculationPayStubAmount( $pay_stub_obj ), $pp_annual_deduction_amount );
//Debug::Text('Calculation Pay Stub Amount: '. $cd_obj->getCalculationPayStubAmount( $pay_stub_obj ), __FILE__, __LINE__, __METHOD__, 10);
if ( $pp_wage_base_amount > 0
&& $amount > $pp_wage_base_amount ) {
//Debug::Text('Exceeds Wage Base...'. $amount, __FILE__, __LINE__, __METHOD__, 10);
$amount = bcsub( $pp_wage_base_amount, $pp_exempt_amount );
} else {
//Debug::Text('Under Wage Base...'. $amount, __FILE__, __LINE__, __METHOD__, 10);
$amount = bcsub( $amount, $pp_exempt_amount );
}
Debug::Text( 'Amount: ' . $amount, __FILE__, __LINE__, __METHOD__, 10 );
$retval = bcmul( $amount, bcdiv( $percent, 100 ) );
} else {
$retval = 0;
}
if ( $percent >= 0 && $retval < 0 ) {
$retval = 0;
}
unset( $amount, $percent, $wage_base, $pp_wage_base_amount, $pp_exempt_amount, $annual_deduction_amount, $pp_annual_deduction_amount );
break;
case 19: //Advanced Percent (Tax Bracket Alternate)
/*
This is designed to be used for single line item tax calculations, in that the formula looks like this,
where only ONE bracket would be applied to the employee, NOT all:
Wage between 0 - 10, 000 calculate 10%
Wage between 10, 001 - 20, 000 calculate 15% + $1000 (10% of 10, 000 as per above)
Wage between 20, 001 - 30, 000 calculate 20% + $2500 (10% of 10, 000 as first bracket, and 15% of 10, 000 as per 2nd bracket)
*/
$percent = ( ( $this->getUserValue1() == '' ) ? $cd_obj->getUserValue1() : $this->getUserValue1() );
$percent = $this->Validator->stripNonFloat( $percent );
$min_wage = ( ( $this->getUserValue2() == '' ) ? $cd_obj->getUserValue2() : $this->getUserValue2() );
$min_wage = $this->Validator->stripNonFloat( $min_wage );
$max_wage = ( ( $this->getUserValue3() == '' ) ? $cd_obj->getUserValue3() : $this->getUserValue3() );
$max_wage = $this->Validator->stripNonFloat( $max_wage );
$annual_deduction_amount = ( ( $this->getUserValue4() == '' ) ? $cd_obj->getUserValue4() : $this->getUserValue4() );
$annual_deduction_amount = $this->Validator->stripNonFloat( $annual_deduction_amount );
$annual_fixed_amount = ( ( $this->getUserValue5() == '' ) ? $cd_obj->getUserValue5() : $this->getUserValue5() );
$annual_fixed_amount = $this->Validator->stripNonFloat( $annual_fixed_amount );
$min_wage = bcdiv( $min_wage, $annual_pay_periods );
$max_wage = bcdiv( $max_wage, $annual_pay_periods );
$annual_deduction_amount = bcdiv( $annual_deduction_amount, $annual_pay_periods );
$annual_fixed_amount = bcdiv( $annual_fixed_amount, $annual_pay_periods );
Debug::Text( 'Percent: ' . $percent . ' Min Wage: ' . $min_wage . ' Max Wage: ' . $max_wage . ' Annual Deduction: ' . $annual_deduction_amount, __FILE__, __LINE__, __METHOD__, 10 );
if ( $percent != '' && $percent != 0 ) {
$amount = bcsub( $cd_obj->getCalculationPayStubAmount( $pay_stub_obj ), $annual_deduction_amount );
Debug::Text( 'Amount: ' . $amount, __FILE__, __LINE__, __METHOD__, 10 );
if ( $amount >= $min_wage && $amount <= $max_wage ) {
$retval = bcadd( bcmul( bcsub( $amount, $min_wage ), bcdiv( $percent, 100 ) ), $annual_fixed_amount );
}
} else {
$retval = 0;
}
if ( $percent >= 0 && $retval < 0 ) {
$retval = 0;
}
unset( $amount, $percent, $min_wage, $max_wage, $annual_deduction_amount, $annual_fixed_amount );
break;
case 20: //Fixed amount
$amount = ( ( $this->getUserValue1() == '' ) ? $cd_obj->getUserValue1() : $this->getUserValue1() );
$amount = $this->Validator->stripNonFloat( $amount );
$retval = $amount;
unset( $amount );
break;
case 30: //Fixed Amount (Range Bracket)
$fixed_amount = ( ( $this->getUserValue1() == '' ) ? $cd_obj->getUserValue1() : $this->getUserValue1() );
$fixed_amount = $this->Validator->stripNonFloat( $fixed_amount );
$min_wage = ( ( $this->getUserValue2() == '' ) ? $cd_obj->getUserValue2() : $this->getUserValue2() );
$min_wage = $this->Validator->stripNonFloat( $min_wage );
$max_wage = ( ( $this->getUserValue3() == '' ) ? $cd_obj->getUserValue3() : $this->getUserValue3() );
$max_wage = $this->Validator->stripNonFloat( $max_wage );
$annual_deduction_amount = ( ( $this->getUserValue4() == '' ) ? $cd_obj->getUserValue4() : $this->getUserValue4() );
$annual_deduction_amount = $this->Validator->stripNonFloat( $annual_deduction_amount );
$min_wage = bcdiv( $min_wage, $annual_pay_periods );
$max_wage = bcdiv( $max_wage, $annual_pay_periods );
$annual_deduction_amount = bcdiv( $annual_deduction_amount, $annual_pay_periods );
Debug::Text( 'Amount: ' . $fixed_amount . ' Min Wage: ' . $min_wage . ' Max Wage: ' . $max_wage . ' Annual Deduction: ' . $annual_deduction_amount, __FILE__, __LINE__, __METHOD__, 10 );
if ( $fixed_amount != '' && $fixed_amount != 0 ) {
$amount = bcsub( $cd_obj->getCalculationPayStubAmount( $pay_stub_obj ), $annual_deduction_amount );
Debug::Text( 'Amount: ' . $amount, __FILE__, __LINE__, __METHOD__, 10 );
if ( $amount >= $min_wage && $amount <= $max_wage ) {
$retval = $fixed_amount;
}
} else {
$retval = 0;
}
unset( $fixed_amount, $amount, $percent, $min_wage, $max_wage, $annual_deduction_amount );
break;
case 52: //Fixed Amount (w/Limit)
$fixed_amount = ( ( $this->getUserValue1() == '' ) ? $cd_obj->getUserValue1() : $this->getUserValue1() );
$fixed_amount = $this->Validator->stripNonFloat( $fixed_amount );
$target_amount = ( ( $this->getUserValue2() == '' ) ? $cd_obj->getUserValue2() : $this->getUserValue2() );
$target_amount = $this->Validator->stripNonFloat( $target_amount );
Debug::Text( 'Fixed Amount: ' . $fixed_amount . ' Target Amount: ' . $target_amount, __FILE__, __LINE__, __METHOD__, 10 );
$retval = 0;
if ( $fixed_amount != '' && $fixed_amount != 0 ) {
$ytd_amount = $cd_obj->getCalculationPayStubAmount( $pay_stub_obj );
$ytd_amount_remaining = Misc::getAmountDifferenceToLimit( $ytd_amount, $target_amount );
$retval = Misc::getAmountToLimit( $ytd_amount_remaining, $fixed_amount );
Debug::Text( ' Retval: ' . $retval . ' YTD Amount: ' . $ytd_amount . ' YTD Remaining Amount: ' . $ytd_amount_remaining, __FILE__, __LINE__, __METHOD__, 10 );
}
unset( $fixed_amount, $target_amount, $ytd_amount, $ytd_amount_remaining );
break;
case 69: // Custom Formulas
$user_value1 = ( ( $this->getUserValue1() == '' ) ? $cd_obj->getUserValue1() : $this->getUserValue1() );
$user_value2 = ( ( $this->getUserValue2() == '' ) ? $cd_obj->getUserValue2() : $this->getUserValue2() );
$user_value3 = ( ( $this->getUserValue3() == '' ) ? $cd_obj->getUserValue3() : $this->getUserValue3() );
$user_value4 = ( ( $this->getUserValue4() == '' ) ? $cd_obj->getUserValue4() : $this->getUserValue4() );
$user_value5 = ( ( $this->getUserValue5() == '' ) ? $cd_obj->getUserValue5() : $this->getUserValue5() );
$user_value6 = ( ( $this->getUserValue6() == '' ) ? $cd_obj->getUserValue6() : $this->getUserValue6() );
$user_value7 = ( ( $this->getUserValue7() == '' ) ? $cd_obj->getUserValue7() : $this->getUserValue7() );
$user_value8 = ( ( $this->getUserValue8() == '' ) ? $cd_obj->getUserValue8() : $this->getUserValue8() );
$user_value9 = ( ( $this->getUserValue9() == '' ) ? $cd_obj->getUserValue9() : $this->getUserValue9() );
$user_value10 = ( ( $this->getUserValue10() == '' ) ? $cd_obj->getUserValue10() : $this->getUserValue10() );
// evaluate math expressions as the company_value1 and user_value1-10 defined by user.
$company_value1 = $cd_obj->getCompanyValue1(); // Custom Formula
$variables = [];
$formula_variables = array_keys( (array)TTMath::parseColumnsFromFormula( $company_value1 ) );
Debug::Arr( $formula_variables, 'Formula Variables: ', __FILE__, __LINE__, __METHOD__, 10 );
if ( is_array( $formula_variables ) ) {
$udtlf = TTnew( 'UserDateTotalListFactory' ); /** @var UserDateTotalListFactory $udtlf */
if ( in_array( 'currency_conversion_rate', $formula_variables ) && is_object( $this->getUserObject() ) && is_object( $this->getUserObject()->getCurrencyObject() ) ) {
$currency_iso_code = $this->getUserObject()->getCurrencyObject()->getISOCode();
$currency_conversion_rate = $this->getUserObject()->getCurrencyObject()->getConversionRate();
Debug::Text( 'Currency Variables: Rate: ' . $currency_conversion_rate . ' ISO: ' . $currency_iso_code, __FILE__, __LINE__, __METHOD__, 10 );
}
//First pass to gather any necessary data based on variables
if ( in_array( 'employee_hourly_rate', $formula_variables ) || in_array( 'employee_annual_wage', $formula_variables ) || in_array( 'employee_wage_average_weekly_hours', $formula_variables ) ) {
$uwlf = TTnew( 'UserWageListFactory' ); /** @var UserWageListFactory $uwlf */
$uwlf->getWageByUserIdAndPayPeriodEndDate( $this->getUser(), $pay_period_obj->getEndDate() );
if ( $uwlf->getRecordCount() > 0 ) {
$uwf = $uwlf->getCurrent();
$employee_hourly_rate = $uwf->getHourlyRate();
$employee_annual_wage = $uwf->getAnnualWage();
$employee_wage_average_weekly_hours = TTDate::getHours( $uwf->getWeeklyTime() );
} else {
$employee_hourly_rate = 0;
$employee_annual_wage = 0;
$employee_wage_average_weekly_hours = 0;
}
Debug::Text( 'Employee Hourly Rate: ' . $employee_hourly_rate, __FILE__, __LINE__, __METHOD__, 10 );
}
if ( in_array( 'pay_period_worked_days', $formula_variables ) || in_array( 'pay_period_paid_days', $formula_variables ) || in_array( 'pay_period_worked_weeks', $formula_variables ) || in_array( 'pay_period_paid_weeks', $formula_variables ) ) {
$pay_period_days_worked = (array)$udtlf->getDaysWorkedByUserIDAndStartDateAndEndDate( $this->getUser(), $pay_period_obj->getStartDate(), $pay_period_obj->getEndDate() );
$pay_period_days_absence = (array)$udtlf->getDaysPaidAbsenceByUserIDAndStartDateAndEndDate( $this->getUser(), $pay_period_obj->getStartDate(), $pay_period_obj->getEndDate() );
}
if ( in_array( 'pay_period_worked_time', $formula_variables ) || in_array( 'pay_period_paid_time', $formula_variables ) ) {
$pay_period_worked_time = $udtlf->getWorkedTimeSumByUserIDAndStartDateAndEndDate( $this->getUser(), $pay_period_obj->getStartDate(), $pay_period_obj->getEndDate() );
$pay_period_absence_time = $udtlf->getPaidAbsenceTimeSumByUserIDAndStartDateAndEndDate( $this->getUser(), $pay_period_obj->getStartDate(), $pay_period_obj->getEndDate() );
}
if ( $cd_obj->getCompanyValue2() != '' && $cd_obj->getCompanyValue2() > 0 && $cd_obj->getCompanyValue3() != '' && $cd_obj->getCompanyValue3() > 0 ) {
Debug::Text( 'Formula Lookback enable: ' . $cd_obj->getCompanyValue2(), __FILE__, __LINE__, __METHOD__, 10 );
foreach ( $formula_variables as $formula_variable ) {
if ( strpos( $formula_variable, 'lookback_' ) !== false ) {
Debug::Text( 'Lookback variables exist...', __FILE__, __LINE__, __METHOD__, 10 );
$lookback_dates = $cd_obj->getLookbackStartAndEndDates( $pay_period_obj );
$lookback_pay_stub_dates = $cd_obj->getLookbackPayStubs( $this->getUser(), $pay_period_obj );
//Debug::Arr( $lookback_dates, 'Lookback Dates...', __FILE__, __LINE__, __METHOD__, 10 );
//Debug::Arr( $lookback_pay_stub_dates, 'Lookback PayStub Dates...', __FILE__, __LINE__, __METHOD__, 10 );
break;
}
}
}
if ( isset( $lookback_pay_stub_dates['first_pay_stub_start_date'] ) && isset( $lookback_pay_stub_dates['last_pay_stub_end_date'] )
&& ( in_array( 'lookback_pay_stub_worked_days', $formula_variables ) || in_array( 'lookback_pay_stub_paid_days', $formula_variables ) || in_array( 'lookback_pay_stub_worked_weeks', $formula_variables ) || in_array( 'lookback_pay_stub_paid_weeks', $formula_variables )) ) {
Debug::Text( 'Lookback Pay Stub Dates... Start: ' . TTDate::getDate( 'DATE', $lookback_pay_stub_dates['first_pay_stub_start_date'] ) . ' End: ' . TTDate::getDate( 'DATE', $lookback_pay_stub_dates['last_pay_stub_end_date'] ), __FILE__, __LINE__, __METHOD__, 10 );
$lookback_pay_stub_days_worked = (array)$udtlf->getDaysWorkedByUserIDAndStartDateAndEndDate( $this->getUser(), $lookback_pay_stub_dates['first_pay_stub_start_date'], $lookback_pay_stub_dates['last_pay_stub_end_date'] );
$lookback_pay_stub_days_absence = (array)$udtlf->getDaysPaidAbsenceByUserIDAndStartDateAndEndDate( $this->getUser(), $lookback_pay_stub_dates['first_pay_stub_start_date'], $lookback_pay_stub_dates['last_pay_stub_end_date'] );
} else {
$lookback_pay_stub_days_worked = [];
$lookback_pay_stub_days_absence = [];
}
if ( isset( $lookback_pay_stub_dates['first_pay_stub_start_date'] ) && isset( $lookback_pay_stub_dates['last_pay_stub_end_date'] )
&& ( in_array( 'lookback_pay_stub_worked_time', $formula_variables ) || in_array( 'lookback_pay_stub_paid_time', $formula_variables ) ) ) {
Debug::Text( 'Lookback Pay Stub Dates... Start: ' . TTDate::getDate( 'DATE', $lookback_pay_stub_dates['first_pay_stub_start_date'] ) . ' End: ' . TTDate::getDate( 'DATE', $lookback_pay_stub_dates['last_pay_stub_end_date'] ), __FILE__, __LINE__, __METHOD__, 10 );
$lookback_pay_stub_worked_time = $udtlf->getWorkedTimeSumByUserIDAndStartDateAndEndDate( $this->getUser(), $lookback_pay_stub_dates['first_pay_stub_start_date'], $lookback_pay_stub_dates['last_pay_stub_end_date'] );
$lookback_pay_stub_absence_time = $udtlf->getPaidAbsenceTimeSumByUserIDAndStartDateAndEndDate( $this->getUser(), $lookback_pay_stub_dates['first_pay_stub_start_date'], $lookback_pay_stub_dates['last_pay_stub_end_date'] );
} else {
$lookback_pay_stub_worked_time = 0;
$lookback_pay_stub_absence_time = 0;
}
//Second pass to define variables.
foreach ( $formula_variables as $formula_variable ) {
//Handle individual PS account amounts/units.
switch ( substr( $formula_variable, 0, 3 ) ) {
case 'PU:': //Units
$variables[$formula_variable] = $cd_obj->getPayStubEntryAmountSum( $pay_stub_obj, [ str_replace( 'PU:', '', $formula_variable ) ], 'current', 'units' );
break;
case 'PR:': //Rate
$variables[$formula_variable] = $cd_obj->getPayStubEntryAmountSum( $pay_stub_obj, [ str_replace( 'PR:', '', $formula_variable ) ], 'current', 'rate' );
break;
case 'PA:': //Amount
$variables[$formula_variable] = $cd_obj->getPayStubEntryAmountSum( $pay_stub_obj, [ str_replace( 'PA:', '', $formula_variable ) ], 'current', 'amount' );
break;
case 'PY:': //YTD Amount/Balance
$variables[$formula_variable] = $cd_obj->getPayStubEntryAmountSum( $pay_stub_obj, [ str_replace( 'PY:', '', $formula_variable ) ], 'previous', 'ytd_amount' ); //YTD Amount is only populated on previous pay stub when this runs.
break;
}
if ( !isset( $variables[$formula_variable] ) ) {
switch ( $formula_variable ) {
case 'custom_value1':
$variables[$formula_variable] = $user_value1;
break;
case 'custom_value2':
$variables[$formula_variable] = $user_value2;
break;
case 'custom_value3':
$variables[$formula_variable] = $user_value3;
break;
case 'custom_value4':
$variables[$formula_variable] = $user_value4;
break;
case 'custom_value5':
$variables[$formula_variable] = $user_value5;
break;
case 'custom_value6':
$variables[$formula_variable] = $user_value6;
break;
case 'custom_value7':
$variables[$formula_variable] = $user_value7;
break;
case 'custom_value8':
$variables[$formula_variable] = $user_value8;
break;
case 'custom_value9':
$variables[$formula_variable] = $user_value9;
break;
case 'custom_value10':
$variables[$formula_variable] = $user_value10;
break;
case 'employee_hourly_rate':
$variables[$formula_variable] = $employee_hourly_rate;
break;
case 'employee_annual_wage':
$variables[$formula_variable] = $employee_annual_wage;
break;
case 'employee_wage_average_weekly_hours':
$variables[$formula_variable] = $employee_wage_average_weekly_hours;
break;
case 'annual_pay_periods':
$variables[$formula_variable] = $annual_pay_periods;
break;
case 'pay_period_start_date':
$variables[$formula_variable] = $pay_period_obj->getStartDate();
break;
case 'pay_period_end_date':
$variables[$formula_variable] = $pay_period_obj->getEndDate();
break;
case 'pay_period_transaction_date':
$variables[$formula_variable] = $pay_period_obj->getTransactionDate();
break;
case 'pay_period_total_days':
$variables[$formula_variable] = round( TTDate::getDays( ( TTDate::getEndDayEpoch( $pay_period_obj->getEndDate() ) - TTDate::getBeginDayEpoch( $pay_period_obj->getStartDate() ) ) ) );
break;
case 'pay_period_worked_days':
$variables[$formula_variable] = count( array_unique( $pay_period_days_worked ) );
break;
case 'pay_period_paid_days':
$variables[$formula_variable] = count( array_unique( array_merge( $pay_period_days_worked, $pay_period_days_absence ) ) );
break;
case 'pay_period_worked_weeks':
$variables[$formula_variable] = $test = count( array_unique( array_map( function($epoch) use ($pay_period_start_week_day) {
return TTDate::getWeek( $epoch, $pay_period_start_week_day);
}, array_map( 'TTDate::strtotime', $pay_period_days_worked ) ) ) );
break;
case 'pay_period_paid_weeks':
$variables[$formula_variable] = $test = count( array_unique( array_map( function($epoch) use ($pay_period_start_week_day) {
return TTDate::getWeek( $epoch, $pay_period_start_week_day);
}, array_map( 'TTDate::strtotime', array_merge( $pay_period_days_worked, $pay_period_days_absence ) ) ) ) );
break;
case 'pay_period_worked_time':
$variables[$formula_variable] = $pay_period_worked_time;
break;
case 'pay_period_paid_time':
$variables[$formula_variable] = ( $pay_period_worked_time + $pay_period_absence_time );
break;
case 'employee_hire_date':
$variables[$formula_variable] = $this->getUserObject()->getHireDate();
break;
case 'employee_termination_date':
$variables[$formula_variable] = $this->getUserObject()->getTerminationDate();
break;
case 'employee_birth_date':
$variables[$formula_variable] = $this->getUserObject()->getBirthDate();
break;
case 'currency_iso_code':
$variables[$formula_variable] = $currency_iso_code;
break;
case 'currency_conversion_rate':
$variables[$formula_variable] = $currency_conversion_rate;
break;
case 'include_pay_stub_amount':
$variables[$formula_variable] = $cd_obj->getCalculationPayStubAmount( $pay_stub_obj, 10 );
break;
case 'include_pay_stub_ytd_amount':
$variables[$formula_variable] = $cd_obj->getCalculationPayStubAmount( $pay_stub_obj, 30 );
break;
case 'include_pay_stub_units':
$variables[$formula_variable] = $cd_obj->getCalculationPayStubAmount( $pay_stub_obj, 20 );
break;
case 'include_pay_stub_ytd_units':
$variables[$formula_variable] = $cd_obj->getCalculationPayStubAmount( $pay_stub_obj, 40 );
break;
case 'exclude_pay_stub_amount':
$variables[$formula_variable] = $cd_obj->getCalculationPayStubAmount( $pay_stub_obj, null, 10 );
break;
case 'exclude_pay_stub_ytd_amount':
$variables[$formula_variable] = $cd_obj->getCalculationPayStubAmount( $pay_stub_obj, null, 30 );
break;
case 'exclude_pay_stub_units':
$variables[$formula_variable] = $cd_obj->getCalculationPayStubAmount( $pay_stub_obj, null, 20 );
break;
case 'exclude_pay_stub_ytd_units':
$variables[$formula_variable] = $cd_obj->getCalculationPayStubAmount( $pay_stub_obj, null, 40 );
break;
case 'pay_stub_amount':
$variables[$formula_variable] = $cd_obj->getCalculationPayStubAmount( $pay_stub_obj, 10, 10 );
break;
case 'pay_stub_ytd_amount':
$variables[$formula_variable] = $cd_obj->getCalculationPayStubAmount( $pay_stub_obj, 30, 30 );
break;
case 'pay_stub_units':
$variables[$formula_variable] = $cd_obj->getCalculationPayStubAmount( $pay_stub_obj, 20, 20 );
break;
case 'pay_stub_ytd_units':
$variables[$formula_variable] = $cd_obj->getCalculationPayStubAmount( $pay_stub_obj, 40, 40 );
break;
//Lookback variables.
case 'lookback_total_pay_stubs':
$variables[$formula_variable] = ( isset( $lookback_pay_stub_dates['total_pay_stubs'] ) ) ? $lookback_pay_stub_dates['total_pay_stubs'] : 0;
break;
case 'lookback_start_date':
$variables[$formula_variable] = ( isset( $lookback_dates['start_date'] ) ) ? $lookback_dates['start_date'] : 0;
break;
case 'lookback_end_date':
$variables[$formula_variable] = ( isset( $lookback_dates['end_date'] ) ) ? $lookback_dates['end_date'] : 0;
break;
case 'lookback_total_days':
if ( isset( $lookback_dates['start_date'] ) && isset( $lookback_dates['end_date'] ) ) {
$variables[$formula_variable] = round( TTDate::getDays( ( TTDate::getEndDayEpoch( $lookback_dates['end_date'] ) - TTDate::getBeginDayEpoch( $lookback_dates['start_date'] ) ) ) );
} else {
$variables[$formula_variable] = 0;
}
break;
case 'lookback_first_pay_stub_start_date':
$variables[$formula_variable] = ( isset( $lookback_pay_stub_dates['first_pay_stub_start_date'] ) ) ? $lookback_pay_stub_dates['first_pay_stub_start_date'] : 0;
break;
case 'lookback_first_pay_stub_end_date':
$variables[$formula_variable] = ( isset( $lookback_pay_stub_dates['first_pay_stub_end_date'] ) ) ? $lookback_pay_stub_dates['first_pay_stub_end_date'] : 0;
break;
case 'lookback_first_pay_stub_transaction_date':
$variables[$formula_variable] = ( isset( $lookback_pay_stub_dates['first_pay_stub_transaction_date'] ) ) ? $lookback_pay_stub_dates['first_pay_stub_transaction_date'] : 0;
break;
case 'lookback_last_pay_stub_start_date':
$variables[$formula_variable] = ( isset( $lookback_pay_stub_dates['last_pay_stub_start_date'] ) ) ? $lookback_pay_stub_dates['last_pay_stub_start_date'] : 0;
break;
case 'lookback_last_pay_stub_end_date':
$variables[$formula_variable] = ( isset( $lookback_pay_stub_dates['last_pay_stub_end_date'] ) ) ? $lookback_pay_stub_dates['last_pay_stub_end_date'] : 0;
break;
case 'lookback_last_pay_stub_transaction_date':
$variables[$formula_variable] = ( isset( $lookback_pay_stub_dates['last_pay_stub_transaction_date'] ) ) ? $lookback_pay_stub_dates['last_pay_stub_end_date'] : 0;
break;
case 'lookback_pay_stub_total_days':
if ( isset( $lookback_pay_stub_dates['first_pay_stub_start_date'] ) && isset( $lookback_pay_stub_dates['last_pay_stub_end_date'] ) ) {
$variables[$formula_variable] = round( TTDate::getDays( ( ( TTDate::getEndDayEpoch( $lookback_pay_stub_dates['last_pay_stub_end_date'] ) - TTDate::getBeginDayEpoch( $lookback_pay_stub_dates['first_pay_stub_start_date'] ) ) ) ) );
} else {
$variables[$formula_variable] = 0;
}
break;
case 'lookback_pay_stub_worked_days':
$variables[$formula_variable] = count( array_unique( $lookback_pay_stub_days_worked ) );
break;
case 'lookback_pay_stub_paid_days':
$variables[$formula_variable] = count( array_unique( array_merge( $lookback_pay_stub_days_worked, $lookback_pay_stub_days_absence ) ) );
break;
case 'lookback_pay_stub_worked_weeks':
$variables[$formula_variable] = $test = count( array_unique( array_map( function($epoch) use ($pay_period_start_week_day) {
return TTDate::getWeek( $epoch, $pay_period_start_week_day);
}, array_map( 'TTDate::strtotime', $lookback_pay_stub_days_worked ) ) ) );
break;
case 'lookback_pay_stub_paid_weeks':
$variables[$formula_variable] = $test = count( array_unique( array_map( function($epoch) use ($pay_period_start_week_day) {
return TTDate::getWeek( $epoch, $pay_period_start_week_day);
}, array_map( 'TTDate::strtotime', array_merge( $lookback_pay_stub_days_worked, $lookback_pay_stub_days_absence ) ) ) ) );
break;
case 'lookback_pay_stub_worked_time':
$variables[$formula_variable] = $lookback_pay_stub_worked_time;
break;
case 'lookback_pay_stub_paid_time':
$variables[$formula_variable] = ( $lookback_pay_stub_worked_time + $lookback_pay_stub_absence_time );
break;
case 'lookback_include_pay_stub_amount':
$variables[$formula_variable] = $cd_obj->getLookbackCalculationPayStubAmount( 10 );
break;
case 'lookback_include_pay_stub_ytd_amount':
$variables[$formula_variable] = $cd_obj->getLookbackCalculationPayStubAmount( 30 );
break;
case 'lookback_include_pay_stub_units':
$variables[$formula_variable] = $cd_obj->getLookbackCalculationPayStubAmount( 20 );
break;
case 'lookback_include_pay_stub_ytd_units':
$variables[$formula_variable] = $cd_obj->getLookbackCalculationPayStubAmount( 40 );
break;
case 'lookback_exclude_pay_stub_amount':
$variables[$formula_variable] = $cd_obj->getLookbackCalculationPayStubAmount( null, 10 );
break;
case 'lookback_exclude_pay_stub_ytd_amount':
$variables[$formula_variable] = $cd_obj->getLookbackCalculationPayStubAmount( null, 30 );
break;
case 'lookback_exclude_pay_stub_units':
$variables[$formula_variable] = $cd_obj->getLookbackCalculationPayStubAmount( null, 20 );
break;
case 'lookback_exclude_pay_stub_ytd_units':
$variables[$formula_variable] = $cd_obj->getLookbackCalculationPayStubAmount( null, 40 );
break;
case 'lookback_pay_stub_amount':
$variables[$formula_variable] = $cd_obj->getLookbackCalculationPayStubAmount( 10, 10 );
break;
case 'lookback_pay_stub_ytd_amount':
$variables[$formula_variable] = $cd_obj->getLookbackCalculationPayStubAmount( 30, 30 );
break;
case 'lookback_pay_stub_units':
$variables[$formula_variable] = $cd_obj->getLookbackCalculationPayStubAmount( 20, 20 );
break;
case 'lookback_pay_stub_ytd_units':
$variables[$formula_variable] = $cd_obj->getLookbackCalculationPayStubAmount( 40, 40 );
break;
}
}
}
unset( $uwlf, $uwf, $employee_hourly_rate, $employee_annual_wage, $employee_wage_average_weekly_hours, $annual_pay_periods, $lookback_dates, $lookback_pay_stub_dates, $currency_iso_code, $currency_conversion_rate, $pay_period_worked_time, $pay_period_absence_time, $lookback_pay_stub_worked_time, $lookback_pay_stub_absence_time, $pay_period_days_worked, $pay_period_days_absence, $lookback_pay_stub_days_worked, $lookback_pay_stub_days_absence );
}
//Debug::Arr( $variables, 'Formula Variable values: ', __FILE__, __LINE__, __METHOD__, 10 );
Debug::Arr( [ str_replace( "\r", '; ', $company_value1 ), str_replace( "\r", '; ', TTMath::translateVariables( $company_value1, $variables ) ) ], 'Original/Translated Formula: ', __FILE__, __LINE__, __METHOD__, 10 );
$retval = TTMath::evaluate( TTMath::translateVariables( $company_value1, $variables ) );
Debug::Text( 'Formula Retval: ' . $retval, __FILE__, __LINE__, __METHOD__, 10 );
break;
case 82: //US - Medicare - Employee
case 83: //US - Medicare - Employer
case 84: //US - Social Security - Employee
case 85: //US - Social Security - Employer
case 89: //US - Federal Unemployment Insurance - Employer
$amount = $cd_obj->getCalculationPayStubAmount( $pay_stub_obj );
Debug::Text( 'Amount: '. $amount .' Annual Pay Periods: ' . $annual_pay_periods .' Current PP: '. $current_pay_period, __FILE__, __LINE__, __METHOD__, 10 );
$pd_obj = new PayrollDeduction( 'US', null );
$pd_obj->setCompany( $this->getUserObject()->getCompany() );
$pd_obj->setUser( $this->getUser() );
$pd_obj->setDate( $pay_stub_obj->getTransactionDate() );
$pd_obj->setAnnualPayPeriods( $annual_pay_periods );
$pd_obj->setCurrentPayPeriod( $current_pay_period );
$pd_obj->setHireAdjustedAnnualPayPeriods( $hire_adjusted_annual_pay_periods );
$pd_obj->setHireAdjustedCurrentPayPeriod( $hire_adjusted_current_pay_period );
$pd_obj->setCurrentPayrollRunID( $payroll_run_id );
$pd_obj->setFormulaType( $formula_type_id );
if ( is_object( $this->getUserObject() ) ) {
$currency_id = $this->getUserObject()->getCurrency();
$pd_obj->setUserCurrency( $currency_id );
Debug::Text( 'User Currency ID: ' . $currency_id, __FILE__, __LINE__, __METHOD__, 10 );
}
$pd_obj->setGrossPayPeriodIncome( $amount );
switch ( $cd_obj->getCalculation() ) {
case 82: //US - Medicare - Employee
$pd_obj->setYearToDateGrossIncome( $cd_obj->getCalculationYTDAmount( $pay_stub_obj ) ); //Make sure YTD amount is specified for all calculation types.
$retval = $pd_obj->getEmployeeMedicare();
break;
case 83: //US - Medicare - Employer
$retval = $pd_obj->getEmployerMedicare();
break;
case 84: //US - Social Security - Employee
$pd_obj->setYearToDateSocialSecurityContribution( $cd_obj->getPayStubEntryAccountYTDAmount( $pay_stub_obj ) );
$retval = $pd_obj->getEmployeeSocialSecurity();
break;
case 85: //US - Social Security - Employer
$pd_obj->setYearToDateSocialSecurityContribution( $cd_obj->getPayStubEntryAccountYTDAmount( $pay_stub_obj ) );
$retval = $pd_obj->getEmployerSocialSecurity();
break;
case 89: //US - Federal Unemployment Insurance - Employer
$pd_obj->setYearToDateFederalUIContribution( $cd_obj->getPayStubEntryAccountYTDAmount( $pay_stub_obj ) );
$pd_obj->setFederalUIRate( ( ( $this->getUserValue1() == '' ) ? $cd_obj->getUserValue1() : $this->getUserValue1() ) );
$retval = $pd_obj->getFederalEmployerUI();
break;
}
break;
case 210: //US - State Unemployment Insurance - Employer
$user_value1 = ( ( $this->getUserValue1() == '' ) ? $cd_obj->getUserValue1() : $this->getUserValue1() );
$amount = $cd_obj->getCalculationPayStubAmount( $pay_stub_obj );
Debug::Text( 'Amount: '. $amount .' Annual Pay Periods: ' . $annual_pay_periods .' Current PP: '. $current_pay_period, __FILE__, __LINE__, __METHOD__, 10 );
$pd_obj = new PayrollDeduction( 'US', $cd_obj->getProvince() );
$pd_obj->setCompany( $this->getUserObject()->getCompany() );
$pd_obj->setUser( $this->getUser() );
$pd_obj->setDate( $pay_stub_obj->getTransactionDate() );
$pd_obj->setAnnualPayPeriods( $annual_pay_periods );
$pd_obj->setCurrentPayPeriod( $current_pay_period );
$pd_obj->setHireAdjustedAnnualPayPeriods( $hire_adjusted_annual_pay_periods );
$pd_obj->setHireAdjustedCurrentPayPeriod( $hire_adjusted_current_pay_period );
$pd_obj->setCurrentPayrollRunID( $payroll_run_id );
$pd_obj->setFormulaType( $formula_type_id );
if ( is_object( $this->getUserObject() ) ) {
$currency_id = $this->getUserObject()->getCurrency();
$pd_obj->setUserCurrency( $currency_id );
Debug::Text( 'User Currency ID: ' . $currency_id, __FILE__, __LINE__, __METHOD__, 10 );
}
$pd_obj->setGrossPayPeriodIncome( $amount );
switch ( $cd_obj->getCalculation() ) {
case 210: //US - State Unemployment Insurance - Employer
$pd_obj->setYearToDateStateUIContribution( $cd_obj->getPayStubEntryAccountYTDAmount( $pay_stub_obj ) );
$pd_obj->setStateUIRate( $user_value1 );
$retval = $pd_obj->getStateEmployerUI();
break;
}
break;
case 90: //Canada - CPP
$amount = $cd_obj->getCalculationPayStubAmount( $pay_stub_obj );
Debug::Text( 'Amount: '. $amount .' Annual Pay Periods: ' . $annual_pay_periods .' Current PP: '. $current_pay_period, __FILE__, __LINE__, __METHOD__, 10 );
$pd_obj = new PayrollDeduction( 'CA', null );
$pd_obj->setCompany( $this->getUserObject()->getCompany() );
$pd_obj->setUser( $this->getUser() );
$pd_obj->setDate( $pay_stub_obj->getTransactionDate() );
$pd_obj->setAnnualPayPeriods( $annual_pay_periods );
$pd_obj->setCurrentPayPeriod( $current_pay_period );
$pd_obj->setHireAdjustedAnnualPayPeriods( $hire_adjusted_annual_pay_periods );
$pd_obj->setHireAdjustedCurrentPayPeriod( $hire_adjusted_current_pay_period );
$pd_obj->setCurrentPayrollRunID( $payroll_run_id );
$pd_obj->setFormulaType( $formula_type_id );
$pd_obj->setEnableCPPAndEIDeduction( true );
//Used to check $this->getPayStubEntryAccountLinkObject()->getEmployeeCPP() here, but that function has been deprecated to better support multiple legal entities.
$pd_obj->setYearToDateCPPContribution( $cd_obj->getPayStubEntryAccountYTDAmount( $pay_stub_obj ) );
$pd_obj->setGrossPayPeriodIncome( $amount );
$retval = $pd_obj->getEmployeeCPP();
if ( $retval < 0 ) {
$retval = 0;
}
break;
case 91: //Canada - EI
$amount = $cd_obj->getCalculationPayStubAmount( $pay_stub_obj );
Debug::Text( 'Amount: '. $amount .' Annual Pay Periods: ' . $annual_pay_periods .' Current PP: '. $current_pay_period, __FILE__, __LINE__, __METHOD__, 10 );
$pd_obj = new PayrollDeduction( 'CA', null );
$pd_obj->setCompany( $this->getUserObject()->getCompany() );
$pd_obj->setUser( $this->getUser() );
$pd_obj->setDate( $pay_stub_obj->getTransactionDate() );
$pd_obj->setAnnualPayPeriods( $annual_pay_periods );
$pd_obj->setCurrentPayPeriod( $current_pay_period );
$pd_obj->setHireAdjustedAnnualPayPeriods( $hire_adjusted_annual_pay_periods );
$pd_obj->setHireAdjustedCurrentPayPeriod( $hire_adjusted_current_pay_period );
$pd_obj->setCurrentPayrollRunID( $payroll_run_id );
$pd_obj->setFormulaType( $formula_type_id );
$pd_obj->setEnableCPPAndEIDeduction( true );
//Used to check $this->getPayStubEntryAccountLinkObject()->getEmployeeEI() here, but that function has been deprecated to better support multiple legal entities.
$pd_obj->setYearToDateEIContribution( $cd_obj->getPayStubEntryAccountYTDAmount( $pay_stub_obj ) );
$pd_obj->setGrossPayPeriodIncome( $amount );
$retval = $pd_obj->getEmployeeEI();
if ( $retval < 0 ) {
$retval = 0;
}
break;
case 100: //Federal Income Tax
$user_value1 = ( ( $this->getUserValue1() == '' ) ? $cd_obj->getUserValue1() : $this->getUserValue1() );
$user_value2 = ( ( $this->getUserValue2() == '' ) ? $cd_obj->getUserValue2() : $this->getUserValue2() );
$user_value3 = ( ( $this->getUserValue3() == '' ) ? $cd_obj->getUserValue3() : $this->getUserValue3() );
$user_value4 = ( ( $this->getUserValue4() == '' ) ? $cd_obj->getUserValue4() : $this->getUserValue4() );
$user_value5 = ( ( $this->getUserValue5() == '' ) ? $cd_obj->getUserValue5() : $this->getUserValue5() );
$user_value6 = ( ( $this->getUserValue6() == '' ) ? $cd_obj->getUserValue6() : $this->getUserValue6() );
$user_value7 = ( ( $this->getUserValue7() == '' ) ? $cd_obj->getUserValue7() : $this->getUserValue7() );
$user_value9 = ( ( $this->getUserValue9() == '' ) ? $cd_obj->getUserValue9() : $this->getUserValue9() );
Debug::Text( 'UserValue: 1: ' . $user_value1 . ' 2: ' . $user_value2 . ' 3: ' . $user_value3 . ' 4: ' . $user_value4 . ' 5: ' . $user_value5 . ' 6: ' . $user_value6 . ' 7: ' . $user_value7 . ' 9: ' . $user_value9, __FILE__, __LINE__, __METHOD__, 10 );
$amount = $cd_obj->getCalculationPayStubAmount( $pay_stub_obj );
Debug::Text( 'Amount: '. $amount .' Annual Pay Periods: ' . $annual_pay_periods .' Current PP: '. $current_pay_period, __FILE__, __LINE__, __METHOD__, 10 );
$pd_obj = new PayrollDeduction( $cd_obj->getCountry(), null );
$pd_obj->setCompany( $this->getUserObject()->getCompany() );
$pd_obj->setUser( $this->getUser() );
$pd_obj->setDate( $pay_stub_obj->getTransactionDate() );
$pd_obj->setAnnualPayPeriods( $annual_pay_periods );
$pd_obj->setCurrentPayPeriod( $current_pay_period );
$pd_obj->setHireAdjustedAnnualPayPeriods( $hire_adjusted_annual_pay_periods );
$pd_obj->setHireAdjustedCurrentPayPeriod( $hire_adjusted_current_pay_period );
$pd_obj->setCurrentPayrollRunID( $payroll_run_id );
$pd_obj->setFormulaType( $formula_type_id );
if ( is_object( $this->getUserObject() ) ) {
$currency_id = $this->getUserObject()->getCurrency();
$pd_obj->setUserCurrency( $currency_id );
Debug::Text( 'User Currency ID: ' . $currency_id, __FILE__, __LINE__, __METHOD__, 10 );
}
$pd_obj->setYearToDateGrossIncome( $cd_obj->getCalculationYTDAmount( $pay_stub_obj ) ); //Make sure YTD amount is specified for all calculation types.
$pd_obj->setYearToDateDeduction( $cd_obj->getPayStubEntryAccountYTDAmount( $pay_stub_obj ) ); //Make sure YTD amount is specified for all calculation types.
$pd_obj->setGrossPayPeriodIncome( $amount );
if ( $cd_obj->getCountry() == 'CA' ) {
$user_value1 = $this->Validator->stripNonFloat( $user_value1 );
//CA
$pd_obj->setFederalTotalClaimAmount( $user_value1 );
$pd_obj->setEnableCPPAndEIDeduction( true );
$cdlf = TTnew( 'CompanyDeductionListFactory' ); /** @var CompanyDeductionListFactory $cdlf */
$cdlf->getByCompanyIdAndLegalEntityIdAndCalculationIdAndStatusId( $cd_obj->getCompany(), $cd_obj->getLegalEntity(), 90, 10 ); //90=CPP, 10=Enabled
if ( $cdlf->getRecordCount() == 1 ) {
$tmp_cd_obj = $cdlf->getCurrent();
Debug::Text( 'Found Employee CPP account link!: ', __FILE__, __LINE__, __METHOD__, 10 );
//Check to see if CPP was calculated on the CURRENT pay stub, if not assume they are CPP exempt.
//Since this calculation formula doesn't know directly if the user was CPP exempt or not, we have to assume it by
//the calculate CPP on the current pay stub. However if the CPP calculation is done AFTER this, it may mistakenly assume they are exempt.
//Make sure we handle the maximum CPP contribution cases properly as well.
//$current_cpp = $pay_stub_obj->getSumByEntriesArrayAndTypeIDAndPayStubAccountID( 'current', NULL, $this->getPayStubEntryAccountLinkObject()->getEmployeeCPP() );
$current_cpp = $pay_stub_obj->getSumByEntriesArrayAndTypeIDAndPayStubAccountID( 'current', null, $tmp_cd_obj->getPayStubEntryAccount() );
if ( isset( $current_cpp['amount'] ) && $current_cpp['amount'] == 0 ) {
Debug::Text( 'Current CPP: ' . $current_cpp['amount'] . ' Setting CPP exempt in Federal Income Tax calculation...', __FILE__, __LINE__, __METHOD__, 10 );
$pd_obj->setCPPExempt( true );
} else if ( isset( $current_cpp['amount'] ) && $current_cpp['amount'] != 0 ) {
$pd_obj->setEmployeeCPPForPayPeriod( $current_cpp['amount'] ); //Make sure we pass in the amount that was calculated, as it may have different include/exclude accounts than this.
}
//$ytd_cpp_arr = $pay_stub_obj->getSumByEntriesArrayAndTypeIDAndPayStubAccountID( 'previous', NULL, $this->getPayStubEntryAccountLinkObject()->getEmployeeCPP() );
$ytd_cpp_arr = $pay_stub_obj->getSumByEntriesArrayAndTypeIDAndPayStubAccountID( 'previous', null, $tmp_cd_obj->getPayStubEntryAccount() );
Debug::text( 'YTD CPP Contribution: ' . $ytd_cpp_arr['ytd_amount'], __FILE__, __LINE__, __METHOD__, 10 );
$pd_obj->setYearToDateCPPContribution( $ytd_cpp_arr['ytd_amount'] );
unset( $ytd_cpp_arr, $current_cpp, $tmp_cd_obj );
}
$cdlf->getByCompanyIdAndLegalEntityIdAndCalculationIdAndStatusId( $cd_obj->getCompany(), $cd_obj->getLegalEntity(), 91, 10 ); //91=EI, 10=Enabled
if ( $cdlf->getRecordCount() == 1 ) {
$tmp_cd_obj = $cdlf->getCurrent();
Debug::Text( 'Found Employee EI account link!: ', __FILE__, __LINE__, __METHOD__, 10 );
//See comment above regarding CPP exempt.
//$current_ei = $pay_stub_obj->getSumByEntriesArrayAndTypeIDAndPayStubAccountID( 'current', NULL, $this->getPayStubEntryAccountLinkObject()->getEmployeeEI() );
$current_ei = $pay_stub_obj->getSumByEntriesArrayAndTypeIDAndPayStubAccountID( 'current', null, $tmp_cd_obj->getPayStubEntryAccount() );
if ( isset( $current_ei['amount'] ) && $current_ei['amount'] == 0 ) {
Debug::Text( 'Current EI: ' . $current_ei['amount'] . ' Setting EI exempt in Federal Income Tax calculation...', __FILE__, __LINE__, __METHOD__, 10 );
$pd_obj->setEIExempt( true );
} else if ( isset( $current_ei['amount'] ) && $current_ei['amount'] != 0 ) {
$pd_obj->setEmployeeEIForPayPeriod( $current_ei['amount'] ); //Make sure we pass in the amount that was calculated, as it may have different include/exclude accounts than this.
}
//$ytd_ei_arr = $pay_stub_obj->getSumByEntriesArrayAndTypeIDAndPayStubAccountID( 'previous', NULL, $this->getPayStubEntryAccountLinkObject()->getEmployeeEI() );
$ytd_ei_arr = $pay_stub_obj->getSumByEntriesArrayAndTypeIDAndPayStubAccountID( 'previous', null, $tmp_cd_obj->getPayStubEntryAccount() );
Debug::text( 'YTD EI Contribution: ' . $ytd_ei_arr['ytd_amount'], __FILE__, __LINE__, __METHOD__, 10 );
$pd_obj->setYearToDateEIContribution( $ytd_ei_arr['ytd_amount'] );
unset( $ytd_ei_arr, $current_ei, $tmp_cd_obj );
}
unset( $cdlf );
} else if ( $cd_obj->getCountry() == 'US' ) {
//
//**IMPORTANT NOTE: These settings need to all match for US state income tax too, as some states (ie: Iowa) take federal tax into account.
//
$user_value2 = $this->Validator->stripNonFloat( $user_value2 );
//UserValue3 is boolean.
$user_value4 = $this->Validator->stripNonFloat( $user_value4 );
$user_value5 = $this->Validator->stripNonFloat( $user_value5 );
$user_value6 = $this->Validator->stripNonFloat( $user_value6 );
$user_value7 = $this->Validator->stripNonFloat( $user_value7 );
//US
$pd_obj->setFederalFormW4Version( $user_value9 );
$pd_obj->setFederalFilingStatus( $user_value1 );
$pd_obj->setFederalAllowance( $user_value2 );
$pd_obj->setFederalMultipleJobs( ( ( (int)$user_value3 >= 1 ) ? true : false ) );
$pd_obj->setFederalClaimDependents( $user_value4 );
$pd_obj->setFederalOtherIncome( $user_value5 );
$pd_obj->setFederalDeductions( $user_value6 );
$pd_obj->setFederalAdditionalDeduction( $user_value7 );
$pd_obj->setFederalTaxExempt( ( ( (int)$this->getUserValue10() >= 1 ) ? true : false ) );
} else if ( $cd_obj->getCountry() == 'CR' ) {
//CR
$pd_obj->setFederalFilingStatus( $user_value1 ); //Single/Married
$pd_obj->setFederalAllowance( $user_value2 ); //Allownces/Children
}
$retval = $pd_obj->getFederalPayPeriodDeductions();
if ( $retval < 0 ) {
$retval = 0;
}
break;
case 200: //Province Income Tax
$user_value1 = ( ( $this->getUserValue1() == '' ) ? $cd_obj->getUserValue1() : $this->getUserValue1() );
$user_value2 = ( ( $this->getUserValue2() == '' ) ? $cd_obj->getUserValue2() : $this->getUserValue2() );
$user_value3 = ( ( $this->getUserValue3() == '' ) ? $cd_obj->getUserValue3() : $this->getUserValue3() );
Debug::Text( 'UserValue: 1: ' . $user_value1 . ' 2: ' . $user_value2 . ' 3: ' . $user_value3, __FILE__, __LINE__, __METHOD__, 10 );
$amount = $cd_obj->getCalculationPayStubAmount( $pay_stub_obj );
Debug::Text( 'Amount: '. $amount .' Annual Pay Periods: ' . $annual_pay_periods .' Current PP: '. $current_pay_period, __FILE__, __LINE__, __METHOD__, 10 );
$pd_obj = new PayrollDeduction( $cd_obj->getCountry(), $cd_obj->getProvince() );
$pd_obj->setCompany( $this->getUserObject()->getCompany() );
$pd_obj->setUser( $this->getUser() );
$pd_obj->setDate( $pay_stub_obj->getTransactionDate() );
$pd_obj->setAnnualPayPeriods( $annual_pay_periods );
$pd_obj->setCurrentPayPeriod( $current_pay_period );
$pd_obj->setHireAdjustedAnnualPayPeriods( $hire_adjusted_annual_pay_periods );
$pd_obj->setHireAdjustedCurrentPayPeriod( $hire_adjusted_current_pay_period );
$pd_obj->setCurrentPayrollRunID( $payroll_run_id );
$pd_obj->setFormulaType( $formula_type_id );
if ( is_object( $this->getUserObject() ) ) {
$currency_id = $this->getUserObject()->getCurrency();
$pd_obj->setUserCurrency( $currency_id );
Debug::Text( 'User Currency ID: ' . $currency_id, __FILE__, __LINE__, __METHOD__, 10 );
}
$pd_obj->setYearToDateGrossIncome( $cd_obj->getCalculationYTDAmount( $pay_stub_obj ) ); //Make sure YTD amount is specified for all calculation types.
$pd_obj->setYearToDateDeduction( $cd_obj->getPayStubEntryAccountYTDAmount( $pay_stub_obj ) ); //Make sure YTD amount is specified for all calculation types.
$pd_obj->setGrossPayPeriodIncome( $amount );
if ( $cd_obj->getCountry() == 'CA' ) {
$user_value1 = $this->Validator->stripNonFloat( $user_value1 );
Debug::Text( 'Canada Pay Period Deductions...', __FILE__, __LINE__, __METHOD__, 10 );
$pd_obj->setProvincialTotalClaimAmount( $user_value1 );
$pd_obj->setEnableCPPAndEIDeduction( true );
$cdlf = TTnew( 'CompanyDeductionListFactory' ); /** @var CompanyDeductionListFactory $cdlf */
$cdlf->getByCompanyIdAndLegalEntityIdAndCalculationIdAndStatusId( $cd_obj->getCompany(), $cd_obj->getLegalEntity(), 90, 10 ); //90=CPP, 10=Enabled
if ( $cdlf->getRecordCount() == 1 ) {
$tmp_cd_obj = $cdlf->getCurrent();
Debug::Text( 'Found Employee CPP account link!: ', __FILE__, __LINE__, __METHOD__, 10 );
//Check to see if CPP was calculated on the CURRENT pay stub, if not assume they are CPP exempt.
//Since this calculation formula doesn't know directly if the user was CPP exempt or not, we have to assume it by
//the calculate CPP on the current pay stub. However if the CPP calculation is done AFTER this, it may mistakenly assume they are exempt.
//Make sure we handle the maximum CPP contribution cases properly as well.
//$current_cpp = $pay_stub_obj->getSumByEntriesArrayAndTypeIDAndPayStubAccountID( 'current', NULL, $this->getPayStubEntryAccountLinkObject()->getEmployeeCPP() );
$current_cpp = $pay_stub_obj->getSumByEntriesArrayAndTypeIDAndPayStubAccountID( 'current', null, $tmp_cd_obj->getPayStubEntryAccount() );
if ( isset( $current_cpp['amount'] ) && $current_cpp['amount'] == 0 ) {
Debug::Text( 'Current CPP: ' . $current_cpp['amount'] . ' Setting CPP exempt in Provincial Income Tax calculation...', __FILE__, __LINE__, __METHOD__, 10 );
$pd_obj->setCPPExempt( true );
} else if ( isset( $current_cpp['amount'] ) && $current_cpp['amount'] != 0 ) {
$pd_obj->setEmployeeCPPForPayPeriod( $current_cpp['amount'] ); //Make sure we pass in the amount that was calculated, as it may have different include/exclude accounts than this.
}
//$ytd_cpp_arr = $pay_stub_obj->getSumByEntriesArrayAndTypeIDAndPayStubAccountID( 'previous', NULL, $this->getPayStubEntryAccountLinkObject()->getEmployeeCPP() );
$ytd_cpp_arr = $pay_stub_obj->getSumByEntriesArrayAndTypeIDAndPayStubAccountID( 'previous', null, $tmp_cd_obj->getPayStubEntryAccount() );
Debug::text( 'YTD CPP Contribution: ' . $ytd_cpp_arr['ytd_amount'], __FILE__, __LINE__, __METHOD__, 10 );
$pd_obj->setYearToDateCPPContribution( $ytd_cpp_arr['ytd_amount'] );
unset( $ytd_cpp_arr, $current_cpp, $tmp_cd_obj );
}
$cdlf->getByCompanyIdAndLegalEntityIdAndCalculationIdAndStatusId( $cd_obj->getCompany(), $cd_obj->getLegalEntity(), 91, 10 ); //91=EI, 10=Enabled
if ( $cdlf->getRecordCount() == 1 ) {
$tmp_cd_obj = $cdlf->getCurrent();
Debug::Text( 'Found Employee EI account link!: ', __FILE__, __LINE__, __METHOD__, 10 );
//See comment above regarding CPP exempt.
//$current_ei = $pay_stub_obj->getSumByEntriesArrayAndTypeIDAndPayStubAccountID( 'current', NULL, $this->getPayStubEntryAccountLinkObject()->getEmployeeEI() );
$current_ei = $pay_stub_obj->getSumByEntriesArrayAndTypeIDAndPayStubAccountID( 'current', null, $tmp_cd_obj->getPayStubEntryAccount() );
if ( isset( $current_ei['amount'] ) && $current_ei['amount'] == 0 ) {
Debug::Text( 'Current EI: ' . $current_ei['amount'] . ' Setting EI exempt in Provincial Income Tax calculation...', __FILE__, __LINE__, __METHOD__, 10 );
$pd_obj->setEIExempt( true );
} else if ( isset( $current_ei['amount'] ) && $current_ei['amount'] != 0 ) {
$pd_obj->setEmployeeEIForPayPeriod( $current_ei['amount'] ); //Make sure we pass in the amount that was calculated, as it may have different include/exclude accounts than this.
}
//$ytd_ei_arr = $pay_stub_obj->getSumByEntriesArrayAndTypeIDAndPayStubAccountID( 'previous', NULL, $this->getPayStubEntryAccountLinkObject()->getEmployeeEI() );
$ytd_ei_arr = $pay_stub_obj->getSumByEntriesArrayAndTypeIDAndPayStubAccountID( 'previous', null, $tmp_cd_obj->getPayStubEntryAccount() );
Debug::text( 'YTD EI Contribution: ' . $ytd_ei_arr['ytd_amount'], __FILE__, __LINE__, __METHOD__, 10 );
$pd_obj->setYearToDateEIContribution( $ytd_ei_arr['ytd_amount'] );
unset( $ytd_ei_arr, $current_ei, $tmp_cd_obj );
}
unset( $cdlf );
$retval = $pd_obj->getProvincialPayPeriodDeductions();
} else if ( $cd_obj->getCountry() == 'US' ) {
Debug::Text( 'US Pay Period Deductions...', __FILE__, __LINE__, __METHOD__, 10 );
if ( $pd_obj->isFederalTaxRequired() == true ) {
Debug::Text( ' US State Tax formula requires Federal Taxes as input value...', __FILE__, __LINE__, __METHOD__, 10 );
//Need to set Federal settings here.
$udlf = TTnew( 'UserDeductionListFactory' ); /** @var UserDeductionListFactory $udlf */
$udlf->getByUserIdAndCalculationIdAndCountryID( $user_id, 100, $cd_obj->getCountry() );
if ( $udlf->getRecordCount() > 0 ) {
$tmp_federal_ud_obj = $udlf->getCurrent();
$tmp_user_value1 = $this->Validator->stripNonFloat( ( ( $tmp_federal_ud_obj->getUserValue1() == '' ) ? $tmp_federal_ud_obj->getCompanyDeductionObject()->getUserValue1() : $tmp_federal_ud_obj->getUserValue1() ) );
$tmp_user_value2 = $this->Validator->stripNonFloat( ( ( $tmp_federal_ud_obj->getUserValue2() == '' ) ? $tmp_federal_ud_obj->getCompanyDeductionObject()->getUserValue2() : $tmp_federal_ud_obj->getUserValue2() ) );
$tmp_user_value3 = ( ( $tmp_federal_ud_obj->getUserValue3() == '' ) ? $tmp_federal_ud_obj->getCompanyDeductionObject()->getUserValue3() : $tmp_federal_ud_obj->getUserValue3() ); //UserValue3 is boolean.
$tmp_user_value4 = $this->Validator->stripNonFloat( ( ( $tmp_federal_ud_obj->getUserValue4() == '' ) ? $tmp_federal_ud_obj->getCompanyDeductionObject()->getUserValue4() : $tmp_federal_ud_obj->getUserValue4() ) );
$tmp_user_value5 = $this->Validator->stripNonFloat( ( ( $tmp_federal_ud_obj->getUserValue5() == '' ) ? $tmp_federal_ud_obj->getCompanyDeductionObject()->getUserValue5() : $tmp_federal_ud_obj->getUserValue5() ) );
$tmp_user_value6 = $this->Validator->stripNonFloat( ( ( $tmp_federal_ud_obj->getUserValue6() == '' ) ? $tmp_federal_ud_obj->getCompanyDeductionObject()->getUserValue6() : $tmp_federal_ud_obj->getUserValue6() ) );
$tmp_user_value7 = $this->Validator->stripNonFloat( ( ( $tmp_federal_ud_obj->getUserValue7() == '' ) ? $tmp_federal_ud_obj->getCompanyDeductionObject()->getUserValue7() : $tmp_federal_ud_obj->getUserValue7() ) );
$tmp_user_value9 = ( ( $tmp_federal_ud_obj->getUserValue9() == '' ) ? $tmp_federal_ud_obj->getCompanyDeductionObject()->getUserValue9() : $tmp_federal_ud_obj->getUserValue9() );
Debug::Text( ' Found Federal User Deduction... Total Records: ' . $udlf->getRecordCount() . ' TmpUserValue1: ' . $tmp_user_value1 . ' TmpUserValue2: ' . $tmp_user_value2 .' TmpUserValue9: '. $tmp_user_value9, __FILE__, __LINE__, __METHOD__, 10 );
$pd_obj->setFederalFormW4Version( $tmp_user_value9 );
$pd_obj->setFederalFilingStatus( $tmp_user_value1 );
$pd_obj->setFederalAllowance( $tmp_user_value2 );
$pd_obj->setFederalMultipleJobs( ( ( (int)$tmp_user_value3 >= 1 ) ? true : false ) );
$pd_obj->setFederalClaimDependents( $tmp_user_value4 );
$pd_obj->setFederalOtherIncome( $tmp_user_value5 );
$pd_obj->setFederalDeductions( $tmp_user_value6 );
$pd_obj->setFederalAdditionalDeduction( $tmp_user_value7 );
$pd_obj->setFederalTaxExempt( ( ( (int)$tmp_federal_ud_obj->getUserValue10() >= 1 ) ? true : false ) );
unset( $tmp_federal_ud_obj, $tmp_user_value1, $tmp_user_value2, $tmp_user_value3, $tmp_user_value4, $tmp_user_value5, $tmp_user_value6, $tmp_user_value7, $tmp_user_value9 );
}
unset( $udlf );
}
$user_value1 = $this->Validator->stripNonFloat( $user_value1 );
$user_value2 = $this->Validator->stripNonFloat( $user_value2 );
$user_value3 = $this->Validator->stripNonFloat( $user_value3 );
$pd_obj->setStateFilingStatus( $user_value1 );
$pd_obj->setStateAllowance( $user_value2 );
$pd_obj->setUserValue1( $user_value1 );
$pd_obj->setUserValue2( $user_value2 );
$pd_obj->setUserValue3( $user_value3 );
if ( (int)$this->getUserValue10() >= 1 ) {
$pd_obj->setProvincialTaxExempt( true );
}
$retval = $pd_obj->getStatePayPeriodDeductions();
}
if ( $retval < 0 ) {
$retval = 0;
}
break;
case 300: //District Income Tax
$user_value1 = ( ( $this->getUserValue1() == '' ) ? $cd_obj->getUserValue1() : $this->getUserValue1() );
$user_value2 = ( ( $this->getUserValue2() == '' ) ? $cd_obj->getUserValue2() : $this->getUserValue2() );
$user_value3 = ( ( $this->getUserValue3() == '' ) ? $cd_obj->getUserValue3() : $this->getUserValue3() );
Debug::Text( 'UserValue: 1: ' . $user_value1 . ' 2: ' . $user_value2 . ' 3: ' . $user_value3, __FILE__, __LINE__, __METHOD__, 10 );
$amount = $cd_obj->getCalculationPayStubAmount( $pay_stub_obj );
Debug::Text( 'Amount: '. $amount .' Annual Pay Periods: ' . $annual_pay_periods .' Current PP: '. $current_pay_period . 'District: ' . $cd_obj->getDistrict(), __FILE__, __LINE__, __METHOD__, 10 );
$pd_obj = new PayrollDeduction( $cd_obj->getCountry(), $cd_obj->getProvince(), $cd_obj->getDistrict() );
$pd_obj->setCompany( $this->getUserObject()->getCompany() );
$pd_obj->setUser( $this->getUser() );
$pd_obj->setDate( $pay_stub_obj->getTransactionDate() );
$pd_obj->setAnnualPayPeriods( $annual_pay_periods );
$pd_obj->setCurrentPayPeriod( $current_pay_period );
$pd_obj->setHireAdjustedAnnualPayPeriods( $hire_adjusted_annual_pay_periods );
$pd_obj->setHireAdjustedCurrentPayPeriod( $hire_adjusted_current_pay_period );
$pd_obj->setCurrentPayrollRunID( $payroll_run_id );
$pd_obj->setFormulaType( $formula_type_id );
$pd_obj->setDistrictFilingStatus( $user_value1 );
$pd_obj->setDistrictAllowance( $user_value2 );
$pd_obj->setUserValue1( $user_value1 );
$pd_obj->setUserValue2( $user_value2 );
$pd_obj->setUserValue3( $user_value3 );
$pd_obj->setYearToDateGrossIncome( $cd_obj->getCalculationYTDAmount( $pay_stub_obj ) ); //Make sure YTD amount is specified for all calculation types.
$pd_obj->setYearToDateDeduction( $cd_obj->getPayStubEntryAccountYTDAmount( $pay_stub_obj ) ); //Make sure YTD amount is specified for all calculation types.
$pd_obj->setGrossPayPeriodIncome( $amount );
$retval = $pd_obj->getDistrictPayPeriodDeductions();
if ( $retval < 0 ) {
$retval = 0;
}
break;
}
Debug::Text( 'Deduction Amount: ' . $retval, __FILE__, __LINE__, __METHOD__, 10 );
//Allow negative values, as some advanced tax bracket setups require this.
if ( $retval < 0 ) {
//Debug::Text('Deduction was negative, setting to 0...', __FILE__, __LINE__, __METHOD__, 10);
Debug::Text( 'Deduction was negative...', __FILE__, __LINE__, __METHOD__, 10 );
//$retval = 0;
}
return $retval;
}
/**
* Returns the maximum taxable wages for any given calculation formula.
* Returns FALSE for no maximum.
* Primary used in TaxSummary (Generic) report.
* @return bool|mixed
*/
function getMaximumPayStubEntryAccountAmount( $end_date = null ) {
$retval = false;
$cd_obj = $this->getCompanyDeductionObject();
if ( is_object( $cd_obj ) ) {
switch ( $cd_obj->getCalculation() ) {
case 15: //Advanced Percent
if ( $this->getUserValue2() == '' ) {
$wage_base = $cd_obj->getUserValue2();
} else {
$wage_base = $this->getUserValue2();
}
$retval = $this->Validator->stripNonFloat( $wage_base );
break;
case 16: //Advanced Percent (w/Target) -- No maximum
break;
case 17: //Advanced Percent (Range Bracket)
if ( $this->getUserValue3() == '' ) {
$max_wage = $cd_obj->getUserValue3();
} else {
$max_wage = $this->getUserValue3();
}
$retval = $this->Validator->stripNonFloat( $max_wage );
break;
case 18: //Advanced Percent (Tax Bracket)
// Can't use any maximum here, as its calculated on a per pay period basis, therefore it can be different from one pay period to another,
// and when running this report we don't even know how many pay periods there were, how many out-of-cycle pay stubs, or if the pay period schedule changed.
// Closest we could get to it is by calculating the $deducted_amount * ( 1 / $percent ) to get the total wages the withheld amount equals.
// Typically tax brackets tax 100% of earnings anyways, its only an issue if they are using this formula with a hard cap of like $78000/year
//if ( $this->getUserValue2() == '' ) {
// $wage_base = $cd_obj->getUserValue2();
//} else {
// $wage_base = $this->getUserValue2();
//}
//$retval = $this->Validator->stripNonFloat( $wage_base );
break;
case 84: //US - Social Security Formula (Employee)
case 85: //US - Social Security Formula (Employer)
case 89: //US - Federal Unemployment (Employer)
case 210: //US - State Unemployment (Employer)
case 90: //Canada - CPP Formula
case 91: //Canada - EI Formula
require_once( Environment::getBasePath() . DIRECTORY_SEPARATOR . 'classes' . DIRECTORY_SEPARATOR . 'payroll_deduction' . DIRECTORY_SEPARATOR . 'PayrollDeduction.class.php' );
switch ( $cd_obj->getCalculation() ) {
case 84: //US - Social Security Formula (Employee)
case 85: //US - Social Security Formula (Employer)
$pd_obj = new PayrollDeduction( 'US', null );
$pd_obj->setCompany( $cd_obj->getCompany() );
$pd_obj->setDate( $end_date );
$retval = $pd_obj->getSocialSecurityMaximumEarnings();
break;
case 89: //US - Federal Unemployment (Employer)
$pd_obj = new PayrollDeduction( 'US', null );
$pd_obj->setCompany( $cd_obj->getCompany() );
$pd_obj->setDate( $end_date );
$retval = $pd_obj->getFederalUIMaximumEarnings();
break;
case 210: //US - State Unemployment (Employer)
$pd_obj = new PayrollDeduction( 'US', $cd_obj->getProvince() );
$pd_obj->setCompany( $cd_obj->getCompany() );
$pd_obj->setDate( $end_date );
$retval = $pd_obj->getStateUIWageBase();
break;
case 90: //Canada - CPP Formula
$pd_obj = new PayrollDeduction( 'CA', null );
$pd_obj->setCompany( $cd_obj->getCompany() );
$pd_obj->setDate( $end_date );
$retval = $pd_obj->getCPPMaximumEarnings();
break;
case 91: //Canada - EI Formula
$pd_obj = new PayrollDeduction( 'CA', null );
$pd_obj->setCompany( $cd_obj->getCompany() );
$pd_obj->setDate( $end_date );
$retval = $pd_obj->getEIMaximumEarnings();
break;
}
break;
}
}
return $retval;
}
/**
* Returns the fixed amount rate when specified.
* @return bool|mixed
*/
function getFixedAmount() {
$retval = false;
$cd_obj = $this->getCompanyDeductionObject();
if ( is_object( $cd_obj ) ) {
switch ( $cd_obj->getCalculation() ) {
case 20: //Fixed Amount
case 30: //Fixed Amount (Range Bracket)
case 52: //Fixed Amount (w/Target)
if ( $this->getUserValue1() == '' ) {
$fixed_amount = $cd_obj->getUserValue1();
} else {
$fixed_amount = $this->getUserValue1();
}
$retval = $this->Validator->stripNonFloat( $fixed_amount );
break;
}
}
return $retval;
}
/**
* Returns the percent rate when specified.
* @return bool|mixed
*/
function getRate() {
$retval = false;
$cd_obj = $this->getCompanyDeductionObject();
if ( is_object( $cd_obj ) ) {
switch ( $cd_obj->getCalculation() ) {
case 10: //Percent
case 15: //Advanced Percent
case 16: //Advanced Percent (w/Target)
case 17: //Advanced Percent (Range Bracket)
case 18: //Advanced Percent (Tax Bracket)
case 19: //Advanced Percent (Tax Bracket Alt.)
case 89: //US - Federal Unemployment Insurance
case 210: //US - State Unemployment Insurance
if ( $this->getUserValue1() == '' ) {
$percent = $cd_obj->getUserValue1();
} else {
$percent = $this->getUserValue1();
}
$retval = $this->Validator->stripNonFloat( $percent );
break;
}
}
return $retval;
}
/**
* Migrates UserDeductions as best as it possibly can for an employee when switching legal entities.
* @param $user_obj object
* @param $data_diff array
* @return bool
*/
static function MigrateLegalEntity( $user_obj, $data_diff ) {
//Get all CompanyDeduction records assigned to the new legal entity so we can quickly loop over them multiple times if needed.
$cdlf = TTnew( 'CompanyDeductionListFactory' ); /** @var CompanyDeductionListFactory $cdlf */
$cdlf->StartTransaction();
$cdlf->getByCompanyIdAndLegalEntityId( $user_obj->getCompany(), $user_obj->getLegalEntity() );
$udlf = TTnew( 'UserDeductionListFactory' ); /** @var UserDeductionListFactory $udlf */
$udlf->getByCompanyIdAndUserId( $user_obj->getCompany(), $user_obj->getId() );
if ( $udlf->getRecordCount() > 0 ) {
Debug::text( 'Legal Entity changed. Trying to match all tax/deduction data to new entity for user: ' . $user_obj->getId(), __FILE__, __LINE__, __METHOD__, 10 );
foreach ( $udlf as $ud_obj ) {
$matched_company_deduction_ids = [];
$cd_obj = $ud_obj->getCompanyDeductionObject();
if ( is_object( $cd_obj ) && $cd_obj->getLegalEntity() == TTUUID::getZeroId() ) {
Debug::text( ' Skipping due to no legal entity assigned: ' . $cd_obj->getName() . '(' . $cd_obj->getId() . ')', __FILE__, __LINE__, __METHOD__, 10 );
continue;
}
if ( is_object( $cd_obj ) && $cd_obj->getLegalEntity() == $user_obj->getGenericOldDataValue( 'legal_entity_id' ) ) { //Only convert records assigned to the old legal entity. Skip records not assigned to any legal entity.
//Search for matching CompanyDeduction record to try to re-assign them to.
// Must Match: Calculate Type, Legal Entity -> User Legal Entity, Pay Stub Account
if ( $cdlf->getRecordCount() > 0 ) {
foreach ( $cdlf as $tmp_cd_obj ) {
if ( $cd_obj->getCalculation() == $tmp_cd_obj->getCalculation()
&& $tmp_cd_obj->getLegalEntity() == $user_obj->getLegalEntity()
&& $cd_obj->getPayStubEntryAccount() == $tmp_cd_obj->getPayStubEntryAccount()
) {
Debug::text( ' Legal Entity/Calculation/Pay Stub Account Match Found! Company Deduction: Old: ' . $cd_obj->getName() . '(' . $cd_obj->getId() . ') New: ' . $tmp_cd_obj->getName() . '(' . $tmp_cd_obj->getId() . ')', __FILE__, __LINE__, __METHOD__, 10 );
$matched_company_deduction_ids[$tmp_cd_obj->getId()] = $tmp_cd_obj->getName(); //Use an array, if more than exactly one match, we can't migrate date to it.
} else {
Debug::text( ' NOT a Match... Company Deduction: Old: ' . $cd_obj->getName() . '(' . $cd_obj->getId() . ') New: ' . $tmp_cd_obj->getName() . '(' . $tmp_cd_obj->getId() . ')', __FILE__, __LINE__, __METHOD__, 10 );
}
}
unset( $tmp_cd_obj );
}
}
Debug::text( ' Matches Found (' . count( $matched_company_deduction_ids ) . ')!', __FILE__, __LINE__, __METHOD__, 10 );
if ( count( $matched_company_deduction_ids ) > 1 ) {
$matched_company_deduction_id = Misc::findClosestMatch( $cd_obj->getName(), $matched_company_deduction_ids );
Debug::text( ' Closest Match: ' . $matched_company_deduction_id . ' Searched For: ' . $cd_obj->getName(), __FILE__, __LINE__, __METHOD__, 10 );
} else if ( count( $matched_company_deduction_ids ) == 1 ) {
reset( $matched_company_deduction_ids );
$matched_company_deduction_id = key( $matched_company_deduction_ids );
Debug::text( ' Only one Match: ' . $matched_company_deduction_id, __FILE__, __LINE__, __METHOD__, 10 );
} else {
$matched_company_deduction_id = null;
Debug::text( ' No Match Found (' . count( $matched_company_deduction_ids ) . ')!', __FILE__, __LINE__, __METHOD__, 10 );
}
if ( $matched_company_deduction_id != '' ) {
//Create new UserDeduction record so the audit log shows the employee being removed from one CompanyDeduction record and assigned to another.
$tmp_ud_obj = clone $ud_obj;
$tmp_ud_obj->setId( false );
$tmp_ud_obj->setCompanyDeduction( $matched_company_deduction_id );
if ( $tmp_ud_obj->isValid() ) {
$tmp_ud_obj->Save();
}
unset( $tmp_ud_obj );
}
if ( $cd_obj->getLegalEntity() == TTUUID::getZeroID() && $matched_company_deduction_id == '' ) {
Debug::text( ' No legal entity assigned to Tax/Deduction record, and no match found, so *not* unassigning user from: ' . $cd_obj->getName() . '(' . $cd_obj->getId() . ')', __FILE__, __LINE__, __METHOD__, 10 );
} else {
Debug::text( ' Unassigning user from: ' . $cd_obj->getName() . '(' . $cd_obj->getId() . ')', __FILE__, __LINE__, __METHOD__, 10 );
$ud_obj->setDeleted( true );
if ( $ud_obj->isValid() ) {
$ud_obj->Save();
} else {
Debug::text( ' ERROR! Validation failed when reassigning CompanyDeduction records... Company Deduction: ' . $cd_obj->getName() . '(' . $cd_obj->getId() . ')', __FILE__, __LINE__, __METHOD__, 10 );
}
}
}
}
$cdlf->CommitTransaction();
unset( $udlf, $ud_obj, $cd_obj, $cdlf, $matched_company_deduction_ids );
return true;
}
/**
* @param bool $ignore_warning
* @return bool
*/
function Validate( $ignore_warning = true ) {
//
// BELOW: Validation code moved from set*() functions.
//
// User
$ulf = TTnew( 'UserListFactory' ); /** @var UserListFactory $ulf */
$this->Validator->isResultSetWithRows( 'user',
$ulf->getByID( $this->getUser() ),
TTi18n::gettext( 'Invalid Employee' )
);
// Tax/Deduction
if ( $this->getCompanyDeduction() == TTUUID::getZeroID() ) {
$cdlf = TTnew( 'CompanyDeductionListFactory' ); /** @var CompanyDeductionListFactory $cdlf */
$this->Validator->isResultSetWithRows( 'company_deduction',
$cdlf->getByID( $this->getCompanyDeduction() ),
TTi18n::gettext( 'Tax/Deduction is invalid' )
);
}
// Length Of Service Date
if ( $this->getLengthOfServiceDate() != '' ) {
$this->Validator->isDate( 'length_of_service_date',
$this->getLengthOfServiceDate(),
TTi18n::gettext( 'Incorrect Length Of Service Date' )
);
}
// Start Date
if ( $this->getStartDate() != '' ) {
$this->Validator->isDate( 'start_date',
$this->getStartDate(),
TTi18n::gettext( 'Incorrect Start Date' )
);
}
// End Date
if ( $this->getEndDate() != '' ) {
$this->Validator->isDate( 'end_date',
$this->getEndDate(),
TTi18n::gettext( 'Incorrect End Date' )
);
}
// User Value 1
if ( $this->getUserValue1() != '' ) {
$this->Validator->isLength( 'user_value1',
$this->getUserValue1(),
TTi18n::gettext( 'User Value 1 is too short or too long' ),
1,
20
);
}
// User Value 2
if ( $this->getUserValue2() != '' ) {
$this->Validator->isLength( 'user_value2',
$this->getUserValue2(),
TTi18n::gettext( 'User Value 2 is too short or too long' ),
1,
20
);
}
// User Value 3
if ( $this->getUserValue3() != '' ) {
$this->Validator->isLength( 'user_value3',
$this->getUserValue3(),
TTi18n::gettext( 'User Value 3 is too short or too long' ),
1,
20
);
}
// User Value 4
if ( $this->getUserValue4() != '' ) {
$this->Validator->isLength( 'user_value4',
$this->getUserValue4(),
TTi18n::gettext( 'User Value 4 is too short or too long' ),
1,
20
);
}
// User Value 5
if ( $this->getUserValue5() != '' ) {
$this->Validator->isLength( 'user_value5',
$this->getUserValue5(),
TTi18n::gettext( 'User Value 5 is too short or too long' ),
1,
20
);
}
// User Value 6
if ( $this->getUserValue6() != '' ) {
$this->Validator->isLength( 'user_value6',
$this->getUserValue6(),
TTi18n::gettext( 'User Value 6 is too short or too long' ),
1,
20
);
}
// User Value 7
if ( $this->getUserValue7() != '' ) {
$this->Validator->isLength( 'user_value7',
$this->getUserValue7(),
TTi18n::gettext( 'User Value 7 is too short or too long' ),
1,
20
);
}
// User Value 8
if ( $this->getUserValue8() != '' ) {
$this->Validator->isLength( 'user_value8',
$this->getUserValue8(),
TTi18n::gettext( 'User Value 8 is too short or too long' ),
1,
20
);
}
// User Value 9
if ( $this->getUserValue9() != '' ) {
$this->Validator->isLength( 'user_value9',
$this->getUserValue9(),
TTi18n::gettext( 'User Value 9 is too short or too long' ),
1,
20
);
}
// User Value 10
if ( $this->getUserValue10() != '' ) {
$this->Validator->isLength( 'user_value10',
$this->getUserValue10(),
TTi18n::gettext( 'User Value 10 is too short or too long' ),
1,
20
);
}
//
// ABOVE: Validation code moved from set*() functions.
//
if ( $this->getUser() == false ) {
$this->Validator->isTrue( 'user',
false,
TTi18n::gettext( 'Employee not specified' ) );
}
if ( TTUUID::isUUID( $this->getUser() )
&& $this->getDeleted() == false
&& TTUUID::isUUID( $this->getCompanyDeduction() )
&& is_object( $this->getCompanyDeductionObject() ) ) {
$this->Validator->isTrue( 'company_deduction',
$this->isUniqueCompanyDeduction( $this->getCompanyDeduction() ),
TTi18n::gettext( 'Tax/Deduction is already assigned to employee' ) . ': ' . $this->getCompanyDeductionObject()->getName()
);
}
return true;
}
/**
* @return bool
*/
function preValidate() {
//If the length of service date matches the current hire date, make it blank so we always default to the hire date in case it changes later.
if ( is_object( $this->getUserObject() ) && TTDate::getMiddleDayEpoch( $this->getLengthOfServiceDate() ) == TTDate::getMiddleDayEpoch( $this->getUserObject()->getHireDate() ) ) {
Debug::Text( 'Forcing blank LengthOfServiceDate as it matches hire_date...', __FILE__, __LINE__, __METHOD__, 10 );
$this->setLengthOfServiceDate( null );
}
if ( is_object( $this->getCompanyDeductionObject() ) && $this->getCompanyDeductionObject()->getStartDate() != '' && TTDate::getMiddleDayEpoch( $this->getStartDate() ) == TTDate::getMiddleDayEpoch( $this->getCompanyDeductionObject()->getStartDate() ) ) {
Debug::Text( 'Forcing blank StartDate as it matches Tax/Deduction record...', __FILE__, __LINE__, __METHOD__, 10 );
$this->setStartDate( null );
}
if ( is_object( $this->getCompanyDeductionObject() ) && $this->getCompanyDeductionObject()->getEndDate() != '' && TTDate::getMiddleDayEpoch( $this->getEndDate() ) == TTDate::getMiddleDayEpoch( $this->getCompanyDeductionObject()->getEndDate() ) ) {
Debug::Text( 'Forcing blank EndDate as it matches Tax/Deduction record...', __FILE__, __LINE__, __METHOD__, 10 );
$this->setEndDate( null );
}
return true;
}
/**
* @return bool
*/
function postSave() {
$this->removeCache( $this->getId() );
return true;
}
/**
* @param $data
* @return bool
*/
function setObjectFromArray( $data ) {
if ( is_array( $data ) ) {
$variable_function_map = $this->getVariableToFunctionMap();
foreach ( $variable_function_map as $key => $function ) {
if ( isset( $data[$key] ) ) {
$function = 'set' . $function;
switch ( $key ) {
case 'company_deduction_id':
if ( method_exists( $this, $function ) ) {
$this->$function( $data[$key] );
//As soon as we set the Company Deduction record, parse the UserValues before they are set later on.
if ( is_object( $this->getCompanyDeductionObject() ) ) {
$data = $this->getCompanyDeductionObject()->parseUserValues( $this->getCompanyDeductionObject()->getCalculation(), $data );
}
}
break;
case 'length_of_service_date':
case 'start_date':
case 'end_date':
if ( method_exists( $this, $function ) ) {
$this->$function( TTDate::parseDateTime( $data[$key] ) );
}
break;
default:
if ( method_exists( $this, $function ) ) {
$this->$function( $data[$key] );
}
break;
}
}
}
$this->setCreatedAndUpdatedColumns( $data );
return true;
}
return false;
}
/**
* @param null $include_columns
* @return array
*/
function getObjectAsArray( $include_columns = null ) {
$data = [];
$variable_function_map = $this->getVariableToFunctionMap();
if ( is_array( $variable_function_map ) ) {
$cdf = new CompanyDeductionFactory();
foreach ( $variable_function_map as $variable => $function_stub ) {
if ( $include_columns == null || ( isset( $include_columns[$variable] ) && $include_columns[$variable] == true ) ) {
$function = 'get' . $function_stub;
switch ( $variable ) {
//CompanyDeduction columns.
case 'name':
case 'status_id':
case 'type_id':
case 'calculation_id':
//User columns.
case 'first_name':
case 'last_name':
case 'middle_name':
case 'employee_number':
case 'user_status_id':
$data[$variable] = $this->getColumn( $variable );
break;
case 'user_status':
$uf = TTnew( 'UserFactory' ); /** @var UserFactory $uf */
$data[$variable] = Option::getByKey( $this->getColumn( $variable . '_id' ), $uf->getOptions( 'status' ) );
break;
case 'full_name':
$data[$variable] = Misc::getFullName( $this->getColumn( 'first_name' ), $this->getColumn( 'middle_name' ), $this->getColumn( 'last_name' ), true, true );
break;
//CompanyDeduction columns.
case 'type':
case 'status':
case 'calculation':
$data[$variable] = Option::getByKey( $this->getColumn( $variable . '_id' ), $cdf->getOptions( $variable ) );
break;
case 'length_of_service_date':
case 'start_date':
case 'end_date':
$data[$variable] = TTDate::getAPIDate( 'DATE', $this->$function() );
break;
default:
if ( method_exists( $this, $function ) ) {
$data[$variable] = $this->$function();
}
break;
}
}
}
$this->getCreatedAndUpdatedColumns( $data, $include_columns );
}
return $data;
}
/**
* @param $log_action
* @return bool
*/
function addLog( $log_action ) {
$obj = $this->getUserObject();
if ( is_object( $obj ) ) {
return TTLog::addEntry( $this->getCompanyDeduction(), $log_action, TTi18n::getText( 'Employee Deduction' ) . ': ' . $obj->getFullName(), null, $this->getTable(), $this );
}
return false;
}
}
?>