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:
@@ -3,6 +3,8 @@
|
||||
namespace App;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Carbon\Carbon;
|
||||
|
||||
class SubBooking extends Model
|
||||
{
|
||||
@@ -11,6 +13,189 @@ class SubBooking extends Model
|
||||
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 *
|
||||
**************************************************************************/
|
||||
|
||||
Reference in New Issue
Block a user