TimeTrex/classes/modules/install/InstallSchema_1031A.class.php

410 lines
17 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\Install
*/
class InstallSchema_1031A extends InstallSchema_Base {
/**
* @return bool
*/
function preInstall() {
Debug::text( 'preInstall: ' . $this->getVersion(), __FILE__, __LINE__, __METHOD__, 9 );
return true;
}
/**
* @return bool
*/
function postInstall() {
//As of v11 and the switch to UUID, we need to make sure fast_tree_options for the hierarchy_tree is still available for conversion.
global $fast_tree_options, $db;
$fast_tree_options = [ 'db' => $db, 'table' => 'hierarchy_tree' ]; //This is required for upgrading 1031A schema.
Debug::text( 'postInstall: ' . $this->getVersion(), __FILE__, __LINE__, __METHOD__, 9 );
//Go through all pay period schedules and update the annual pay period column
$ppslf = TTnew( 'PayPeriodScheduleListFactory' ); /** @var PayPeriodScheduleListFactory $ppslf */
$ppslf->getAll();
if ( $ppslf->getRecordCount() > 0 ) {
foreach ( $ppslf as $pps_obj ) {
$pps_obj->setAnnualPayPeriods( $pps_obj->calcAnnualPayPeriods() );
if ( $pps_obj->isValid() ) {
$pps_obj->Save();
}
}
}
//Go through all employee wages and update HourlyRate to the accurate annual hourly rate.
//**Handle this in 1034A postInstall() instead, as it needs to handle incorrect effective_dates properly.
/*
$uwlf = TTnew( 'UserWageListFactory' );
$uwlf->getAll();
if ( $uwlf->getRecordCount() > 0 ) {
foreach( $uwlf as $uw_obj ) {
$uw_obj->setHourlyRate( $uw_obj->calcHourlyRate( time(), TRUE ) );
if ( $uw_obj->isValid() ) {
$uw_obj->Save();
}
}
}
*/
//Upgrade to new hierarchy format.
$clf = TTnew( 'CompanyListFactory' ); /** @var CompanyListFactory $clf */
$clf->getAll();
if ( $clf->getRecordCount() > 0 ) {
$object_types = [];
foreach ( $clf as $c_obj ) {
if ( $c_obj->getStatus() != 30 ) {
$company_id = $c_obj->getId();
Debug::Text( ' Company ID: ' . $company_id, __FILE__, __LINE__, __METHOD__, 10 );
$hclf = TTnew( 'HierarchyControlListFactory' ); /** @var HierarchyControlListFactory $hclf */
$hclf->StartTransaction();
$hclf->getByCompanyId( $company_id );
if ( $hclf->getRecordCount() > 0 ) {
foreach ( $hclf as $hc_obj ) {
$paths_to_root = [];
$hierarchy_id = $hc_obj->getId();
$hlf = TTnew( 'HierarchyListFactory' ); /** @var HierarchyListFactory $hlf */
$hierarchy_users = $hlf->getByCompanyIdAndHierarchyControlId( $company_id, $hierarchy_id );
if ( is_array( $hierarchy_users ) && count( $hierarchy_users ) > 0 ) {
$hotlf = TTnew( 'HierarchyObjectTypeListFactory' ); /** @var HierarchyObjectTypeListFactory $hotlf */
$hotlf->getByHierarchyControlId( $hierarchy_id );
if ( $hotlf->getRecordCount() > 0 ) {
foreach ( $hotlf as $hot_obj ) {
//When upgrading from pre. v3.1ish to post 3.5 causing hierarchies to not get carried over due to new object types.
//Replace object_type_id = 50 with new ones in the 1000 range.
if ( $hot_obj->getObjectType() == 50 ) {
$object_types[$hierarchy_id][] = 1010;
$object_types[$hierarchy_id][] = 1020;
$object_types[$hierarchy_id][] = 1030;
$object_types[$hierarchy_id][] = 1040;
$object_types[$hierarchy_id][] = 1100;
} else {
$object_types[$hierarchy_id][] = $hot_obj->getObjectType();
}
}
}
//Not all hierarchies can be converted, and if one error occurs then all hierarchy conversions are rolled back
//to prevent an invalid hierarchy from being created and possibly becoming a security risk.
$parent_groups = [];
foreach ( $hierarchy_users as $hierarchy_user_arr ) {
Debug::Text( ' Checking User ID: ' . $hierarchy_user_arr['id'], __FILE__, __LINE__, __METHOD__, 10 );
$id = $hierarchy_user_arr['id'];
$tmp_id = $id;
$i = 0;
do {
Debug::Text( ' Iteration...', __FILE__, __LINE__, __METHOD__, 10 );
$hlf_b = TTnew( 'HierarchyListFactory' ); /** @var HierarchyListFactory $hlf_b */
$parents = $hlf_b->getParentLevelIdArrayByHierarchyControlIdAndUserId( $hierarchy_id, $tmp_id );
sort( $parents );
$level = ( $hlf_b->getFastTreeObject()->getLevel( $tmp_id ) - 1 );
if ( is_array( $parents ) && count( $parents ) > 0 ) {
$parent_users = [];
foreach ( $parents as $user_id ) {
$parent_users[] = $user_id;
}
$parent_groups[$level] = $parent_users;
unset( $parent_users );
}
if ( isset( $parents[0] ) ) {
$tmp_id = $parents[0];
}
$i++;
} while ( is_array( $parents ) && count( $parents ) > 0 && $i < 100 );
if ( isset( $parent_groups ) ) {
$serialized_path = serialize( $parent_groups );
$paths_to_root[$serialized_path][] = $id;
unset( $serialized_path );
}
unset( $parent_groups, $parents );
}
}
Debug::Arr( $paths_to_root, ' Paths To Root: ', __FILE__, __LINE__, __METHOD__, 10 );
//Decode path_to_root array
if ( isset( $paths_to_root ) && count( $paths_to_root ) > 0 ) {
$decoded_paths = [];
foreach ( $paths_to_root as $serialized_path => $children ) {
$path_arr = unserialize( $serialized_path, [ 'allowed_classes' => false ] );
$decoded_paths[] = [ 'hierarchy_control_id' => $hierarchy_id, 'path' => $path_arr, 'children' => $children ];
}
unset( $path_arr, $children );
Debug::Arr( $decoded_paths, ' Decoded Paths: ', __FILE__, __LINE__, __METHOD__, 10 );
if ( empty( $decoded_paths ) == false ) {
foreach ( $decoded_paths as $decoded_path ) {
Debug::Text( ' Company ID: ' . $company_id, __FILE__, __LINE__, __METHOD__, 10 );
//Create new hierarchy_control
$hcf = TTnew( 'HierarchyControlFactory' ); /** @var HierarchyControlFactory $hcf */
$hcf->setID( $hcf->getNextInsertId() );
$hcf->setCompany( $company_id );
$hcf->setObjectType( $object_types[$decoded_path['hierarchy_control_id']] );
//Generate meaningful name
$name = false;
if ( isset( $decoded_path['path'] ) && is_array( $decoded_path['path'] ) ) {
ksort( $decoded_path['path'] ); //Sort by level.
foreach ( $decoded_path['path'] as $level => $superior_ids ) {
foreach ( $superior_ids as $superior_id ) {
$ulf = TTnew( 'UserListFactory' ); /** @var UserListFactory $ulf */
$ulf->getById( $superior_id );
if ( $ulf->getRecordCount() > 0 ) {
$name[] = $level . '. ' . $ulf->getCurrent()->getFullName();
}
}
}
unset( $level, $superior_ids, $superior_id );
}
if ( isset( $name ) && is_array( $name ) ) {
$name = $hc_obj->getName() . ' ' . implode( ', ', $name ) . ' (#' . rand( 1000, 9999 ) . ')';
} else {
$name = $hc_obj->getName() . ' (#' . rand( 1000, 9999 ) . ')';
}
Debug::Text( 'Hierarchy Control ID: ' . $hcf->getID() . ' Name: ' . $name, __FILE__, __LINE__, __METHOD__, 10 );
$hcf->setName( substr( $name, 0, 249 ) );
$hcf->setDescription( TTi18n::getText( 'Automatically created by TimeTrex' ) );
Debug::Text( 'zHierarchy Control ID: ' . $hcf->getID(), __FILE__, __LINE__, __METHOD__, 10 );
$hcf->setUser( $decoded_path['children'] );
if ( isset( $decoded_path['path'] ) && is_array( $decoded_path['path'] ) ) {
foreach ( $decoded_path['path'] as $level => $superior_ids ) {
foreach ( $superior_ids as $superior_id ) {
$hlf = TTnew( 'HierarchyLevelFactory' ); /** @var HierarchyLevelFactory $hlf */
$hlf->setHierarchyControl( $hcf->getID() );
$hlf->setLevel( $level );
$hlf->setUser( $superior_id );
if ( $hlf->isValid() ) {
$hlf->Save();
Debug::Text( 'Saving Level Row ID... User ID: ' . $superior_id, __FILE__, __LINE__, __METHOD__, 10 );
}
}
}
unset( $level, $superior_ids, $superior_id );
}
if ( $hcf->isValid() ) {
$hcf->Save( true, true );
}
}
}
unset( $decoded_paths );
}
//Delete existing hierarchy control.
$hc_obj->setDeleted( true );
if ( $hc_obj->isValid() == true ) {
$hc_obj->Save();
}
}
}
//$hclf->FailTransaction();
$hclf->CommitTransaction();
}
}
}
//Go through each permission group, and enable break policies for anyone who can see meal policies
$clf = TTnew( 'CompanyListFactory' ); /** @var CompanyListFactory $clf */
$clf->getAll();
if ( $clf->getRecordCount() > 0 ) {
foreach ( $clf as $c_obj ) {
Debug::text( 'Company: ' . $c_obj->getName(), __FILE__, __LINE__, __METHOD__, 9 );
if ( $c_obj->getStatus() != 30 ) {
$pclf = TTnew( 'PermissionControlListFactory' ); /** @var PermissionControlListFactory $pclf */
$pclf->getByCompanyId( $c_obj->getId(), null, null, null, [ 'name' => 'asc' ] ); //Force order to prevent references to columns that haven't been created yet.
if ( $pclf->getRecordCount() > 0 ) {
foreach ( $pclf as $pc_obj ) {
Debug::text( 'Permission Group: ' . $pc_obj->getName(), __FILE__, __LINE__, __METHOD__, 9 );
$plf = TTnew( 'PermissionListFactory' ); /** @var PermissionListFactory $plf */
$plf->getByCompanyIdAndPermissionControlIdAndSectionAndNameAndValue( $c_obj->getId(), $pc_obj->getId(), 'meal_policy', 'enabled', 1 );
if ( $plf->getRecordCount() > 0 ) {
Debug::text( 'Found permission group with meal policy enabled: ' . $plf->getCurrent()->getValue(), __FILE__, __LINE__, __METHOD__, 9 );
$pc_obj->setPermission(
[
'break_policy' => [
'enabled' => true,
'view' => true,
'add' => true,
'edit' => true,
'delete' => true,
],
]
);
} else {
Debug::text( 'Permission group does NOT have meal policy enabled...', __FILE__, __LINE__, __METHOD__, 9 );
}
}
}
}
}
}
//This used to be handled in 1016T postInstall function, but when upgrading really old versions (ie: 2.2.22) of TimeTrex to newer
//ones (ie: 3.3.2) it would fail because new columns have been added to the company_deduction table in schema 1031A.
//Migrate to completely separate Tax / Deductions for social security, as the employee and employer rates are different now.
$clf = TTnew( 'CompanyListFactory' ); /** @var CompanyListFactory $clf */
$clf->getAll();
if ( $clf->getRecordCount() > 0 ) {
foreach ( $clf as $c_obj ) {
Debug::text( 'Company: ' . $c_obj->getName(), __FILE__, __LINE__, __METHOD__, 9 );
if ( $c_obj->getStatus() != 30 && $c_obj->getCountry() == 'US' ) {
//Get PayStub Link accounts
$pseallf = TTnew( 'PayStubEntryAccountLinkListFactory' ); /** @var PayStubEntryAccountLinkListFactory $pseallf */
$pseallf->getByCompanyId( $c_obj->getID() );
if ( $pseallf->getRecordCount() > 0 ) {
$psea_obj = $pseallf->getCurrent();
} else {
Debug::text( 'Failed getting PayStubEntryLink for Company ID: ' . $company_id, __FILE__, __LINE__, __METHOD__, 10 );
continue;
}
$include_pay_stub_accounts = false;
$exclude_pay_stub_accounts = false;
$cdlf = TTnew( 'CompanyDeductionListFactory' ); /** @var CompanyDeductionListFactory $cdlf */
$cdlf->getByCompanyIdAndName( $c_obj->getID(), 'Social Security - Employee' );
if ( $cdlf->getRecordCount() == 1 ) {
$cd_obj = $cdlf->getCurrent();
Debug::text( 'Found SS Employee Tax / Deduction, ID: ' . $c_obj->getID() . ' Percent: ' . $cd_obj->getUserValue1() . ' Wage Base: ' . $cd_obj->getUserValue2(), __FILE__, __LINE__, __METHOD__, 9 );
if ( $cd_obj->getCalculation() == 15 && $cd_obj->getUserValue1() == 6.2 && $cd_obj->getUserValue2() <= 106800 ) {
Debug::text( 'SS Employee Tax / Deduction Matches... Adjusting for 2011...', __FILE__, __LINE__, __METHOD__, 9 );
$cd_obj->setUserValue1( 4.2 );
$cd_obj->setUserValue2( 106800 );
$include_pay_stub_accounts = $cd_obj->getIncludePayStubEntryAccount();
$exclude_pay_stub_accounts = $cd_obj->getExcludePayStubEntryAccount();
$cd_obj->ignore_column_list = true; //Prevents SQL errors due to new columns being added later on.
if ( $cd_obj->isValid() ) {
$cd_obj->Save();
}
}
} else {
Debug::text( 'Failed to find SS Employee Tax / Deduction for Company: ' . $c_obj->getName(), __FILE__, __LINE__, __METHOD__, 9 );
}
unset( $cdlf, $cd_obj );
$cdlf = TTnew( 'CompanyDeductionListFactory' ); /** @var CompanyDeductionListFactory $cdlf */
$cdlf->getByCompanyIdAndName( $c_obj->getID(), 'Social Security - Employer' );
if ( $cdlf->getRecordCount() == 1 ) {
$cd_obj = $cdlf->getCurrent();
Debug::text( 'Found SS Employer Tax / Deduction, ID: ' . $c_obj->getID() . ' Percent: ' . $cd_obj->getUserValue1(), __FILE__, __LINE__, __METHOD__, 9 );
if ( $cd_obj->getCalculation() == 10 && $cd_obj->getUserValue1() == 100 ) {
Debug::text( 'SS Employer Tax / Deduction Matches... Adjusting for 2011...', __FILE__, __LINE__, __METHOD__, 9 );
$cd_obj->setCalculation( 15 );
$cd_obj->setUserValue1( 6.2 );
$cd_obj->setUserValue2( 106800 );
if ( $include_pay_stub_accounts !== false ) {
Debug::text( 'Matching Include/Exclude accounts with SS Employee Entry...', __FILE__, __LINE__, __METHOD__, 9 );
//Match include accounts with SS employee entry.
$cd_obj->setIncludePayStubEntryAccount( $include_pay_stub_accounts );
$cd_obj->setExcludePayStubEntryAccount( $exclude_pay_stub_accounts );
} else {
Debug::text( 'NOT Matching Include/Exclude accounts with SS Employee Entry...', __FILE__, __LINE__, __METHOD__, 9 );
$cd_obj->setIncludePayStubEntryAccount( [ $psea_obj->getTotalGross() ] );
}
$cd_obj->ignore_column_list = true; //Prevents SQL errors due to new columns being added later on.
if ( $cd_obj->isValid() ) {
$cd_obj->Save();
}
}
} else {
Debug::text( 'Failed to find SS Employer Tax / Deduction for Company: ' . $c_obj->getName(), __FILE__, __LINE__, __METHOD__, 9 );
}
}
}
}
//Add MiscDaily cronjob to database.
$cjf = TTnew( 'CronJobFactory' ); /** @var CronJobFactory $cjf */
$cjf->setName( 'MiscDaily' );
$cjf->setMinute( 55 );
$cjf->setHour( 1 );
$cjf->setDayOfMonth( '*' );
$cjf->setMonth( '*' );
$cjf->setDayOfWeek( '*' );
$cjf->setCommand( 'MiscDaily.php' );
$cjf->Save();
//Add MiscWeekly cronjob to database.
$cjf = TTnew( 'CronJobFactory' ); /** @var CronJobFactory $cjf */
$cjf->setName( 'MiscWeekly' );
$cjf->setMinute( 55 );
$cjf->setHour( 1 );
$cjf->setDayOfMonth( '*' );
$cjf->setMonth( '*' );
$cjf->setDayOfWeek( '0' ); //Sunday morning.
$cjf->setCommand( 'MiscWeekly.php' );
$cjf->Save();
return true;
}
}
?>