user_id = $user_id; $this->pay_period_id = $pay_period_id; return true; } /** * @return null */ function getUser() { return $this->user_id; } /** * @return null */ function getPayPeriod() { return $this->pay_period_id; } /** * @return bool */ function getAdvance() { if ( isset( $this->advance ) ) { return $this->advance; } return false; } /** * @param $bool * @return bool */ function setAdvance( $bool ) { $this->advance = $bool; return true; } //Because this class doesn't extend the original Factory class, we have to duplicate the getGenericObject() code here. /** * @return bool|null */ function getUserObject() { if ( isset( $this->user_obj ) && is_object( $this->user_obj ) && $this->getUser() == $this->user_obj->getID() ) { return $this->user_obj; } else { $lf = TTnew( 'UserListFactory' ); /** @var UserListFactory $lf */ $lf->getById( $this->getUser() ); if ( $lf->getRecordCount() == 1 ) { $this->user_obj = $lf->getCurrent(); return $this->user_obj; } return false; } } /** * @return bool|null */ function getPayPeriodObject() { if ( isset( $this->pay_period_obj ) && is_object( $this->pay_period_obj ) && $this->getPayPeriod() == $this->pay_period_obj->getID() ) { return $this->pay_period_obj; } else { $lf = TTnew( 'PayPeriodListFactory' ); /** @var PayPeriodListFactory $lf */ $lf->getById( $this->getPayPeriod() ); if ( $lf->getRecordCount() == 1 ) { $this->pay_period_obj = $lf->getCurrent(); return $this->pay_period_obj; } return false; } } /** * @return bool|null */ function getPayPeriodScheduleObject() { $pay_period_schedule_id = TTUUID::getZeroID(); if ( is_object( $this->getPayPeriodObject() ) ) { $pay_period_schedule_id = $this->getPayPeriodObject()->getPayPeriodSchedule(); } if ( isset( $this->pay_period_schedule_obj ) && is_object( $this->pay_period_schedule_obj ) && $pay_period_schedule_id == $this->pay_period_schedule_obj->getID() ) { return $this->pay_period_schedule_obj; } else { $lf = TTnew( 'PayPeriodScheduleListFactory' ); /** @var PayPeriodScheduleListFactory $lf */ $lf->getById( $pay_period_schedule_id ); if ( $lf->getRecordCount() == 1 ) { $this->pay_period_schedule_obj = $lf->getCurrent(); return $this->pay_period_schedule_obj; } return false; } } /** * @return bool|null */ function getPayStubEntryAccountLinkObject() { $company_id = TTUUID::getZeroID(); if ( is_object( $this->getUserObject() ) ) { $company_id = $this->getUserObject()->getCompany(); } if ( isset( $this->pay_stub_entry_account_link_obj ) && is_object( $this->pay_stub_entry_account_link_obj ) && $company_id == $this->pay_stub_entry_account_link_obj->getCompany() ) { return $this->pay_stub_entry_account_link_obj; } else { $lf = TTnew( 'PayStubEntryAccountLinkListFactory' ); /** @var PayStubEntryAccountLinkListFactory $lf */ $lf->getByCompanyId( $company_id ); if ( $lf->getRecordCount() == 1 ) { $this->pay_stub_entry_account_link_obj = $lf->getCurrent(); return $this->pay_stub_entry_account_link_obj; } return false; } } /** * @param $seconds * @param $rate * @return int|string */ function getWage( $seconds, $rate ) { if ( $seconds == '' || empty( $seconds ) ) { return 0; } if ( $rate == '' || empty( $rate ) ) { return 0; } return bcmul( TTDate::getHours( $seconds ), $rate ); } /** * @param object $user_wage_obj * @return string */ function getMaximumPayPeriodWage( $user_wage_obj ) { if ( is_object( $user_wage_obj ) && is_object( $this->getPayPeriodScheduleObject() ) && $this->getPayPeriodScheduleObject()->getAnnualPayPeriods() > 0 ) { $maximum_pay_period_wage = bcdiv( $user_wage_obj->getAnnualWage(), $this->getPayPeriodScheduleObject()->getAnnualPayPeriods() ); Debug::text( 'Absolute Maximum Pay Period (NO Advance): Wage: ' . $maximum_pay_period_wage . ' User Wage ID: ' . $user_wage_obj->getId() . ' Annual Wage: ' . $user_wage_obj->getAnnualWage() . ' Annual Pay Periods: ' . $this->getPayPeriodScheduleObject()->getAnnualPayPeriods(), __FILE__, __LINE__, __METHOD__, 10 ); } else { Debug::text( 'WARNING: Pay Period Schedule does not exist, or annual pay periods is 0...', __FILE__, __LINE__, __METHOD__, 10 ); $maximum_pay_period_wage = 0; } return $maximum_pay_period_wage; } /** * @return string */ function getPayStubAmendmentEarnings() { //Get pay stub amendments here. $psalf = TTnew( 'PayStubAmendmentListFactory' ); /** @var PayStubAmendmentListFactory $psalf */ if ( $this->getAdvance() == true ) { //For advances, any PS amendment effective BEFORE the advance end date is considered in full. //Any AFTER the advance end date, is considered half. //$pay_period_end_date = $this->getPayPeriodObject()->getAdvanceEndDate(); $advance_pos_sum = $psalf->getAmountSumByUserIdAndTypeIdAndAuthorizedAndStartDateAndEndDate( $this->getUser(), 10, true, $this->getPayPeriodObject()->getStartDate(), $this->getPayPeriodObject()->getAdvanceEndDate() ); Debug::text( 'Pay Stub Amendment Advance Earnings: ' . $advance_pos_sum, __FILE__, __LINE__, __METHOD__, 10 ); $full_pos_sum = $psalf->getAmountSumByUserIdAndTypeIdAndAuthorizedAndStartDateAndEndDate( $this->getUser(), 10, true, $this->getPayPeriodObject()->getAdvanceEndDate(), $this->getPayPeriodObject()->getEndDate() ); Debug::text( 'Pay Stub Amendment Full Earnings: ' . $full_pos_sum, __FILE__, __LINE__, __METHOD__, 10 ); //Take the full amount of PS amendments BEFORE the advance end date, and half of any AFTER the advance end date. //$pos_sum = $advance_pos_sum + ($full_pos_sum / 2); $pos_sum = bcadd( $advance_pos_sum, bcdiv( $full_pos_sum, 2 ) ); } else { $pos_sum = $psalf->getAmountSumByUserIdAndTypeIdAndAuthorizedAndStartDateAndEndDate( $this->getUser(), 10, true, $this->getPayPeriodObject()->getStartDate(), $this->getPayPeriodObject()->getEndDate() ); } //$neg_sum = $psalf->getAmountSumByUserIdAndTypeIdAndTaxExemptAndAuthorizedAndStartDateAndEndDate( $this->getUser(), 20, FALSE, TRUE, $this->getPayPeriodObject()->getStartDate(), $this->getPayPeriodObject()->getEndDate() )*-1; Debug::text( 'Pay Stub Amendment Total Earnings: ' . $pos_sum, __FILE__, __LINE__, __METHOD__, 10 ); return $pos_sum; } /** * @return string */ function getPayStubAmendmentDeductions() { //Get pay stub amendments here. $psalf = TTnew( 'PayStubAmendmentListFactory' ); /** @var PayStubAmendmentListFactory $psalf */ if ( $this->getAdvance() == true ) { //For advances, any PS amendment effective BEFORE the advance end date is considered in full. //Any AFTER the advance end date, is considered half. //$pay_period_end_date = $this->getPayPeriodObject()->getAdvanceEndDate(); $advance_neg_sum = $psalf->getAmountSumByUserIdAndTypeIdAndAuthorizedAndStartDateAndEndDate( $this->getUser(), 20, true, $this->getPayPeriodObject()->getStartDate(), $this->getPayPeriodObject()->getAdvanceEndDate() ); Debug::text( 'Pay Stub Amendment Advance Deductions: ' . $advance_neg_sum, __FILE__, __LINE__, __METHOD__, 10 ); $full_neg_sum = $psalf->getAmountSumByUserIdAndTypeIdAndAuthorizedAndStartDateAndEndDate( $this->getUser(), 20, true, $this->getPayPeriodObject()->getAdvanceEndDate(), $this->getPayPeriodObject()->getEndDate() ); Debug::text( 'Pay Stub Amendment Full Deductions: ' . $full_neg_sum, __FILE__, __LINE__, __METHOD__, 10 ); //Take the full amount of PS amendments BEFORE the advance end date, and half of any AFTER the advance end date. //$neg_sum = $advance_neg_sum + ($full_neg_sum / 2); $neg_sum = bcadd( $advance_neg_sum, bcdiv( $full_neg_sum, 2 ) ); } else { //$pay_period_end_date = $neg_sum = $psalf->getAmountSumByUserIdAndTypeIdAndAuthorizedAndStartDateAndEndDate( $this->getUser(), 20, true, $this->getPayPeriodObject()->getStartDate(), $this->getPayPeriodObject()->getEndDate() ); } //$neg_sum = $psalf->getAmountSumByUserIdAndTypeIdAndTaxExemptAndAuthorizedAndStartDateAndEndDate( $this->getUser(), 20, FALSE, TRUE, $this->getPayPeriodObject()->getStartDate(), $this->getPayPeriodObject()->getEndDate() )*-1; Debug::text( 'Pay Stub Amendment Total Deductions: ' . $neg_sum, __FILE__, __LINE__, __METHOD__, 10 ); return bcmul( $neg_sum, -1 ); } /** * @return int */ function getRawGrossWage() { $wage = 0; $udt_arr = $this->getUserDateTotalArray(); if ( isset( $udt_arr['entries'] ) && count( $udt_arr['entries'] ) > 0 ) { foreach ( $udt_arr['entries'] as $udt ) { if ( isset( $udt['amount'] ) ) { $wage += $udt['amount']; } } } Debug::text( 'Raw Gross Wage: ' . $wage, __FILE__, __LINE__, __METHOD__, 10 ); return $wage; } /** * @return int */ function getGrossWage() { $wage = $this->getRawGrossWage(); Debug::text( 'Gross Wage (NOT incl amendments) $' . $wage, __FILE__, __LINE__, __METHOD__, 10 ); return $wage; } /** * @return array|bool|null */ function getUserDateTotalArray() { if ( isset( $this->user_date_total_arr ) ) { return $this->user_date_total_arr; } //If the user date total array isn't set, set it now, and return its value. return $this->setUserDateTotalArray(); //return FALSE; } /** * @return array|bool */ function setUserDateTotalArray() { $calculate_salary = false; $dock_absence_time = 0; $paid_absence_time = 0; $dock_absence_amount = 0; $paid_absence_amount = 0; $prev_wage_effective_date = 0; $paid_absence_amount_arr = []; $reduce_salary_absence_amount_arr = []; $salary_regular_time = []; $dock_absence_amount_arr = []; $ret_arr = []; //Loop through unique UserDateTotal rows... Adding entries to pay stubs. $udtlf = TTnew( 'UserDateTotalListFactory' ); /** @var UserDateTotalListFactory $udtlf */ $udtlf->getByUserIdAndPayPeriodIdAndEndDate( $this->getUser(), $this->getPayPeriod(), $this->getPayPeriodObject()->getEndDate() ); if ( $udtlf->getRecordCount() > 0 ) { foreach ( $udtlf as $udt_obj ) { Debug::text( 'User Total Row... Object Type: ' . $udt_obj->getObjectType() . ' PayCode ID: ' . $udt_obj->getPayCode() . ' Amount: ' . $udt_obj->getTotalTimeAmount() . ' Hourly Rate: ' . $udt_obj->getColumn( 'hourly_rate' ) . ' Pay Code Type: ' . $udt_obj->getColumn( 'pay_code_type_id' ) . ' User Wage ID: ' . $udt_obj->getColumn( 'user_wage_id' ), __FILE__, __LINE__, __METHOD__, 10 ); if ( $udt_obj->getColumn( 'pay_code_type_id' ) == 10 ) { //Paid if ( $udt_obj->getObjectType() == 25 ) { //Absence Debug::text( 'User Total Row... Absence Time: ' . $udt_obj->getTotalTime(), __FILE__, __LINE__, __METHOD__, 10 ); if ( is_object( $udt_obj->getPayCodeObject() ) && ( $udt_obj->getPayCodeObject()->getType() == 10 || $udt_obj->getPayCodeObject()->getType() == 12 ) && $udt_obj->getPayCodeObject()->getPayStubEntryAccountID() != '' ) { //Paid Debug::text( 'Paid Absence Time: ' . $udt_obj->getTotalTime(), __FILE__, __LINE__, __METHOD__, 10 ); $pay_stub_entry = $udt_obj->getPayCodeObject()->getPayStubEntryAccountID(); $total_time = $udt_obj->getTotalTime(); $rate = $udt_obj->getColumn( 'hourly_rate' ); $amount = $udt_obj->getTotalTimeAmount(); //Debug::text('Paid Absence Info: '. $udt_obj->getTotalTime(), __FILE__, __LINE__, __METHOD__, 10); Debug::text( 'cPay Stub Entry Account ID: ' . $pay_stub_entry . ' Amount: ' . $amount . ' Rate: ' . $rate, __FILE__, __LINE__, __METHOD__, 10 ); $paid_absence_time = bcadd( $paid_absence_time, $udt_obj->getTotalTime() ); $paid_absence_amount = bcadd( $paid_absence_amount, $amount ); //Make sure we add the amount below. Incase there are two or more //entries for a paid absence in the same user_wage_id on one pay stub. if ( !isset( $paid_absence_amount_arr[$udt_obj->getColumn( 'user_wage_id' )] ) ) { $paid_absence_amount_arr[$udt_obj->getColumn( 'user_wage_id' )] = 0; } $paid_absence_amount_arr[$udt_obj->getColumn( 'user_wage_id' )] = bcadd( $paid_absence_amount_arr[$udt_obj->getColumn( 'user_wage_id' )], $amount ); //Some paid absences are over and above employees salary, so we need to track them separately. //So we only reduce the salary of the amount of regular paid absences, not "Paid (Above Salary)" absences. if ( !isset( $reduce_salary_absence_amount_arr[$udt_obj->getColumn( 'user_wage_id' )] ) ) { $reduce_salary_absence_amount_arr[$udt_obj->getColumn( 'user_wage_id' )] = 0; } if ( $udt_obj->getColumn( 'pay_code_type_id' ) == 10 ) { $reduce_salary_absence_amount_arr[$udt_obj->getColumn( 'user_wage_id' )] = bcadd( $reduce_salary_absence_amount_arr[$udt_obj->getColumn( 'user_wage_id' )], $amount ); } } } else { //Check if they are a salary user... //Use WORKED time to calculate regular time. Not just regular time. //user_wage_id is only needed for default wages, so it doesn't take into account pay formulas at all. if ( $udt_obj->getColumn( 'user_wage_type_id' ) > 10 ) { //Salaried //Salary Debug::text( 'Strict Salary Wage: Reduce Regular Pay By: Dock Time: ' . $dock_absence_time . ' and Paid Absence: ' . $paid_absence_time, __FILE__, __LINE__, __METHOD__, 10 ); $calculate_salary = true; if ( !isset( $salary_regular_time[$udt_obj->getColumn( 'user_wage_id' )] ) ) { $salary_regular_time[$udt_obj->getColumn( 'user_wage_id' )] = 0; } //Only include regular time units in salary calculation. if ( $udt_obj->getObjectType() == 20 ) { //Regular Time $salary_regular_time[$udt_obj->getColumn( 'user_wage_id' )] += $udt_obj->getTotalTime(); } } else { //Hourly Debug::text( 'Hourly Wage', __FILE__, __LINE__, __METHOD__, 10 ); $pay_stub_entry = $udt_obj->getPayCodeObject()->getPayStubEntryAccountId(); $total_time = $udt_obj->getTotalTime(); $rate = $udt_obj->getColumn( 'hourly_rate' ); $amount = $udt_obj->getTotalTimeAmount(); Debug::text( 'aPay Stub Entry Account ID: ' . $pay_stub_entry . ' Amount: ' . $amount .' Rate: '. $rate, __FILE__, __LINE__, __METHOD__, 10 ); } } } else if ( $udt_obj->getColumn( 'pay_code_type_id' ) == 12 ) { //Paid Above //This is typically but not always overtime/premium time. if ( is_object( $udt_obj->getPayCodeObject() ) && $udt_obj->getColumn( 'hourly_rate' ) != 0 ) { Debug::text( 'Paid (Above Salary) Time... Rate: ' . $udt_obj->getColumn( 'hourly_rate' ), __FILE__, __LINE__, __METHOD__, 10 ); $pay_stub_entry = $udt_obj->getPayCodeObject()->getPayStubEntryAccountId(); $total_time = $udt_obj->getTotalTime(); $rate = $udt_obj->getColumn( 'hourly_rate' ); $amount = $udt_obj->getTotalTimeAmount(); Debug::text( 'bPay Stub Entry Account ID: ' . $pay_stub_entry . ' Amount: ' . $amount . ' Rate: ' . $rate, __FILE__, __LINE__, __METHOD__, 10 ); } else { Debug::text( ' NOT Paid Time Policy...', __FILE__, __LINE__, __METHOD__, 10 ); } // //We shouldn't do anything with UNPAID pay codes. If there needs to be Tax/Deduction calculations based on unpaid timesheet information, they should be marked as "PAID" but have a $0 hourly rate instead. // //PayStubFactory will still accept $0 amount entries, allow calculations to be made on them, then remove them at the last second though. // } elseif ( $udt_obj->getColumn('pay_code_type_id') == 20 ) { //UnPaid // //Pass through even unpaid time to pay stubs, so Tax/Deduction records can base calculations on just units/hours if needed to create other earnings amounts. // if ( is_object( $udt_obj->getPayCodeObject() ) ) { // Debug::text('UnPaid Time... Total Time: '. $udt_obj->getTotalTime() .' Rate: '. $udt_obj->getColumn('hourly_rate'), __FILE__, __LINE__, __METHOD__, 10); // $pay_stub_entry = $udt_obj->getPayCodeObject()->getPayStubEntryAccountId(); // $total_time = $udt_obj->getTotalTime(); // $rate = $udt_obj->getColumn('hourly_rate'); // $amount = $udt_obj->getTotalTimeAmount(); // Debug::text('cPay Stub Entry Account ID: '. $pay_stub_entry .' Amount: '. $amount .' Rate: '. $rate, __FILE__, __LINE__, __METHOD__, 10); // } else { // Debug::text(' NOT UDT Object...', __FILE__, __LINE__, __METHOD__, 10); // } } else if ( $udt_obj->getColumn( 'pay_code_type_id' ) == 30 ) { //Dock $dock_absence_time = bcadd( $dock_absence_time, $udt_obj->getTotalTime() ); $rate = $udt_obj->getColumn( 'hourly_rate' ); $amount = $this->getWage( $udt_obj->getTotalTime(), $rate ); $dock_absence_amount = bcadd( $dock_absence_amount, $amount ); //Make sure we account for multiple dock absence policies, for the same wage entry in the same pay period. if ( isset( $dock_absence_amount_arr[$udt_obj->getColumn( 'user_wage_id' )] ) ) { $dock_absence_amount_arr[$udt_obj->getColumn( 'user_wage_id' )] += $amount; } else { $dock_absence_amount_arr[$udt_obj->getColumn( 'user_wage_id' )] = $amount; } Debug::text( 'DOCK Absence Time.. Adding: ' . $udt_obj->getTotalTime() . ' Total: ' . $dock_absence_time . ' Rate: ' . $rate, __FILE__, __LINE__, __METHOD__, 10 ); unset( $rate ); } if ( isset( $pay_stub_entry ) && $pay_stub_entry != '' ) { Debug::text( 'zPay Stub Entry Account ID: ' . $pay_stub_entry . ' Amount: ' . $amount, __FILE__, __LINE__, __METHOD__, 10 ); $ret_arr['entries'][] = [ 'user_wage_id' => $udt_obj->getColumn( 'user_wage_id' ), 'pay_stub_entry' => $pay_stub_entry, 'total_time' => $total_time, 'amount' => $amount, 'rate' => $rate, 'description' => null, ]; } unset( $pay_stub_entry, $amount, $total_time, $rate ); } if ( $calculate_salary == true ) { //When the employee is salary and their wage changes in the middle of the pay period and they don't have any regular time worked //in any one of the periods that either wage is effective, the period without any regular time was not being paid before. //Therefore we moved the salary calcuations to the very end and if there is any regular time in the entire pay period //we simply loop through all salaried wages and calculate the pro-rated amounts. Even if no regular time exists in one of the wage periods. Debug::text( 'Calculating Salary...', __FILE__, __LINE__, __METHOD__, 10 ); //Get all wages that apply in this period so we can determine pro-rating for salaries. $uwlf = TTNew( 'UserWageListFactory' ); /** @var UserWageListFactory $uwlf */ $uwlf->getDefaultWageGroupByUserIdAndStartDateAndEndDate( $this->getUser(), $this->getPayPeriodObject()->getStartDate(), $this->getPayPeriodObject()->getEndDate() ); //ORDER BY effective_date desc if ( $uwlf->getRecordCount() > 0 ) { foreach ( $uwlf as $uw_obj ) { $description = null; if ( $uw_obj->getType() != 10 ) { if ( isset( $dock_absence_amount_arr[$uw_obj->getID()] ) ) { $dock_absence_wage = abs( $dock_absence_amount_arr[$uw_obj->getID()] ); //Make sure the dock absence wage is always a positive, since we subtract is below. } else { $dock_absence_wage = 0; } if ( isset( $reduce_salary_absence_amount_arr[$uw_obj->getID()] ) ) { $paid_absence_wage = abs( $reduce_salary_absence_amount_arr[$uw_obj->getID()] ); //Make sure the dock absence wage is always a positive, since we subtract is below. } else { $paid_absence_wage = 0; } Debug::text( 'Wage ID: ' . $uw_obj->getID() . ' Dock Absence Wage: ' . $dock_absence_wage . ' Paid Absence Wage: ' . $paid_absence_wage, __FILE__, __LINE__, __METHOD__, 10 ); $maximum_wage_salary = UserWageFactory::proRateSalary( $this->getMaximumPayPeriodWage( $uw_obj ), $uw_obj->getEffectiveDate(), $prev_wage_effective_date, $this->getPayPeriodObject()->getStartDate(), $this->getPayPeriodObject()->getEndDate(), $this->getUserObject()->getHireDate(), $this->getUserObject()->getTerminationDate() ); $amount = bcsub( $maximum_wage_salary, bcadd( $dock_absence_wage, $paid_absence_wage ) ); //Include time if we have it, otherwise use 0. $total_time = ( isset( $salary_regular_time[$uw_obj->getID()] ) ) ? $salary_regular_time[$uw_obj->getID()] : 0; //Dont minus dock/paid absence time. Because its already not included. $rate = null; $pay_stub_entry = $this->getPayStubEntryAccountLinkObject()->getRegularTime(); unset( $dock_absence_wage, $paid_absence_wage ); $salary_dates = UserWageFactory::proRateSalaryDates( $uw_obj->getEffectiveDate(), $prev_wage_effective_date, $this->getPayPeriodObject()->getStartDate(), $this->getPayPeriodObject()->getEndDate(), $this->getUserObject()->getHireDate(), $this->getUserObject()->getTerminationDate() ); if ( is_array( $salary_dates ) && isset( $salary_dates['percent'] ) && $salary_dates['percent'] < 100 ) { $description = TTi18n::getText( 'Prorate Salary' ) . ': ' . TTDate::getDate( 'DATE', $salary_dates['start_date'] ) . ' - ' . TTDate::getDate( 'DATE', $salary_dates['end_date'] ) . ' (' . $salary_dates['percent'] . '%)'; } if ( isset( $pay_stub_entry ) && $pay_stub_entry != '' ) { Debug::text( ' Pay Stub Entry Account ID: ' . $pay_stub_entry . ' Amount: ' . $amount, __FILE__, __LINE__, __METHOD__, 10 ); $ret_arr['entries'][] = [ 'user_wage_id' => $udt_obj->getColumn( 'user_wage_id' ), 'pay_stub_entry' => $pay_stub_entry, 'total_time' => $total_time, 'amount' => $amount, 'rate' => $rate, 'description' => $description, ]; } unset( $pay_stub_entry, $amount, $total_time, $rate ); } //Must go outside the $uw_obj->getType() != 10 check, so we can properly switch from Salary to Hourly in the middle of a PP. $prev_wage_effective_date = $uw_obj->getEffectiveDate(); } } unset( $uwlf, $uw_obj ); } //Compact entries to minimize line items on pay stubs unless absolutely necessary. if ( isset( $ret_arr['entries'] ) ) { $ret_arr['entries'] = $this->compactUserDateTotalPayStubEntries( $ret_arr['entries'] ); } } else { Debug::text( 'NO UserDate Total entries found.', __FILE__, __LINE__, __METHOD__, 10 ); } $ret_arr['other']['paid_absence_time'] = $paid_absence_time; $ret_arr['other']['dock_absence_time'] = $dock_absence_time; $ret_arr['other']['paid_absence_amount'] = $paid_absence_amount; $ret_arr['other']['dock_absence_amount'] = $dock_absence_amount; if ( empty( $ret_arr ) == false ) { Debug::Arr( $ret_arr, 'UserDateTotal Array', __FILE__, __LINE__, __METHOD__, 10 ); return $this->user_date_total_arr = $ret_arr; } return false; } /** * Compact wage entries that have the same: user_wage_id, pay_stub_entry, rate and description. * This is primarily to avoid having multiple Regular Time entries for each meal/break policy that they have, which can be confusing for some employees. * @param $array * @return array */ function compactUserDateTotalPayStubEntries( $array ) { $retarr = []; if ( is_array( $array ) ) { foreach( $array as $entry_arr ) { $compact_key = md5( $entry_arr['user_wage_id'] . $entry_arr['pay_stub_entry'] . Misc::MoneyRound( $entry_arr['rate'], 4 ) . $entry_arr['description'] ); if ( isset( $retarr[$compact_key] ) ) { //Found matching Wage/PayStubEntry/Rate/Description, simply add total_time and amount to it, rather than create a new entry. $retarr[$compact_key]['total_time'] = bcadd( $retarr[$compact_key]['total_time'], $entry_arr['total_time'] ); $retarr[$compact_key]['amount'] = bcadd( $retarr[$compact_key]['amount'], $entry_arr['amount'] ); } else { $retarr[$compact_key] = $entry_arr; } } } return array_values( $retarr ); } } ?>