TTi18n::gettext( 'Pay Multiplied By Factor' ), //20 => TTi18n::gettext('Premium Only'), //Just the specified premium amount. This is now #32 though as that makes more sense. 30 => TTi18n::gettext( 'Flat Hourly Rate (Relative to Wage)' ), //This is a relative rate based on their hourly rate. 32 => TTi18n::gettext( 'Flat Hourly Rate' ), //NOT relative to their default rate. 34 => TTi18n::gettext( 'Flat Hourly Rate (w/Default)' ), //Uses the hourly rate in the pay formula as the default, unless a wage record exists, then it uses that instead, even if its lower or higher. 40 => TTi18n::gettext( 'Minimum Hourly Rate (Relative to Wage)' ), //Pays whichever is greater, this rate or the employees original rate. 42 => TTi18n::gettext( 'Minimum Hourly Rate' ), //Pays whichever is greater, this rate or the employees original rate. 50 => TTi18n::gettext( 'Pay + Premium' ), ]; if ( $product_edition_id >= TT_PRODUCT_PROFESSIONAL ) { //These require wage_source_type=30, which is professional edition or higher. $retval[60] = TTi18n::gettext( 'Daily Flat Rate (w/Default)' ); //Uses the hourly (daily) rate in the pay formula as the default, unless a wage record exists, then it uses that instead, even if its lower or higher. $retval[70] = TTi18n::gettext( 'Daily Average Rate' ); } if ( $product_edition_id >= TT_PRODUCT_CORPORATE ) { //These require wage_source_type=30, which is professional edition or higher. $retval[200] = TTi18n::gettext( 'Piece Rate (per Good Quantity)' ); //$retval[210] = TTi18n::gettext( 'Piece Rate w/Minimum Hourly Rate (Relative to Wage)' ); //Use the employees wage as their minimum hourly rate. //900 => TTi18n::gettext('Custom Formula'), //Can be used to calculate piece work rates. } break; case 'wage_source_type': //Used to calculate wages based on inputs other than just their wage record. //For example if an employee works in two different departments at two different rates, average them then calculate OT on the average. // This should help cut down on requiring a ton of OT policies for each different rate of pay the employee can get. // //****PAY CODES HAVE TO CALCULATE PAY, SO THEY CAN BE MANUALLY ENTERED DIRECTLY FROM A MANUAL TIMESHEET. // Have two levels of rate calculations, so the premium policy can calculate its own rate, then pass it off to the pay code, which can do additional calculations. // For Chesapeake, they would only need different pay codes for Regular Rate, then OT would all be based on that, so it actually wouldn't be that bad. //Label: Obtain Hourly Rate From: $retval = [ 10 => TTi18n::gettext( 'Wage Group' ), //"Code" is singular, as it can just be one. Input pay code calculation // This is basically the source policy(?) 20 => TTi18n::gettext( 'Contributing Pay Code' ), ]; if ( $product_edition_id >= TT_PRODUCT_PROFESSIONAL ) { //Required to calculate US federal OT rates that include premium time. //But what date range is the average over? Daily, Weekly, Per Pay Period? $retval[30] = TTi18n::gettext( 'Average of Contributing Pay Codes' ); //Input pay code average calculation //For cases where the contract rate may be lower than the FLSA rate, in which case FLSA needs to be used. //But in some cases the contract rate may be higher then it needs to be used. //http://docs.oracle.com/cd/E13053_01/hr9pbr1_website_master/eng/psbooks/hpay/chapter.htm?File=hpay/htm/hpay38.htm //40 => TTi18n::gettext('Higher of the Contributing Pay Code or Average'), } break; case 'columns': $retval = [ '-1010-name' => TTi18n::gettext( 'Name' ), '-1020-description' => TTi18n::gettext( 'Description' ), '-1100-pay_type' => TTi18n::gettext( 'Pay Type' ), '-1110-rate' => TTi18n::gettext( 'Rate' ), '-1120-accrual_rate' => TTi18n::gettext( 'Accrual Rate' ), '-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 = [ 'name', 'description', 'updated_date', 'updated_by', ]; break; case 'unique_columns': //Columns that are unique, and disabled for mass editing. $retval = [ 'name', ]; break; } return $retval; } /** * @param $data * @return array */ function _getVariableToFunctionMap( $data ) { $variable_function_map = [ 'id' => 'ID', 'company_id' => 'Company', 'name' => 'Name', 'description' => 'Description', 'wage_source_type_id' => 'WageSourceType', 'wage_source_type' => false, 'wage_source_contributing_shift_policy_id' => 'WageSourceContributingShiftPolicy', 'wage_source_contributing_shift_policy' => false, 'time_source_contributing_shift_policy_id' => 'TimeSourceContributingShiftPolicy', 'time_source_contributing_shift_policy' => false, 'average_days' => 'AverageDays', 'pay_type_id' => 'PayType', 'pay_type' => false, 'rate' => 'Rate', 'wage_group_id' => 'WageGroup', 'accrual_rate' => 'AccrualRate', 'accrual_policy_account_id' => 'AccrualPolicyAccount', 'accrual_balance_threshold' => 'AccrualBalanceThreshold', 'accrual_balance_threshold_fallback_accrual_policy_account_id' => 'AccrualBalanceThresholdFallbackAccrualPolicyAccount', 'in_use' => false, 'deleted' => 'Deleted', ]; return $variable_function_map; } /** * @return bool */ function getCompanyObject() { return $this->getGenericObject( 'CompanyListFactory', $this->getCompany(), 'company_obj' ); } /** * @return bool */ function getAccrualPolicyAccountObject() { return $this->getGenericObject( 'AccrualPolicyAccountListFactory', $this->getAccrualPolicyAccount(), 'accrual_policy_account_obj' ); } /** * @return bool */ function getAccrualBalanceThresholdFallbackAccrualPolicyAccountObject() { return $this->getGenericObject( 'AccrualPolicyAccountListFactory', $this->getAccrualBalanceThresholdFallbackAccrualPolicyAccount(), 'accrual_balance_threshold_fallback_accrual_policy_account_obj' ); } /** * @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 ); } /** * @param $name * @return bool */ function isUniqueName( $name ) { $name = trim( $name ); if ( $name == '' ) { return false; } $ph = [ 'company_id' => TTUUID::castUUID( $this->getCompany() ), 'name' => TTi18n::strtolower( $name ), ]; $query = 'select id from ' . $this->getTable() . ' where company_id = ? AND lower(name) = ? AND deleted=0'; $id = $this->db->GetOne( $query, $ph ); Debug::Arr( $id, 'Unique: ' . $name, __FILE__, __LINE__, __METHOD__, 10 ); if ( $id === false ) { return true; } else { if ( $id == $this->getId() ) { return true; } } return false; } /** * @return bool|mixed */ function getName() { return $this->getGenericDataValue( 'name' ); } /** * @param $value * @return bool */ function setName( $value ) { $value = trim( $value ); return $this->setGenericDataValue( 'name', $value ); } /** * @return bool|mixed */ function getDescription() { return $this->getGenericDataValue( 'description' ); } /** * @param $value * @return bool */ function setDescription( $value ) { $value = trim( $value ); return $this->setGenericDataValue( 'description', $value ); } /** * @return bool|mixed */ function getCode() { return $this->getGenericDataValue( 'code' ); } /** * @param $value * @return bool */ function setCode( $value ) { $value = trim( $value ); return $this->setGenericDataValue( 'code', $value ); } /** * @return bool|int */ function getPayType() { return $this->getGenericDataValue( 'pay_type_id' ); } /** * @param $value * @return bool */ function setPayType( $value ) { $value = (int)trim( $value ); return $this->setGenericDataValue( 'pay_type_id', $value ); } /** * @return bool|int */ function getWageSourceType() { return $this->getGenericDataValue( 'wage_source_type_id' ); } /** * @param $value * @return bool */ function setWageSourceType( $value ) { $value = (int)trim( $value ); return $this->setGenericDataValue( 'wage_source_type_id', $value ); } /** * @return bool|mixed */ function getWageSourceContributingShiftPolicy() { return $this->getGenericDataValue( 'wage_source_contributing_shift_policy_id' ); } /** * @param string $value UUID * @return bool */ function setWageSourceContributingShiftPolicy( $value ) { $value = TTUUID::castUUID( $value ); return $this->setGenericDataValue( 'wage_source_contributing_shift_policy_id', $value ); } /** * @return bool|mixed */ function getTimeSourceContributingShiftPolicy() { return $this->getGenericDataValue( 'time_source_contributing_shift_policy_id' ); } /** * @param string $value UUID * @return bool */ function setTimeSourceContributingShiftPolicy( $value ) { $value = TTUUID::castUUID( $value ); return $this->setGenericDataValue( 'time_source_contributing_shift_policy_id', $value ); } /** * @return bool|mixed */ function getAverageDays() { return $this->getGenericDataValue( 'average_days' ); } /** * @param $value * @return bool */ function setAverageDays( $value ) { $value = (int)trim( $value ); return $this->setGenericDataValue( 'average_days', $value ); } /** * @param $original_hourly_rate * @return bool|int|mixed */ function getHourlyRate( $original_hourly_rate, $udtf = null ) { //Debug::text(' Getting Rate based off Hourly Rate: '. $original_hourly_rate .' Pay Type: '. $this->getPayType(), __FILE__, __LINE__, __METHOD__, 10); $rate = 0; switch ( $this->getPayType() ) { case 10: //Pay Factor //Since they are already paid for this time with regular or OT, minus 1 from the rate $rate = bcmul( $original_hourly_rate, $this->getRate() ); break; case 30: //Flat Hourly Rate (Relative) //Get the difference between the employees current wage and the original wage. $rate = bcsub( $this->getRate(), $original_hourly_rate ); break; //case 20: //Was Premium Only, but its really the same as Flat Hourly Rate (NON relative) case 32: //Flat Hourly Rate (NON relative) //This should be original_hourly_rate, which is typically related to the users wage/wage group, so they can pay whatever is defined there. //If they want to pay a flat hourly rate specified in the pay code use Pay Plus Premium instead. //$rate = $original_hourly_rate; //In v7 this was the above, which isn't correct and unexpected for the user. $rate = $this->getRate(); break; case 34: //Flat Hourly Rate (w/Default) //If a wage record ($original_hourly_rate) is specified, use it, otherwise use the default flat hourly rate specified in the pay formula policy. if ( $original_hourly_rate != 0 ) { $rate = $original_hourly_rate; } else { $rate = $this->getRate(); } break; case 40: //Minimum/Prevailing wage (relative) if ( $this->getRate() > $original_hourly_rate ) { $rate = bcsub( $this->getRate(), $original_hourly_rate ); } else { $rate = 0; } break; case 42: //Minimum/Prevailing wage (NON relative) if ( $this->getRate() > $original_hourly_rate ) { $rate = $this->getRate(); } else { //Use the original rate rather than 0, since this is non-relative its likely //that the employee is just getting paid from pay codes, so if they are getting //paid more than the pay code states, without this they would get paid nothing. //This allows pay codes like "Painting (Regular)" to actually have wages associated with them. $rate = $original_hourly_rate; } break; case 50: //Pay Plus Premium $rate = bcadd( $original_hourly_rate, $this->getRate() ); break; case 60: //Daily Flat Rate (w/Default) case 70: //Daily Average Rate //If a wage record ($original_hourly_rate) is specified, use it, otherwise use the default flat hourly rate specified in the pay formula policy. if ( $original_hourly_rate != 0 ) { $rate = $original_hourly_rate; } else { $rate = 0; } break; case 200: //Piece Rate (Good Quantity) if ( is_object( $udtf ) && $udtf->getTotalTime() != 0 && $udtf->getQuantity() != 0 ) { $rate = bcdiv( bcmul( $this->getRate(), $udtf->getQuantity() ), TTDate::getHours( $udtf->getTotalTime() ) ); } else { $rate = 0; } break; default: Debug::text( ' ERROR: Invalid Pay Type: ' . $this->getPayType(), __FILE__, __LINE__, __METHOD__, 10 ); break; } //Don't round rate, as some currencies accept more than 2 decimal places now. //and all wages support up to 4 decimal places too. //return Misc::MoneyRound($rate); //Debug::text(' Final Rate: '. $rate, __FILE__, __LINE__, __METHOD__, 10); return $rate; } /** * @return bool|mixed */ function getRate() { return $this->getGenericDataValue( 'rate' ); } /** * @param $value * @return bool */ function setRate( $value ) { $value = trim( $value ); return $this->setGenericDataValue( 'rate', $value ); } /** * @return bool|mixed */ function getWageGroup() { return $this->getGenericDataValue( 'wage_group_id' ); } /** * @param string $value UUID * @return bool */ function setWageGroup( $value ) { $value = TTUUID::castUUID( $value ); return $this->setGenericDataValue( 'wage_group_id', $value ); } /** * @return bool|mixed */ function getAccrualRate() { return $this->getGenericDataValue( 'accrual_rate' ); } /** * @param $value * @return bool */ function setAccrualRate( $value ) { $value = trim( $value ); return $this->setGenericDataValue( 'accrual_rate', $value ); } /** * @return bool|mixed */ function getAccrualPolicyAccount() { return $this->getGenericDataValue( 'accrual_policy_account_id' ); } /** * @param string $value UUID * @return bool */ function setAccrualPolicyAccount( $value ) { $value = TTUUID::castUUID( $value ); return $this->setGenericDataValue( 'accrual_policy_account_id', $value ); } /** * @return bool|mixed */ function getAccrualBalanceThreshold() { return $this->getGenericDataValue( 'accrual_balance_threshold' ); } /** * @param $value * @return bool */ function setAccrualBalanceThreshold( $value ) { $value = trim( $value ); return $this->setGenericDataValue( 'accrual_balance_threshold', (int)$this->Validator->stripNon32bitInteger( $value ) ); } /** * @return bool|mixed */ function getAccrualBalanceThresholdFallbackAccrualPolicyAccount() { return $this->getGenericDataValue( 'accrual_balance_threshold_fallback_accrual_policy_account_id' ); } /** * @param string $value UUID * @return bool */ function setAccrualBalanceThresholdFallbackAccrualPolicyAccount( $value ) { $value = TTUUID::castUUID( $value ); return $this->setGenericDataValue( 'accrual_balance_threshold_fallback_accrual_policy_account_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' ) ); // Name if ( $this->Validator->getValidateOnly() == false ) { //Don't check the below when mass editing. if ( $this->getName() == '' ) { $this->Validator->isTRUE( 'name', false, TTi18n::gettext( 'Please specify a name' ) ); } } if ( $this->getName() != '' && $this->Validator->isError( 'name' ) == false ) { $this->Validator->isLength( 'name', $this->getName(), TTi18n::gettext( 'Name is too short or too long' ), 2, 100 ); //Needs to be long enough for upgrade procedure when converting from other policies. } if ( $this->getName() != '' && $this->Validator->isError( 'name' ) == false ) { $this->Validator->isTrue( 'name', $this->isUniqueName( $this->getName() ), TTi18n::gettext( 'Name is already in use' ) ); } // Description if ( $this->getDescription() != '' ) { $this->Validator->isLength( 'description', $this->getDescription(), TTi18n::gettext( 'Description is invalid' ), 1, 250 ); } // Code if ( $this->getCode() !== false ) { $this->Validator->isLength( 'code', $this->getCode(), TTi18n::gettext( 'Code is too short or too long' ), 2, 50 ); } // Pay Type if ( $this->getPayType() !== false ) { $this->Validator->inArrayKey( 'pay_type_id', $this->getPayType(), TTi18n::gettext( 'Incorrect Pay Type' ), $this->getOptions( 'pay_type' ) ); } // Wage Source Type if ( $this->getWageSourceType() !== false ) { $this->Validator->inArrayKey( 'wage_source_type_id', $this->getWageSourceType(), TTi18n::gettext( 'Incorrect Wage Source Type' ), $this->getOptions( 'wage_source_type' ) ); } // Wage Source Contributing Shift Policy if ( $this->getWageSourceContributingShiftPolicy() !== false && $this->getWageSourceContributingShiftPolicy() != TTUUID::getZeroID() ) { $csplf = TTnew( 'ContributingShiftPolicyListFactory' ); /** @var ContributingShiftPolicyListFactory $csplf */ $this->Validator->isResultSetWithRows( 'wage_source_contributing_shift_policy_id', $csplf->getByID( $this->getWageSourceContributingShiftPolicy() ), TTi18n::gettext( 'Wage Source Contributing Shift Policy is invalid' ) ); } // Time Source Contributing Shift Policy if ( $this->getTimeSourceContributingShiftPolicy() !== false && $this->getTimeSourceContributingShiftPolicy() != TTUUID::getZeroID() ) { $csplf = TTnew( 'ContributingShiftPolicyListFactory' ); /** @var ContributingShiftPolicyListFactory $csplf */ $this->Validator->isResultSetWithRows( 'time_source_contributing_shift_policy_id', $csplf->getByID( $this->getTimeSourceContributingShiftPolicy() ), TTi18n::gettext( 'Time Source Contributing Shift Policy is invalid' ) ); } // Rate if ( $this->getRate() !== false ) { $this->Validator->isFloat( 'rate', $this->getRate(), TTi18n::gettext( 'Incorrect Rate' ) ); $this->Validator->isGreaterThan( 'rate', $this->getRate(), TTi18n::gettext( 'Rate is too low' ), -99999 ); if ( $this->Validator->isError( 'rate' ) == false ) { $this->Validator->isLessThan( 'rate', $this->getRate(), TTi18n::gettext( 'Rate is too high' ), 99999 ); } } // Wage Group if ( $this->getWageGroup() !== false && $this->getWageGroup() != TTUUID::getZeroID() ) { $wglf = TTnew( 'WageGroupListFactory' ); /** @var WageGroupListFactory $wglf */ $this->Validator->isResultSetWithRows( 'wage_group_id', $wglf->getByID( $this->getWageGroup() ), TTi18n::gettext( 'Wage Group is invalid' ) ); } // Accrual Rate if ( $this->getAccrualRate() !== false ) { $this->Validator->isFloat( 'accrual_rate', $this->getAccrualRate(), TTi18n::gettext( 'Incorrect Accrual Rate' ) ); $this->Validator->isGreaterThan( 'accrual_rate', $this->getAccrualRate(), TTi18n::gettext( 'Accrual Rate is too low' ), -99999 ); if ( $this->Validator->isError( 'accrual_rate' ) == false ) { $this->Validator->isLessThan( 'accrual_rate', $this->getAccrualRate(), TTi18n::gettext( 'Accrual Rate is too high' ), 99999 ); } } // Accrual Account if ( $this->getAccrualPolicyAccount() !== false && $this->getAccrualPolicyAccount() != TTUUID::getZeroID() ) { $apalf = TTnew( 'AccrualPolicyAccountListFactory' ); /** @var AccrualPolicyAccountListFactory $apalf */ $this->Validator->isResultSetWithRows( 'accrual_policy_account_id', $apalf->getByID( $this->getAccrualPolicyAccount() ), TTi18n::gettext( 'Accrual Account is invalid' ) ); } if ( $this->getAccrualBalanceThreshold() !== false ) { $this->Validator->isFloat( 'accrual_balance_threshold', $this->getAccrualBalanceThreshold(), TTi18n::gettext( 'Incorrect Accrual Balance Threshold' ) ); } // Accrual Balance Threshold Fallback Accrual Account if ( $this->getAccrualBalanceThresholdFallbackAccrualPolicyAccount() !== false && $this->getAccrualBalanceThresholdFallbackAccrualPolicyAccount() != TTUUID::getZeroID() ) { $apalf = TTnew( 'AccrualPolicyAccountListFactory' ); /** @var AccrualPolicyAccountListFactory $apalf */ $this->Validator->isResultSetWithRows( 'accrual_balance_threshold_fallback_accrual_policy_account_id', $apalf->getByID( $this->getAccrualBalanceThresholdFallbackAccrualPolicyAccount() ), TTi18n::gettext( 'Accrual Balance Threshold Fallback Account is invalid' ) ); if ( $this->getAccrualPolicyAccount() == $this->getAccrualBalanceThresholdFallbackAccrualPolicyAccount() ) { $this->Validator->isTRUE( 'accrual_balance_threshold_fallback_accrual_policy_account_id', false, TTi18n::gettext( 'Accrual Balance Threshold Fallback Account must not match Accrual Account' ) ); } } // // ABOVE: Validation code moved from set*() functions. // if ( $this->getDeleted() == true ) { $pclf = TTNew( 'PayCodeListFactory' ); /** @var PayCodeListFactory $pclf */ $pclf->getByCompanyIdAndPayFormulaPolicyId( $this->getCompany(), $this->getId() ); if ( $pclf->getRecordCount() > 0 ) { $this->Validator->isTRUE( 'in_use', false, TTi18n::gettext( 'This pay formula policy is currently in use' ) . ' ' . TTi18n::gettext( 'by pay codes' ) ); } $rtplf = TTNew( 'RegularTimePolicyListFactory' ); /** @var RegularTimePolicyListFactory $rtplf */ $rtplf->getByCompanyIdAndPayFormulaPolicyId( $this->getCompany(), $this->getId() ); if ( $rtplf->getRecordCount() > 0 ) { $this->Validator->isTRUE( 'in_use', false, TTi18n::gettext( 'This pay formula policy is currently in use' ) . ' ' . TTi18n::gettext( 'by regular time policies' ) ); } $otplf = TTNew( 'OverTimePolicyListFactory' ); /** @var OverTimePolicyListFactory $otplf */ $otplf->getByCompanyIdAndPayFormulaPolicyId( $this->getCompany(), $this->getId() ); if ( $otplf->getRecordCount() > 0 ) { $this->Validator->isTRUE( 'in_use', false, TTi18n::gettext( 'This pay formula policy is currently in use' ) . ' ' . TTi18n::gettext( 'by overtime policies' ) ); } $pplf = TTNew( 'PremiumPolicyListFactory' ); /** @var PremiumPolicyListFactory $pplf */ $pplf->getByCompanyIdAndPayFormulaPolicyId( $this->getCompany(), $this->getId() ); if ( $pplf->getRecordCount() > 0 ) { $this->Validator->isTRUE( 'in_use', false, TTi18n::gettext( 'This pay formula policy is currently in use' ) . ' ' . TTi18n::gettext( 'by premium policies' ) ); } $aplf = TTNew( 'AbsencePolicyListFactory' ); /** @var AbsencePolicyListFactory $aplf */ $aplf->getByCompanyIdAndPayFormulaPolicyId( $this->getCompany(), $this->getId() ); if ( $aplf->getRecordCount() > 0 ) { $this->Validator->isTRUE( 'in_use', false, TTi18n::gettext( 'This pay formula policy is currently in use' ) . ' ' . TTi18n::gettext( 'by absence policies' ) ); } $mplf = TTNew( 'MealPolicyListFactory' ); /** @var MealPolicyListFactory $mplf */ $mplf->getByCompanyIdAndPayFormulaPolicyId( $this->getCompany(), $this->getId() ); if ( $mplf->getRecordCount() > 0 ) { $this->Validator->isTRUE( 'in_use', false, TTi18n::gettext( 'This pay formula policy is currently in use' ) . ' ' . TTi18n::gettext( 'by meal policies' ) ); } $bplf = TTNew( 'BreakPolicyListFactory' ); /** @var BreakPolicyListFactory $bplf */ $bplf->getByCompanyIdAndPayFormulaPolicyId( $this->getCompany(), $this->getId() ); if ( $bplf->getRecordCount() > 0 ) { $this->Validator->isTRUE( 'in_use', false, TTi18n::gettext( 'This pay formula policy is currently in use' ) . ' ' . TTi18n::gettext( 'by break policies' ) ); } } return true; } /** * @return bool */ function preValidate() { if ( $this->getWageGroup() === false ) { $this->setWageGroup( TTUUID::getZeroID() ); } if ( $this->getPayType() == 60 || $this->getPayType() == 70 ) { //60=Daily Flat Wage, 70=Daily Average -- Always set WageSourceType=30 (Average Contributing) $this->setWageSourceType( 30 ); } return true; } /** * @return bool */ function postSave() { $this->removeCache( $this->getId() ); return true; } /** * @param string $user_id UUID * @param string $accrual_policy_account_id UUID * @return bool|int */ function getCurrentAccrualBalance( $user_id, $accrual_policy_account_id = null ) { if ( $user_id == '' ) { return false; } if ( $accrual_policy_account_id == '' ) { $accrual_policy_account_id = $this->getID(); } //Check min/max times of accrual policy. $ablf = TTnew( 'AccrualBalanceListFactory' ); /** @var AccrualBalanceListFactory $ablf */ $ablf->getByUserIdAndAccrualPolicyAccount( $user_id, $accrual_policy_account_id ); if ( $ablf->getRecordCount() > 0 ) { $accrual_balance = $ablf->getCurrent()->getBalance(); } else { $accrual_balance = 0; } Debug::Text( ' Current Accrual Balance: ' . $accrual_balance, __FILE__, __LINE__, __METHOD__, 10 ); return $accrual_balance; } function getAmountAfterBalanceThreshold( $user_id, $amount, $previous_amount = 0 ) { $retval = [ 'adjusted_amount' => $amount, 'amount_remaining' => 0 ]; //Check Accrual Balance Threshold $current_accrual_balance = $this->getCurrentAccrualBalance( $user_id, $this->getAccrualPolicyAccount() ); if ( $this->getAccrualRate() > 0 ) { //Threshold is a maximum $current_accrual_balance -= $previous_amount; //When editing an existing record, we need to back out the previous amount before calculating the new balance threshold. $adjusted_accrual_balance = ( $current_accrual_balance + $amount ); if ( $adjusted_accrual_balance > $this->getAccrualBalanceThreshold() ) { $retval = [ 'adjusted_amount' => ( $this->getAccrualBalanceThreshold() - $current_accrual_balance ), 'amount_remaining' => ( $adjusted_accrual_balance - $this->getAccrualBalanceThreshold() ) ]; } } else if ( $this->getAccrualRate() < 0 ) { //Threshold is a minimum $current_accrual_balance += $previous_amount; //When editing an existing record, we need to back out the previous amount before calculating the new balance threshold. $adjusted_accrual_balance = ( $current_accrual_balance + $amount ); if ( $adjusted_accrual_balance < $this->getAccrualBalanceThreshold() ) { $retval = [ 'adjusted_amount' => ( $amount - $adjusted_accrual_balance ), 'amount_remaining' => ( $current_accrual_balance + $amount ) ]; } } if ( $retval['amount_remaining'] != 0 && is_object( $this->getAccrualPolicyAccountObject() ) ) { $retval['note'] = TTi18n::getText( 'Amount: %1 Current Balance: %2 Falling Back: %3 From: %4 to %5', [ TTDate::getTimeUnit( $amount ), TTDate::getTimeUnit( $current_accrual_balance ), TTDate::getTimeUnit( $retval['amount_remaining'] ), $this->getAccrualPolicyAccountObject()->getName(), ( is_object( $this->getAccrualBalanceThresholdFallbackAccrualPolicyAccountObject() ) ? $this->getAccrualBalanceThresholdFallbackAccrualPolicyAccountObject()->getName() : TTi18n::getText('N/A') ) ] ); } Debug::Arr( $retval, ' Current Accrual Balance: ' . $current_accrual_balance .' Previous Amount: '. $previous_amount, __FILE__, __LINE__, __METHOD__, 10 ); return $retval; } /** * @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 ) { $data = []; $variable_function_map = $this->getVariableToFunctionMap(); 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 'pay_type': $function = 'get' . str_replace( '_', '', $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 Formula Policy' ) .': '. $this->getName(), null, $this->getTable(), $this ); } } ?>