belongsTo('App\IOType'); } /** * Get the actuals connected with the target. * * @return Illuminate\Database\Eloquent\Relations\HasMany */ public function actuals() { return $this->hasMany('App\SubBooking'); } public function person() { return $this->belongsTo('App\Person'); } /************************************************************************** * INDIRECT RELATIONS * **************************************************************************/ /************************************************************************** * INDIRECT PROPERTIES * **************************************************************************/ /** * Get the signed amount of the target. * * @return float */ public function signedAmount() { return $this->amount * $this->ioType->factor; } /** * Return the sum of all actuals belonging to this target * * @return float */ public function actualsSum() { $sum = 0; foreach ($this->actuals as $actual) { $sum += $actual->signedAmount(); } return $sum; } /** * Get the difference of target and actually payed amount so far. I. e. * return the amount still to be payed. * * @return float */ public function difference() { return $this->signedAmount() - $this->actualsSum(); } /** * Return true, if the target is paid and therefore closed. * * @return boolean */ public function isPaid() { return $this->difference() == 0; } /************************************************************************** * COLLECTIONS FILTERED BY PAYMENT STATES * **************************************************************************/ /* * Get all targets which are paid off. * * @return Illuminate\Database\Eloquent\Collection */ public static function open() { return PersonTarget::queryWhere('open'); } /* * Get all targets which are paid off. * * @return Illuminate\Database\Eloquent\Collection */ public static function paid() { return PersonTarget::queryWhere('paid'); } /* * Get all targets which are underpaid. * * @return Illuminate\Database\Eloquent\Collection */ public static function underpaid() { return PersonTarget::queryWhere('underpaid'); } /* * Get all targets which are overpaid. * * @return Illuminate\Database\Eloquent\Collection */ public static function overpaid() { return PersonTarget::queryWhere('overpaid'); } /* * Get all targets which are a receivable. * * @return Illuminate\Database\Eloquent\Collection */ public static function receivable() { return PersonTarget::queryWhere('receivable'); } /* * Get all targets which are a debt. * * @return Illuminate\Database\Eloquent\Collection */ public static function debt() { return PersonTarget::queryWhere('debt'); } /* * Get the person targets which satisfy a given condition. * Possible values for $cond are: * * 'paid' - all targets, which are paid * 'underpaid' - all targets which are underpaid * 'overpaid' - all targets which are overpaid * 'receivable' - all targets which are a receivable, i. e. have a positive * difference between target and actual value. * 'debt' - all targets which are a debt, i. e. have a negative * difference between target and actual value. * * @param string $cond * @return array */ private static function queryWhere($cond) { // Set the having clause of the query according to the $cond argument. $having = true; switch ($cond) { case 'paid': $having = 'target = actual'; break; case 'open': $having = 'target != actual'; break; case 'underpaid': $having = '(target > 0 AND target > actual) OR ' . '(target < 0 AND target < actual)'; break; case 'overpaid': $having = '(target > 0 AND target < actual) OR ' . '(target < 0 AND target > actual)'; break; case 'receivable': $having = 'target > actual'; break; case 'debt': $having = 'target < actual'; break; } // Run the database query to retreive the data from the database. $selection = DB::select(' SELECT p_t.*, p_t.amount * i_o2.factor AS target, IFNULL(SUM(i_o1.factor * s_b.amount), 0) AS actual FROM person_targets p_t INNER JOIN i_o_types i_o2 ON i_o2.id = p_t.io_type_id LEFT JOIN sub_bookings s_b ON p_t.id = s_b.person_target_id LEFT JOIN account_types a_t ON a_t.id = s_b.account_type_id LEFT JOIN account_classes a_c ON a_c.id = a_t.account_class_id LEFT JOIN i_o_types i_o1 ON i_o1.id = a_c.io_type_id GROUP BY p_t.id HAVING ' . $having . ' ORDER BY p_t.date, p_t.reference, p_t.person_id;'); // Remove the unused columns 'target' and 'actual' from the query // result. // This is not necessary, unless you want to save the hydrated models to // the databse. In this case we would get an error since the // peron_targets table has no column 'target' and 'actual'. foreach ($selection as $personTarget) { unset($personTarget->target); unset($personTarget->actual); } // Create a collection of PersonTargets from the raw query result. return PersonTarget::hydrate($selection); } }