923 lines
28 KiB
PHP
923 lines
28 KiB
PHP
|
<?php
|
||
|
/*********************************************************************************
|
||
|
*
|
||
|
* TimeTrex is a Workforce Management program developed by
|
||
|
* TimeTrex Software Inc. Copyright (C) 2003 - 2021 TimeTrex Software Inc.
|
||
|
*
|
||
|
* This program is free software; you can redistribute it and/or modify it under
|
||
|
* the terms of the GNU Affero General Public License version 3 as published by
|
||
|
* the Free Software Foundation with the addition of the following permission
|
||
|
* added to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED
|
||
|
* WORK IN WHICH THE COPYRIGHT IS OWNED BY TIMETREX, TIMETREX DISCLAIMS THE
|
||
|
* WARRANTY OF NON INFRINGEMENT OF THIRD PARTY RIGHTS.
|
||
|
*
|
||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||
|
* FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
||
|
* details.
|
||
|
*
|
||
|
*
|
||
|
* You should have received a copy of the GNU Affero General Public License along
|
||
|
* with this program; if not, see http://www.gnu.org/licenses or write to the Free
|
||
|
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||
|
* 02110-1301 USA.
|
||
|
*
|
||
|
*
|
||
|
* You can contact TimeTrex headquarters at Unit 22 - 2475 Dobbin Rd. Suite
|
||
|
* #292 West Kelowna, BC V4T 2E9, Canada or at email address info@timetrex.com.
|
||
|
*
|
||
|
*
|
||
|
* The interactive user interfaces in modified source and object code versions
|
||
|
* of this program must display Appropriate Legal Notices, as required under
|
||
|
* Section 5 of the GNU Affero General Public License version 3.
|
||
|
*
|
||
|
*
|
||
|
* In accordance with Section 7(b) of the GNU Affero General Public License
|
||
|
* version 3, these Appropriate Legal Notices must retain the display of the
|
||
|
* "Powered by TimeTrex" logo. If the display of the logo is not reasonably
|
||
|
* feasible for technical reasons, the Appropriate Legal Notices must display
|
||
|
* the words "Powered by TimeTrex".
|
||
|
*
|
||
|
********************************************************************************/
|
||
|
|
||
|
|
||
|
/**
|
||
|
* @package Modules\PayStub
|
||
|
*/
|
||
|
class PayStubEntryAccountFactory extends Factory {
|
||
|
protected $table = 'pay_stub_entry_account';
|
||
|
protected $pk_sequence_name = 'pay_stub_entry_account_id_seq'; //PK Sequence name
|
||
|
|
||
|
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 'status':
|
||
|
$retval = [
|
||
|
10 => TTi18n::gettext( 'Enabled' ),
|
||
|
20 => TTi18n::gettext( 'Disabled' ),
|
||
|
];
|
||
|
break;
|
||
|
case 'type':
|
||
|
$retval = [
|
||
|
10 => TTi18n::gettext( 'Earning' ),
|
||
|
20 => TTi18n::gettext( 'Employee Deduction' ),
|
||
|
30 => TTi18n::gettext( 'Employer Deduction' ),
|
||
|
40 => TTi18n::gettext( 'Total' ),
|
||
|
50 => TTi18n::gettext( 'Accrual' ),
|
||
|
//60 => TTi18n::gettext('Advance Earning'),
|
||
|
//65 => TTi18n::gettext('Advance Deduction'),
|
||
|
80 => TTi18n::gettext( 'Miscellaneous' ), //Neither earnings or deductions, just for record keeping, ie: Employer parts of RRSP's, or other items that employees need to see.
|
||
|
|
||
|
];
|
||
|
break;
|
||
|
case 'accrual_type':
|
||
|
$retval = [
|
||
|
//May need to add 6 more options here for every permutation of Add/Subtract across just ER Ded and Misc. Since Earning & ER Deduction should always be opposite.
|
||
|
10 => TTi18n::gettext( 'Earning/Misc Subtracts, EE/ER Deduction Adds' ),
|
||
|
//12 => TTi18n::gettext('Earning/ER Deduction Subtracts, EE Deduction/Misc Adds'),
|
||
|
//14 => TTi18n::gettext('Earning/ER Deduction/Misc Subtracts, EE Deduction Adds'),
|
||
|
//16 => TTi18n::gettext('Earning Subtracts, EE & ER Deduction/Misc Adds'),
|
||
|
20 => TTi18n::gettext( 'Earning/Misc Adds, EE/ER Deduction Subtracts' ),
|
||
|
//22 => TTi18n::gettext('Earning/ER Deduction Adds, EE Deduction/Misc Subtracts'),
|
||
|
//24 => TTi18n::gettext('Earning/ER Deduction/Misc Adds, EE Subtracts'),
|
||
|
//26 => TTi18n::gettext('Earning Adds, EE & ER Deduction/Misc Subtracts'),
|
||
|
];
|
||
|
break;
|
||
|
case 'type_calculation_order':
|
||
|
//If any of these exceed 3 digits, need to update CalculatePayStub->getDeductionObjectSortValue() to handle more digits.
|
||
|
$retval = [
|
||
|
10 => 40,
|
||
|
20 => 50,
|
||
|
30 => 60,
|
||
|
40 => 70,
|
||
|
50 => 30,
|
||
|
60 => 10,
|
||
|
65 => 20,
|
||
|
80 => 65,
|
||
|
];
|
||
|
break;
|
||
|
case 'columns':
|
||
|
$retval = [
|
||
|
'-1010-status' => TTi18n::gettext( 'Status' ),
|
||
|
'-1020-type' => TTi18n::gettext( 'Type' ),
|
||
|
'-1030-name' => TTi18n::gettext( 'Name' ),
|
||
|
|
||
|
'-1140-ps_order' => TTi18n::gettext( 'Order' ),
|
||
|
'-1150-debit_account' => TTi18n::gettext( 'Debit Account' ),
|
||
|
'-1150-credit_account' => TTi18n::gettext( 'Credit Account' ),
|
||
|
|
||
|
'-1900-in_use' => TTi18n::gettext( 'In Use' ),
|
||
|
|
||
|
'-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',
|
||
|
'ps_order',
|
||
|
'debit_account',
|
||
|
'credit_account',
|
||
|
];
|
||
|
break;
|
||
|
case 'unique_columns': //Columns that are unique, and disabled for mass editing.
|
||
|
$retval = [
|
||
|
'name',
|
||
|
];
|
||
|
break;
|
||
|
case 'linked_columns': //Columns that are linked together, mainly for Mass Edit, if one changes, they all must.
|
||
|
$retval = [
|
||
|
'type',
|
||
|
'accrual',
|
||
|
];
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
return $retval;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @param $data
|
||
|
* @return array
|
||
|
*/
|
||
|
function _getVariableToFunctionMap( $data ) {
|
||
|
$variable_function_map = [
|
||
|
'id' => 'ID',
|
||
|
'company_id' => 'Company',
|
||
|
'status_id' => 'Status',
|
||
|
'status' => false,
|
||
|
'type_id' => 'Type',
|
||
|
'type' => false,
|
||
|
'name' => 'Name',
|
||
|
'ps_order' => 'Order',
|
||
|
'debit_account' => 'DebitAccount',
|
||
|
'credit_account' => 'CreditAccount',
|
||
|
'accrual_pay_stub_entry_account_id' => 'Accrual',
|
||
|
'accrual_type_id' => 'AccrualType',
|
||
|
'in_use' => false,
|
||
|
'deleted' => 'Deleted',
|
||
|
];
|
||
|
|
||
|
return $variable_function_map;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @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->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 getCompany() {
|
||
|
return $this->getGenericDataValue( 'company_id' );
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @param string $value UUID
|
||
|
* @return bool
|
||
|
*/
|
||
|
function setCompany( $value ) {
|
||
|
$value = TTUUID::castUUID( $value );
|
||
|
Debug::Text( 'Company ID: ' . $value, __FILE__, __LINE__, __METHOD__, 10 );
|
||
|
|
||
|
return $this->setGenericDataValue( 'company_id', $value );
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @return int
|
||
|
*/
|
||
|
function getStatus() {
|
||
|
return $this->getGenericDataValue( 'status_id' );
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @param $value
|
||
|
* @return bool
|
||
|
*/
|
||
|
function setStatus( $value ) {
|
||
|
$value = (int)trim( $value );
|
||
|
|
||
|
return $this->setGenericDataValue( 'status_id', $value );
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns the order in which accounts should be calculated
|
||
|
* given a circular dependency scenario
|
||
|
* @return bool
|
||
|
*/
|
||
|
function getTypeCalculationOrder() {
|
||
|
if ( $this->getType() !== false ) {
|
||
|
$order_arr = $this->getOptions( 'type_calculation_order' );
|
||
|
|
||
|
if ( isset( $order_arr[$this->getType()] ) ) {
|
||
|
return $order_arr[$this->getType()];
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @param string $id UUID
|
||
|
* @return bool
|
||
|
*/
|
||
|
function isInUse( $id ) {
|
||
|
$pslf = new PayStubListFactory();
|
||
|
$pself = new PayStubEntryListFactory();
|
||
|
$psalf = new PayStubAmendmentListFactory();
|
||
|
|
||
|
$ph = [
|
||
|
'pay_stub_account_id' => (string)$id,
|
||
|
'pay_stub_account_idb' => (string)$id,
|
||
|
];
|
||
|
|
||
|
$query = '
|
||
|
select a.id
|
||
|
from ' . $pself->getTable() . ' as a
|
||
|
LEFT JOIN ' . $pslf->getTable() . ' as b ON ( a.pay_stub_id = b.id )
|
||
|
where a.pay_stub_entry_name_id = ?
|
||
|
AND ( a.deleted = 0 AND b.deleted = 0 )
|
||
|
UNION ALL
|
||
|
select a.id
|
||
|
from ' . $psalf->getTable() . ' as a
|
||
|
where a.pay_stub_entry_name_id = ? AND a.deleted = 0
|
||
|
LIMIT 1';
|
||
|
|
||
|
$retval = $this->db->GetOne( $query, $ph );
|
||
|
Debug::Arr( $retval, 'In Use... ID: ' . $id, __FILE__, __LINE__, __METHOD__, 10 );
|
||
|
|
||
|
if ( $retval === false ) {
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Check to see if this PS account is linked in the PayStubEntryAccountLink so we can prevent it from being deleted if it is.
|
||
|
* @param string $id UUID
|
||
|
* @return bool
|
||
|
*/
|
||
|
function isInPSEAccountLink( $id ) {
|
||
|
$id = (string)$id; //UUID
|
||
|
|
||
|
$pseal_obj = $this->getPayStubEntryAccountLinkObject();
|
||
|
if ( is_object( $pseal_obj ) ) {
|
||
|
if ( in_array( $id, [ (string)$pseal_obj->getRegularTime(), (string)$pseal_obj->getTotalGross(), (string)$pseal_obj->getTotalEmployeeDeduction(), (string)$pseal_obj->getTotalEmployerDeduction(), (string)$pseal_obj->getTotalNetPay() ], true ) ) {
|
||
|
return true;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Check to see if this PS account is linked by another PS account as an accrual.
|
||
|
* @param string $id UUID
|
||
|
* @return bool
|
||
|
*/
|
||
|
function isInPSEAccountAccrual( $id ) {
|
||
|
$psealf = new PayStubEntryAccountListFactory();
|
||
|
|
||
|
$ph = [
|
||
|
'pay_stub_account_id' => (string)$id,
|
||
|
];
|
||
|
|
||
|
$query = '
|
||
|
select a.id
|
||
|
from ' . $psealf->getTable() . ' as a
|
||
|
where a.accrual_pay_stub_entry_account_id = ?
|
||
|
AND ( a.deleted = 0 )
|
||
|
LIMIT 1';
|
||
|
|
||
|
$retval = $this->db->GetOne( $query, $ph );
|
||
|
Debug::Arr( $retval, 'In Use... ID: ' . $id, __FILE__, __LINE__, __METHOD__, 10 );
|
||
|
|
||
|
if ( $retval === false ) {
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @param string $id UUID
|
||
|
* @return bool
|
||
|
*/
|
||
|
function getCurrentType( $id ) {
|
||
|
$psealf = TTNew( 'PayStubEntryAccountListFactory' ); /** @var PayStubEntryAccountListFactory $psealf */
|
||
|
$psealf->getByIdAndCompanyId( $id, $this->getCompany() );
|
||
|
if ( $psealf->getRecordCount() == 1 ) {
|
||
|
$retval = $psealf->getCurrent()->getType();
|
||
|
Debug::Text( 'Current Type: ' . $retval, __FILE__, __LINE__, __METHOD__, 10 );
|
||
|
|
||
|
return $retval;
|
||
|
}
|
||
|
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @return bool|int
|
||
|
*/
|
||
|
function getType() {
|
||
|
return $this->getGenericDataValue( 'type_id' );
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @param $value
|
||
|
* @return bool
|
||
|
*/
|
||
|
function setType( $value ) {
|
||
|
$value = (int)trim( $value );
|
||
|
|
||
|
return $this->setGenericDataValue( 'type_id', $value );
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @param $name
|
||
|
* @return bool
|
||
|
*/
|
||
|
function isUniqueName( $name ) {
|
||
|
$name = trim( $name );
|
||
|
if ( $name == '' ) {
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
$ph = [
|
||
|
'company_id' => TTUUID::castUUID( $this->getCompany() ),
|
||
|
'type_id' => (int)$this->getType(),
|
||
|
'name' => TTi18n::strtolower( $name ),
|
||
|
];
|
||
|
|
||
|
$query = 'select id from ' . $this->getTable() . ' where company_id = ? AND type_id = ? AND lower(name) = ? AND deleted=0';
|
||
|
$id = $this->db->GetOne( $query, $ph );
|
||
|
Debug::Arr( $id, 'Unique Pay Stub Account: ' . $name, __FILE__, __LINE__, __METHOD__, 10 );
|
||
|
|
||
|
if ( $id === false ) {
|
||
|
return true;
|
||
|
} else {
|
||
|
if ( $id == $this->getId() ) {
|
||
|
return true;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @return bool|string
|
||
|
*/
|
||
|
function getName() {
|
||
|
if ( $this->getGenericDataValue( 'name' ) !== false ) {
|
||
|
/*I18n: apply gettext in the result of this function
|
||
|
to be use in the getByIdArray() function in
|
||
|
the PayStubEntryAccountListFactory.class.php
|
||
|
file.
|
||
|
*/
|
||
|
return TTi18n::gettext( $this->getGenericDataValue( 'name' ) );
|
||
|
}
|
||
|
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @param $value
|
||
|
* @return bool
|
||
|
*/
|
||
|
function setName( $value ) {
|
||
|
$value = trim( $value );
|
||
|
|
||
|
return $this->setGenericDataValue( 'name', $value );
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @return bool|mixed
|
||
|
*/
|
||
|
function getOrder() {
|
||
|
return $this->getGenericDataValue( 'ps_order' );
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @param $value
|
||
|
* @return bool
|
||
|
*/
|
||
|
function setOrder( $value ) {
|
||
|
$value = trim( $value );
|
||
|
|
||
|
return $this->setGenericDataValue( 'ps_order', $value );
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @return bool|mixed
|
||
|
*/
|
||
|
function getDebitAccount() {
|
||
|
return $this->getGenericDataValue( 'debit_account' );
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @param $value
|
||
|
* @return bool
|
||
|
*/
|
||
|
function setDebitAccount( $value ) {
|
||
|
$value = trim( $value );
|
||
|
|
||
|
return $this->setGenericDataValue( 'debit_account', $value );
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @return bool|mixed
|
||
|
*/
|
||
|
function getCreditAccount() {
|
||
|
return $this->getGenericDataValue( 'credit_account' );
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @param $value
|
||
|
* @return bool
|
||
|
*/
|
||
|
function setCreditAccount( $value ) {
|
||
|
$value = trim( $value );
|
||
|
|
||
|
return $this->setGenericDataValue( 'credit_account', $value );
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @return bool|mixed
|
||
|
*/
|
||
|
function getAccrual() {
|
||
|
return $this->getGenericDataValue( 'accrual_pay_stub_entry_account_id' );
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @param string $value UUID
|
||
|
* @return bool
|
||
|
*/
|
||
|
function setAccrual( $value ) {
|
||
|
$value = TTUUID::castUUID( $value );
|
||
|
Debug::Text( 'ID: ' . $value, __FILE__, __LINE__, __METHOD__, 10 );
|
||
|
|
||
|
return $this->setGenericDataValue( 'accrual_pay_stub_entry_account_id', $value );
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @return bool|int
|
||
|
*/
|
||
|
function getAccrualType() {
|
||
|
return $this->getGenericDataValue( 'accrual_type_id' );
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @param $value
|
||
|
* @return bool
|
||
|
*/
|
||
|
function setAccrualType( $value ) {
|
||
|
$value = (int)trim( $value );
|
||
|
|
||
|
return $this->setGenericDataValue( 'accrual_type_id', $value );
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @param bool $ignore_warning
|
||
|
* @return bool
|
||
|
*/
|
||
|
function Validate( $ignore_warning = true ) {
|
||
|
//
|
||
|
// BELOW: Validation code moved from set*() functions.
|
||
|
//
|
||
|
// Company
|
||
|
$clf = TTnew( 'CompanyListFactory' ); /** @var CompanyListFactory $clf */
|
||
|
$this->Validator->isResultSetWithRows( 'company',
|
||
|
$clf->getByID( $this->getCompany() ),
|
||
|
TTi18n::gettext( 'Company is invalid' )
|
||
|
);
|
||
|
// Status
|
||
|
if ( $this->getStatus() !== false ) {
|
||
|
$this->Validator->inArrayKey( 'status',
|
||
|
$this->getStatus(),
|
||
|
TTi18n::gettext( 'Incorrect Status' ),
|
||
|
$this->getOptions( 'status' )
|
||
|
);
|
||
|
}
|
||
|
// Type
|
||
|
if ( $this->getType() !== false ) {
|
||
|
$this->Validator->inArrayKey( 'type_id',
|
||
|
$this->getType(),
|
||
|
TTi18n::gettext( 'Incorrect Type' ),
|
||
|
$this->getOptions( 'type' )
|
||
|
);
|
||
|
if ( $this->Validator->isError( 'type_id' ) == false ) {
|
||
|
Debug::Text( 'Type: ' . $this->getType() . ' isNew: ' . (int)$this->isNew(), __FILE__, __LINE__, __METHOD__, 10 );
|
||
|
if ( $this->isNew() == false && $this->getCurrentType( $this->getId() ) != $this->getType() && $this->isInUse( $this->getId() ) == true ) {
|
||
|
$this->Validator->isTrue( 'type_id',
|
||
|
false,
|
||
|
TTi18n::gettext( 'Type cannot be modified when Pay Stub Account is in use' )
|
||
|
);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
// Name
|
||
|
if ( $this->getName() !== false ) {
|
||
|
$this->Validator->isLength( 'name',
|
||
|
$this->getName(),
|
||
|
TTi18n::gettext( 'Name is too short or too long' ),
|
||
|
2,
|
||
|
100
|
||
|
);
|
||
|
if ( $this->Validator->isError( 'name' ) == false ) {
|
||
|
$this->Validator->isTrue( 'name',
|
||
|
$this->isUniqueName( $this->getName() ),
|
||
|
TTi18n::gettext( 'Name is already in use' )
|
||
|
);
|
||
|
}
|
||
|
}
|
||
|
// Order
|
||
|
if ( $this->Validator->getValidateOnly() == false && $this->getOrder() == '' ) {
|
||
|
$this->Validator->isTRUE( 'ps_order',
|
||
|
false,
|
||
|
TTi18n::gettext( 'Order must be specified' )
|
||
|
);
|
||
|
}
|
||
|
if ( $this->getOrder() != '' && $this->Validator->isError( 'ps_order' ) == false ) {
|
||
|
$this->Validator->isNumeric( 'ps_order',
|
||
|
$this->getOrder(),
|
||
|
TTi18n::gettext( 'Invalid Order' )
|
||
|
);
|
||
|
}
|
||
|
// Debit Account
|
||
|
if ( $this->getDebitAccount() != '' ) {
|
||
|
$this->Validator->isLength( 'debit_account',
|
||
|
$this->getDebitAccount(),
|
||
|
TTi18n::gettext( 'Invalid Debit Account' ),
|
||
|
2,
|
||
|
1000
|
||
|
);
|
||
|
}
|
||
|
// Credit Account
|
||
|
if ( $this->getCreditAccount() != '' ) {
|
||
|
$this->Validator->isLength( 'credit_account',
|
||
|
$this->getCreditAccount(),
|
||
|
TTi18n::gettext( 'Invalid Credit Account' ),
|
||
|
2,
|
||
|
1000
|
||
|
);
|
||
|
}
|
||
|
// Accrual Account
|
||
|
if ( $this->getAccrual() !== false && $this->getAccrual() != TTUUID::getZeroID() ) {
|
||
|
$psealf = TTnew( 'PayStubEntryAccountListFactory' ); /** @var PayStubEntryAccountListFactory $psealf */
|
||
|
$psealf->getByID( $this->getAccrual() );
|
||
|
if ( $psealf->getRecordCount() > 0 ) {
|
||
|
if ( $psealf->getCurrent()->getType() != 50 ) {
|
||
|
//Reset Result set so an error occurs.
|
||
|
$psealf = TTnew( 'PayStubEntryAccountListFactory' ); /** @var PayStubEntryAccountListFactory $psealf */
|
||
|
}
|
||
|
}
|
||
|
$this->Validator->isResultSetWithRows( 'accrual_pay_stub_entry_account_id',
|
||
|
$psealf,
|
||
|
TTi18n::gettext( 'Accrual Account is invalid' )
|
||
|
);
|
||
|
}
|
||
|
// Accrual Type
|
||
|
if ( $this->getAccrualType() !== false ) {
|
||
|
$this->Validator->inArrayKey( 'accrual_type_id',
|
||
|
$this->getAccrualType(),
|
||
|
TTi18n::gettext( 'Incorrect Accrual Type' ),
|
||
|
$this->getOptions( 'accrual_type' )
|
||
|
);
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// ABOVE: Validation code moved from set*() functions.
|
||
|
//
|
||
|
|
||
|
if ( $this->getType() == 50 ) {
|
||
|
//If the PSE account is an accrual, it can't link to one as well.
|
||
|
$this->setAccrual( null );
|
||
|
}
|
||
|
|
||
|
//Make sure this account doesn't point to itself as an accrual.
|
||
|
if ( $this->isNew() == false && $this->getAccrual() == $this->getId() ) {
|
||
|
$this->Validator->isTrue( 'accrual',
|
||
|
false,
|
||
|
TTi18n::gettext( 'Accrual account is invalid' )
|
||
|
);
|
||
|
}
|
||
|
|
||
|
if ( $this->getDeleted() == true ) {
|
||
|
if ( $this->getType() == 10 || $this->getType() == 40 ) { //10=Earning (for Regular Time PSA for salaried employees) 40=Total
|
||
|
$this->Validator->isTRUE( 'in_use',
|
||
|
( $this->isInPSEAccountLink( $this->getId() ) == true ? false : true ),
|
||
|
TTi18n::gettext( 'This pay stub account is currently desiginated as a critical system account, unable to delete' ) );
|
||
|
}
|
||
|
|
||
|
if ( $this->getType() == 50 ) { //50=Accrual
|
||
|
$this->Validator->isTRUE( 'in_use',
|
||
|
( $this->isInPSEAccountAccrual( $this->getId() ) == true ? false : true ),
|
||
|
TTi18n::gettext( 'This pay stub account is currently linked to others as an accrual account, unable to delete' ) );
|
||
|
}
|
||
|
|
||
|
//Check to make sure nothing else references this policy, so we can be sure its okay to delete it.
|
||
|
// The isInUse() check in preSave() already looks for pay stubs, pay stub amendments, and if those exist it should never get here.
|
||
|
$pclf = TTnew( 'PayCodeListFactory' ); /** @var PayCodeListFactory $pclf */
|
||
|
$pclf->getByCompanyIdAndPayStubEntryAccountID( $this->getCompany(), $this->getId(), 1 );
|
||
|
if ( $pclf->getRecordCount() > 0 ) {
|
||
|
$this->Validator->isTRUE( 'in_use',
|
||
|
false,
|
||
|
TTi18n::gettext( 'This account is currently in use' ) . ' ' . TTi18n::gettext( 'by pay codes' ) );
|
||
|
}
|
||
|
|
||
|
$cdlf = TTnew( 'CompanyDeductionListFactory' ); /** @var CompanyDeductionListFactory $cdlf */
|
||
|
$cdlf->getByCompanyIdAndPayStubEntryAccountId( $this->getCompany(), $this->getId(), 1 );
|
||
|
if ( $cdlf->getRecordCount() > 0 ) {
|
||
|
$this->Validator->isTRUE( 'in_use',
|
||
|
false,
|
||
|
TTi18n::gettext( 'This account is currently in use' ) . ' ' . TTi18n::gettext( 'by Tax/Deductions' ) );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//Make sure PS order is correct, in that types can't be separated by total or accrual accounts.
|
||
|
if ( $this->getDeleted() == false && $this->getOrder() != '' && $this->Validator->isError( 'ps_order' ) == false ) {
|
||
|
$pseallf = TTnew( 'PayStubEntryAccountLinkListFactory' ); /** @var PayStubEntryAccountLinkListFactory $pseallf */
|
||
|
$pseallf->getByCompanyId( $this->getCompany() );
|
||
|
if ( $pseallf->getRecordCount() > 0 ) {
|
||
|
$pseal_obj = $pseallf->getCurrent();
|
||
|
|
||
|
$psea_map = [];
|
||
|
$psealf = TTnew( 'PayStubEntryAccountListFactory' ); /** @var PayStubEntryAccountListFactory $psealf */
|
||
|
$psealf->getByCompanyIdAndTypeId( $this->getCompany(), 40 );
|
||
|
if ( $psealf->getRecordCount() > 0 ) {
|
||
|
foreach ( $psealf as $psea_obj ) {
|
||
|
$psea_map[$psea_obj->getId()] = $psea_obj->getOrder();
|
||
|
}
|
||
|
unset( $psea_obj );
|
||
|
}
|
||
|
|
||
|
switch ( $this->getType() ) {
|
||
|
case 10: //Earning
|
||
|
//Greater the 0, less then Total Gross Account
|
||
|
if ( isset( $psea_map[$pseal_obj->getTotalGross()] ) ) {
|
||
|
$min_ps_order = 0;
|
||
|
$max_ps_order = $psea_map[$pseal_obj->getTotalGross()];
|
||
|
}
|
||
|
break;
|
||
|
case 20: //EE Deduction
|
||
|
//Greater then Total Gross Account, less then Total Employee Deduction
|
||
|
if ( isset( $psea_map[$pseal_obj->getTotalGross()] ) && isset( $psea_map[$pseal_obj->getTotalEmployeeDeduction()] ) ) {
|
||
|
$min_ps_order = $psea_map[$pseal_obj->getTotalGross()];
|
||
|
$max_ps_order = $psea_map[$pseal_obj->getTotalEmployeeDeduction()];
|
||
|
}
|
||
|
break;
|
||
|
case 30: //ER Deduction
|
||
|
//Greater then Net Pay Account, less then Total Employer Deduction
|
||
|
if ( isset( $psea_map[$pseal_obj->getTotalNetPay()] ) && isset( $psea_map[$pseal_obj->getTotalEmployerDeduction()] ) ) {
|
||
|
$min_ps_order = $psea_map[$pseal_obj->getTotalNetPay()];
|
||
|
$max_ps_order = $psea_map[$pseal_obj->getTotalEmployerDeduction()];
|
||
|
}
|
||
|
break;
|
||
|
case 50: //Accrual
|
||
|
case 80: //Misc
|
||
|
//Greater then Total Employer Deduction
|
||
|
if ( isset( $psea_map[$pseal_obj->getTotalEmployerDeduction()] ) ) {
|
||
|
$min_ps_order = $psea_map[$pseal_obj->getTotalEmployerDeduction()];
|
||
|
$max_ps_order = 10001;
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if ( isset( $min_ps_order ) && isset( $max_ps_order ) && ( $this->getOrder() <= $min_ps_order || $this->getOrder() >= $max_ps_order ) ) {
|
||
|
Debug::text( 'PS Order... Min: ' . $min_ps_order . ' Max: ' . $max_ps_order, __FILE__, __LINE__, __METHOD__, 10 );
|
||
|
$this->Validator->isTrue( 'ps_order',
|
||
|
false,
|
||
|
TTi18n::gettext( 'Order is invalid for this type of account, it must be between' ) . ' ' . ( $min_ps_order + 1 ) . ' ' . TTi18n::gettext( 'and' ) . ' ' . ( $max_ps_order - 1 ) );
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @param string $company_id UUID
|
||
|
* @param string[] $src_ids UUID
|
||
|
* @param string $dst_id UUID
|
||
|
* @param int $effective_date EPOCH
|
||
|
* @return bool
|
||
|
*/
|
||
|
function migrate( $company_id, $src_ids, $dst_id, $effective_date ) {
|
||
|
$dst_id = TTUUID::castUUID( $dst_id );
|
||
|
$src_ids = array_unique( (array)$src_ids );
|
||
|
|
||
|
if ( empty( $dst_id ) || $dst_id == TTUUID::getZeroID() ) {
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
Debug::Arr( $src_ids, 'Attempting to migrate to: ' . $dst_id, __FILE__, __LINE__, __METHOD__, 10 );
|
||
|
|
||
|
$current_epoch = time();
|
||
|
|
||
|
$pself = TTNew( 'PayStubEntryListFactory' ); /** @var PayStubEntryListFactory $pself */
|
||
|
|
||
|
//Loop over just ACTIVE employees.
|
||
|
$ulf = TTNew( 'UserListFactory' ); /** @var UserListFactory $ulf */
|
||
|
|
||
|
//Get names of all Pay Stub Accounts
|
||
|
$psealf = TTNew( 'PayStubEntryAccountListFactory' ); /** @var PayStubEntryAccountListFactory $psealf */
|
||
|
$psealf->getByCompanyId( $company_id );
|
||
|
$pay_stub_account_arr = $psealf->getArrayByListFactory( $psealf, false );
|
||
|
|
||
|
$ulf->StartTransaction();
|
||
|
|
||
|
$ulf->getByCompanyIdAndStatus( $company_id, 10 );
|
||
|
if ( is_array( $pay_stub_account_arr ) && count( $pay_stub_account_arr ) > 0 && $ulf->getRecordCount() > 0 ) {
|
||
|
foreach ( $ulf as $u_obj ) {
|
||
|
//Get current YTD values assigned to the src_ids.
|
||
|
foreach ( $src_ids as $src_id ) {
|
||
|
$pse_row = $pself->getYTDAmountSumByUserIdAndEntryNameIdAndDate( $u_obj->getId(), $src_id, $current_epoch );
|
||
|
if ( isset( $pse_row['amount'] ) && $pse_row['amount'] != 0 ) {
|
||
|
Debug::Text( 'Found existing YTD amount for User ID: ' . $u_obj->getID() . ' PayStubEntryNameID: ' . $src_id . ' Amount: ' . $pse_row['amount'], __FILE__, __LINE__, __METHOD__, 10 );
|
||
|
|
||
|
if ( isset( $pay_stub_account_arr[$dst_id] ) ) {
|
||
|
$from_description = TTi18n::getText( 'Migrated YTD Amount to' ) . ': ' . $pay_stub_account_arr[$dst_id];
|
||
|
} else {
|
||
|
$from_description = TTi18n::getText( 'Migrated YTD Amount to other account' );
|
||
|
}
|
||
|
|
||
|
if ( isset( $pay_stub_account_arr[$src_id] ) ) {
|
||
|
$to_description = TTi18n::getText( 'Migrated YTD Amount from' ) . ': ' . $pay_stub_account_arr[$src_id];
|
||
|
} else {
|
||
|
$to_description = TTi18n::getText( 'Migrated YTD Amount from other account' );
|
||
|
}
|
||
|
Debug::Text( 'Description: From: ' . $from_description . ' To: ' . $to_description, __FILE__, __LINE__, __METHOD__, 10 );
|
||
|
|
||
|
//Create Pay Stub Amendments to reduce current values to 0.
|
||
|
$psaf = TTNew( 'PayStubAmendmentFactory' ); /** @var PayStubAmendmentFactory $psaf */
|
||
|
$psaf->setStatus( 50 );
|
||
|
$psaf->setType( 10 );
|
||
|
$psaf->setUser( $u_obj->getID() );
|
||
|
$psaf->setPayStubEntryNameId( $src_id );
|
||
|
$psaf->setAmount( ( $pse_row['amount'] * -1 ) );
|
||
|
$psaf->setEffectiveDate( $effective_date );
|
||
|
$psaf->setDescription( $from_description );
|
||
|
if ( $psaf->isValid() ) {
|
||
|
$psaf->Save();
|
||
|
}
|
||
|
|
||
|
//Create Pay Stub Amendments to copy amounts to new dst_id
|
||
|
$psaf = TTNew( 'PayStubAmendmentFactory' ); /** @var PayStubAmendmentFactory $psaf */
|
||
|
$psaf->setStatus( 50 );
|
||
|
$psaf->setType( 10 );
|
||
|
$psaf->setUser( $u_obj->getID() );
|
||
|
$psaf->setPayStubEntryNameId( $dst_id );
|
||
|
$psaf->setAmount( $pse_row['amount'] );
|
||
|
$psaf->setEffectiveDate( $effective_date );
|
||
|
$psaf->setDescription( $to_description );
|
||
|
if ( $psaf->isValid() ) {
|
||
|
$psaf->Save();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
$ulf->CommitTransaction();
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
|
||
|
/**
|
||
|
* @return bool
|
||
|
*/
|
||
|
function preSave() {
|
||
|
if ( $this->getDeleted() == true ) {
|
||
|
//Validate() checks for pay codes, Tax/Deductions etc...
|
||
|
Debug::text( 'Attempting to delete PSE Account', __FILE__, __LINE__, __METHOD__, 10 );
|
||
|
if ( $this->isInUse( $this->getId() ) ) {
|
||
|
Debug::text( 'PSE Account is in use by Pay Stubs... Disabling instead.', __FILE__, __LINE__, __METHOD__, 10 );
|
||
|
$this->setDeleted( false ); //Can't delete, account is in use.
|
||
|
$this->setStatus( 20 ); //Disable instead
|
||
|
} else {
|
||
|
Debug::text( 'aPSE Account is NOT in use... Deleting...', __FILE__, __LINE__, __METHOD__, 10 );
|
||
|
}
|
||
|
} else {
|
||
|
if ( $this->getAccrualType() == '' ) {
|
||
|
$this->setAccrualType( 10 );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
function postSave() {
|
||
|
$this->removeCache( $this->getId() );
|
||
|
$this->removeCache( null, $this->getTable( true ) . $this->getCompany() ); //PayStubEntryAccountListFactory has several functions that cache data in this group, so clear them all.
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @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 ) {
|
||
|
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 ) {
|
||
|
$variable_function_map = $this->getVariableToFunctionMap();
|
||
|
$data = [];
|
||
|
if ( is_array( $variable_function_map ) ) {
|
||
|
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 ) {
|
||
|
case 'in_use':
|
||
|
$data[$variable] = $this->getColumn( $variable );
|
||
|
break;
|
||
|
case 'status':
|
||
|
case 'type':
|
||
|
case 'accrual_type':
|
||
|
$function = 'get' . $variable;
|
||
|
if ( method_exists( $this, $function ) ) {
|
||
|
$data[$variable] = Option::getByKey( $this->$function(), $this->getOptions( $variable ) );
|
||
|
}
|
||
|
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 ) {
|
||
|
return TTLog::addEntry( $this->getId(), $log_action, TTi18n::getText( 'Pay Stub Account' ), null, $this->getTable(), $this );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
?>
|