261 lines
9.0 KiB
PHP
261 lines
9.0 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;
|
|
}
|
|
|
|
public function personOrCompany()
|
|
{
|
|
return $this->booking->person_or_company;
|
|
}
|
|
|
|
/**************************************************************************
|
|
* 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');
|
|
}
|
|
}
|