function calcAccrualPolicy() { //FIXME: There is a minor bug for hour based accruals that if a milestone has a maximum limit, // and an employee recalculates there timesheet, and the limit is reached midweek, if its recalculated // again, the days that get the accrual time won't always be in order because the accrual balance is deleted // only for the day currently being calculated, so on Monday it will delete 1hr of accrual, but the balance will // still include Tue,Wed,Thu and the limit may already be reached. //We still need to calculate accruals even if the total time is 0, because we may want to override a //policy to 0hrs, and if we skip entries with TotalTime() == 0, the accruals won't be updated. if ($this->getDeleted() == FALSE) { Debug::text('Calculating Accrual Policies... Total Time: ' . $this->getTotalTime() . ' Date: ' . TTDate::getDate('DATE', $this->getUserDateObject()->getDateStamp()), __FILE__, __LINE__, __METHOD__, 10); //Calculate accrual policies assigned to other overtime/premium/absence policies //Debug::text('ID: '. $this->getId() .' Overtime Policy ID: '. (int)$this->getOverTimePolicyID() .' Premium Policy ID: '. (int)$this->getPremiumPolicyID() .' Absence Policy ID: '. (int)$this->getAbsencePolicyID(), __FILE__, __LINE__, __METHOD__, 10); //If overtime, premium or absence policy is an accrual, handle that now. if ($this->getOverTimePolicyID() != FALSE) { $accrual_policy_id = $this->getOverTimePolicyObject()->getAccrualPolicyID(); Debug::text('Over Time Accrual Policy ID: ' . $accrual_policy_id, __FILE__, __LINE__, __METHOD__, 10); if ($accrual_policy_id > 0) { Debug::text('Over Time Accrual Rate: ' . $this->getOverTimePolicyObject()->getAccrualRate() . ' Policy ID: ' . $this->getOverTimePolicyObject()->getAccrualPolicyID(), __FILE__, __LINE__, __METHOD__, 10); $af = new AccrualFactory(); $af->setUser($this->getUserDateObject()->getUser()); $af->setAccrualPolicyID($accrual_policy_id); $af->setUserDateTotalID($this->getID()); $accrual_amount = bcmul($this->getTotalTime(), $this->getOverTimePolicyObject()->getAccrualRate()); if ($accrual_amount > 0) { $af->setType(10); //Banked } else { $af->setType(20); //Used } $af->setAmount($accrual_amount); $af->setEnableCalcBalance(TRUE); if ($af->isValid()) { $af->Save(); } unset($accrual_amount); } else { Debug::text('Skipping Over Time Accrual Policy ID: ' . $accrual_policy_id, __FILE__, __LINE__, __METHOD__, 10); } } if ($this->getPremiumPolicyID() != FALSE) { $accrual_policy_id = $this->getPremiumPolicyObject()->getAccrualPolicyID(); Debug::text('Premium Accrual Policy ID: ' . $accrual_policy_id, __FILE__, __LINE__, __METHOD__, 10); if ($accrual_policy_id > 0) { $af = new AccrualFactory(); $af->setUser($this->getUserDateObject()->getUser()); $af->setAccrualPolicyID($accrual_policy_id); $af->setUserDateTotalID($this->getID()); $accrual_amount = bcmul($this->getTotalTime(), $this->getPremiumPolicyObject()->getAccrualRate()); if ($accrual_amount > 0) { $af->setType(10); //Banked } else { $af->setType(20); //Used } $af->setAmount($accrual_amount); $af->setEnableCalcBalance(TRUE); if ($af->isValid()) { $af->Save(); } unset($accrual_amount); } } if ($this->getAbsencePolicyID() != FALSE) { $accrual_policy_id = $this->getAbsencePolicyObject()->getAccrualPolicyID(); Debug::text('Absence Accrual Policy ID: ' . $accrual_policy_id, __FILE__, __LINE__, __METHOD__, 10); if ($accrual_policy_id > 0) { $af = new AccrualFactory(); $af->setUser($this->getUserDateObject()->getUser()); $af->setAccrualPolicyID($accrual_policy_id); $af->setUserDateTotalID($this->getID()); //By default we withdraw from accrual policy, so if there is a negative rate, deposit instead. $accrual_amount = bcmul($this->getTotalTime(), bcmul($this->getAbsencePolicyObject()->getAccrualRate(), -1)); if ($accrual_amount > 0) { $af->setType(10); //Banked } else { $af->setType(20); //Used } $af->setAmount($accrual_amount); $af->setEnableCalcBalance(TRUE); if ($af->isValid()) { $af->Save(); } } } unset($af, $accrual_policy_id); //Calculate any hour based accrual policies. //if ( $this->getType() == 10 AND $this->getStatus() == 10 ) { if ($this->getStatus() == 10 and in_array($this->getType(), array(20, 30))) { //Calculate hour based accruals on regular/overtime only. $aplf = new AccrualPolicyListFactory(); $aplf->getByPolicyGroupUserIdAndType($this->getUserDateObject()->getUser(), 30); if ($aplf->getRecordCount() > 0) { Debug::text('Found Hour Based Accrual Policies to apply.', __FILE__, __LINE__, __METHOD__, 10); foreach ($aplf as $ap_obj) { if ($ap_obj->getMinimumEmployedDays() == 0 or TTDate::getDays($this->getUserDateObject()->getDateStamp() - $this->getUserDateObject()->getUserObject()->getHireDate()) >= $ap_obj->getMinimumEmployedDays()) { Debug::Text(' User has been employed long enough.', __FILE__, __LINE__, __METHOD__, 10); $milestone_obj = $ap_obj->getActiveMilestoneObject($this->getUserDateObject()->getUserObject(), $this->getUserDateObject()->getDateStamp()); $accrual_balance = $ap_obj->getCurrentAccrualBalance($this->getUserDateObject()->getUserObject()->getId(), $ap_obj->getId()); //If Maximum time is set to 0, make that unlimited. if (is_object($milestone_obj) and ($milestone_obj->getMaximumTime() == 0 or $accrual_balance < $milestone_obj->getMaximumTime())) { $accrual_amount = $ap_obj->calcAccrualAmount($milestone_obj, $this->getTotalTime(), 0); if ($accrual_amount > 0) { $new_accrual_balance = bcadd($accrual_balance, $accrual_amount); //If Maximum time is set to 0, make that unlimited. if ($milestone_obj->getMaximumTime() > 0 and $new_accrual_balance > $milestone_obj->getMaximumTime()) { $accrual_amount = bcsub($milestone_obj->getMaximumTime(), $accrual_balance, 4); } Debug::Text(' Min/Max Adjusted Accrual Amount: ' . $accrual_amount . ' Limits: Min: ' . $milestone_obj->getMinimumTime() . ' Max: ' . $milestone_obj->getMaximumTime(), __FILE__, __LINE__, __METHOD__, 10); $af = new AccrualFactory(); $af->setUser($this->getUserDateObject()->getUserObject()->getId()); $af->setType(75); //Accrual Policy $af->setAccrualPolicyID($ap_obj->getId()); $af->setUserDateTotalID($this->getID()); $af->setAmount($accrual_amount); $af->setTimeStamp($this->getUserDateObject()->getDateStamp()); $af->setEnableCalcBalance(TRUE); if ($af->isValid()) { $af->Save(); } unset($accrual_amount, $accrual_balance, $new_accrual_balance); } else { Debug::Text(' Accrual Amount is 0...', __FILE__, __LINE__, __METHOD__, 10); } } else { Debug::Text(' Accrual Balance is outside Milestone Range. Or no milestone found. Skipping...', __FILE__, __LINE__, __METHOD__, 10); } } else { Debug::Text(' User has only been employed: ' . TTDate::getDays($this->getUserDateObject()->getDateStamp() - $this->getUserDateObject()->getUserObject()->getHireDate()) . ' Days, not enough.', __FILE__, __LINE__, __METHOD__, 10); } } } else { Debug::text('No Hour Based Accrual Policies to apply.', __FILE__, __LINE__, __METHOD__, 10); } } else { Debug::text('No worked time on this day or not proper type/status, skipping hour based accrual policies...', __FILE__, __LINE__, __METHOD__, 10); } } /* //FIXME: Figure a better way to re-calculate accrual policies assigned to absences to update accrual balances if ( $this->getEnableCalcAccrualPolicy() == TRUE ) { Debug::text('Recalculating Accruals assigned to absence policies...', __FILE__, __LINE__, __METHOD__, 10); $udtlf = new UserDateTotalListFactory(); $udtlf->getByUserDateIdAndStatus( $this->getUserDateID(), 30 ); //Absences only if ( $udtlf->getRecordCount() > 0 ) { foreach( $udtlf as $udt_obj ) { $accrual_policy_id = $udt_obj->getAbsencePolicyObject()->getAccrualPolicyID(); Debug::text('Absence Accrual Policy ID: '. $accrual_policy_id, __FILE__, __LINE__, __METHOD__, 10); if ( $accrual_policy_id > 0 AND $this->getTotalTime() > 0 ) { $af = new AccrualFactory(); $af->setUser( $this->getUserDateObject()->getUser() ); $af->setAccrualPolicyID( $accrual_policy_id ); $af->setType(20); $af->setUserDateTotalID( $udt_obj->getID() ); $af->setAmount( bcmul( $udt_obj->getTotalTime(), -1 ) ); $af->setEnableCalcBalance(TRUE); if ( $af->isValid() ) { $af->Save(); } } } } } else { Debug::text('NOT Recalculating Accruals assigned to absence policies...', __FILE__, __LINE__, __METHOD__, 10); } */ return TRUE; }