Files
pollux/app/PersonTarget.php
T
Lukas Halbritter c8b08da62a Changed query which is used to obtain certain person target sets. Most joins are
now left joins, otherwise the query would drop all targets without assigned
sub-bookings.
2018-10-23 23:34:16 +02:00

228 lines
6.6 KiB
PHP

<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\DB;
class PersonTarget extends Model
{
/**************************************************************************
* DIRECT RELATIONS *
**************************************************************************/
/**
* Get the IOType of the target.
*
* @return Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function ioType()
{
return $this->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 . ';');
// 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);
}
}