Files
pollux/app/SubBooking.php
T

256 lines
8.9 KiB
PHP

<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\DB;
use Carbon\Carbon;
class SubBooking extends Model
{
/**************************************************************************
* DIRECT RELATIONS *
**************************************************************************/
/*
* Get the booking which contains the sub-booking.
*
* @return Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function booking() {
return $this->belongsTo('\App\Booking', 'booking_id');
}
/*
* Get the person-target related to the sub-booking.
*
* @return Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function personTarget()
{
return $this->belongsTo('App\PersonTarget', 'person_target_id');
}
/*
* Get the project related to the sub-booking.
*
* @return Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function project()
{
return $this->belongsTo('App\Project', 'project_id');
}
/*
* Get the account type related to the sub-booking.
*
* @return Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function accountType()
{
return $this->belongsTo('App\AccountType', 'account_type_id');
}
/**************************************************************************
* INDIRECT PROPERTIES *
**************************************************************************/
/*
* Get the booking date for a sub-booking.
*
* @return string
*/
public function date()
{
return $this->booking->date;
}
/*
* Get the IO-type of the sub-booking.
*
* @return
*/
public function ioType()
{
return $this->accountType->accountClass->ioType;
}
public function signedAmount()
{
return $this->ioType()->factor * $this->amount;
}
/**************************************************************************
* SUMS OVER INCOMES AND EXPEDITURES, ACCOUNT BALANCES *
**************************************************************************/
/**
* Return the balance at a given date.
*
* @param string $date
* @return float
*/
public static function balanceAt($date)
{
$date = Carbon::parse($date)->format('Y-m-d');
$result = SubBooking::joinAccountBranch()
->joinBookings()
->where('bookings.date', '<=', $date)
->selectRaw('sum(i_o_types.factor * sub_bookings.amount) as balance')
->first()->balance;
return is_null($result) ? 0.00 : $result;
}
/**
* Return the sum of all expeditures in the given interval.
*
* Return the sum of all expeditures in the interval from $star to $end.
* If $group is true, the result is grouped by year and month, such that the
* collection contains for every month in the interval an model with the
* properties 'year', 'month' and 'expeditures'.
* Otherwise the result is a collection with a single model, containing the
* property 'expeditures'.
*
* @param string $start
* @param string $end
* @param string $group Toggle, if the result is grouped by year and month.
* @return Illuminate\Database\Eloquent\Collection
*/
public static function expedituresInInterval($start, $end, $group = false)
{
return SubBooking::cashFlowInInterval($start, $end, 'expeditures', $group);
}
/**
* Return the sum of all expeditures in the given interval.
*
* Return the sum of all expeditures in the interval from $star to $end.
* If $group is true, the result is grouped by year and month, such that the
* collection contains for every month in the interval an model with the
* properties 'year', 'month' and 'incomes'.
* Otherwise the result is a collection with a single model, containing the
* property 'incomes'.
*
* @param string $start
* @param string $end
* @param string $group Toggle, if the result is grouped by year and month.
* @return Illuminate\Database\Eloquent\Collection
*/
public static function incomesInInterval($start, $end, $group = false)
{
return SubBooking::cashFlowInInterval($start, $end, 'incomes', $group);
}
/**
* Since the incomesInInterval and expedituresInInterval methods are almost
* the same, this is the collectively used code.
*
* @param string $start
* @param string $end
* @param string $type Can be 'incomes' or 'expeditures'
* @param string $group Toggle, if the result is grouped by year and month.
* @return Illuminate\Database\Eloquent\collection
*/
private static function cashFlowInInterval($start, $end, $type, $group = false)
{
$parsedStart = Carbon::parse($start);
$parsedEnd = Carbon::parse($end);
$typeName = ($type === 'incomes') ? 'Einnahme' : 'Ausgabe';
$start = $parsedStart->format('Y-m-d');
$end = $parsedEnd->format('Y-m-d');
$result = SubBooking::joinAccountBranch()
->interval($start, $end)
->where('i_o_types.name', '=', $typeName)
->selectRaw('sum(i_o_types.factor * sub_bookings.amount) as ' . $type);
if ($group) {
// Group the result, first by month, then by year
$result = $result->groupBy('year', 'month')
->selectRaw('sum(i_o_types.factor * sub_bookings.amount) as ' . $type . ',
YEAR(bookings.date) as year,
MONTH(bookings.date) as month')
->get();
// Add a model with values = 0 for those months without any
// sub-booking. If we would not explicitly define a model for these
// cases, we would try toget a property from a model that does not
// exist.
$yearStart = $parsedStart->format('Y');
$yearEnd = $parsedEnd->format('Y');
for ($year = $yearStart; $year <= $yearEnd; $year++) {
// Set the start and end month for a year, in case the given
// interval starts or ends in the current year.
$monthStart = ($year == $parsedStart->format('Y')) ?
$parsedStart->format('n') :
1;
$monthEnd = ($year == $parsedEnd->format('Y')) ?
$parsedEnd->format('n') :
12;
for ($month = $monthStart; $month <= $monthEnd; $month++) {
if ($result->where('year', '=', $year)
->where('month', '=', $month)->isEmpty()) {
$subBooking = new SubBooking();
$subBooking->$type = 0;
$subBooking->year = (int) $year;
$subBooking->month = (int) $month;
$result->push($subBooking);
}
}
}
return $result;
}
return $result->get();
}
/**************************************************************************
* QUERY SCOPES *
**************************************************************************/
/**
* Consider only sub-bookings in a given interval.
*
* @return Illuminate\Database\Eloquent\Builder
*/
public function scopeInterval($query, $start, $end)
{
return $query->joinBookings()
->where('bookings.date', '>=', Carbon::parse($start)->format('Y-m-d'))
->where('bookings.date', '<=', Carbon::parse($end)->format('Y-m-d'));
}
/**
* Join the 'bookings' table into the query.
*
* @return Illuminate\Database\Eloquent\Builder
*/
public function scopeJoinBookings($query)
{
return $query->join('bookings', 'bookings.id', '=', 'sub_bookings.booking_id');
}
/**
* Join the tables 'i_o_types', 'account_classes' and 'account_types' into
* the query.
*
* @return Illuminate\Database\Eloquent\Builder
*/
public function scopeJoinAccountBranch($query)
{
return $query->join('account_types', 'account_types.id', '=', 'sub_bookings.account_type_id')
->join('account_classes', 'account_classes.id', '=', 'account_types.account_class_id')
->join('i_o_types', 'i_o_types.id', '=', 'account_classes.io_type_id');
}
}