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'); } }