Added the following functions to SubBooking:

Query scopes:
    interval($start, $end)
    joinBookings()
    withSignedAmount()
    joinAccountBranch()
  Sum functions:
    balanceAt($date)
    expedituresInInterval($start, $end, $group)
    incomesInInterval($start, $end, $group)
    cashFlowInInterval($start, $end, $type, $group)
This commit is contained in:
Lukas Halbritter
2018-09-28 22:37:53 +02:00
parent a8aa43e28c
commit 530ced47b2
+185
View File
@@ -3,6 +3,8 @@
namespace App; namespace App;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\DB;
use Carbon\Carbon;
class SubBooking extends Model class SubBooking extends Model
{ {
@@ -11,6 +13,189 @@ class SubBooking extends Model
return $this->ioType->factor * $this->amount; 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');
}
/**
* Add a signed amount property to the table.
*
* @return Illuminate\Database\Eloquent\Builder
*/
public function scopeWithSignedAmount($query)
{
return $query->joinAccountBranch()
->addSelect(DB::raw('sub_bookings.*, (i_o_types.factor * sub_bookings.amount) as signedAmount'));
}
/**
* 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');
}
/************************************************************************** /**************************************************************************
* BOOKINGS * * BOOKINGS *
**************************************************************************/ **************************************************************************/