mirror of
https://github.com/firefly-iii/firefly-iii.git
synced 2025-10-22 12:11:19 +00:00
First effort towards nice charts in the budgeting overviews.
This commit is contained in:
@@ -24,6 +24,289 @@ class ChartController extends BaseController
|
||||
$this->_accounts = $accounts;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public function budgetDefault(\Budget $budget)
|
||||
{
|
||||
$expense = [];
|
||||
$left = [];
|
||||
// get all limit repetitions for this budget.
|
||||
/** @var \Limit $limit */
|
||||
foreach ($budget->limits as $limit) {
|
||||
/** @var \LimitRepetition $rep */
|
||||
foreach ($limit->limitrepetitions as $rep) {
|
||||
$spentInRep = \Transaction::
|
||||
leftJoin(
|
||||
'transaction_journals', 'transaction_journals.id', '=',
|
||||
'transactions.transaction_journal_id'
|
||||
)
|
||||
->leftJoin(
|
||||
'component_transaction_journal', 'component_transaction_journal.transaction_journal_id',
|
||||
'=',
|
||||
'transaction_journals.id'
|
||||
)->where('component_transaction_journal.component_id', '=', $budget->id)->where(
|
||||
'transaction_journals.date', '>=', $rep->startdate->format('Y-m-d')
|
||||
)->where('transaction_journals.date', '<=', $rep->enddate->format('Y-m-d'))->where(
|
||||
'amount', '>', 0
|
||||
)->sum('amount');
|
||||
|
||||
|
||||
$pct = round(($spentInRep / $limit->amount) * 100,2);
|
||||
$expense[] = [$rep->startdate->timestamp * 1000, floatval($spentInRep)];
|
||||
$left[] = [$rep->startdate->timestamp * 1000, $pct];
|
||||
}
|
||||
}
|
||||
|
||||
$return = [
|
||||
'chart_title' => 'Overview for budget ' . $budget->name,
|
||||
'subtitle' => 'Between something something',
|
||||
'series' => [
|
||||
[
|
||||
'type' => 'column',
|
||||
'name' => 'Expenses in envelope',
|
||||
'data' => $expense
|
||||
],
|
||||
[
|
||||
'type' => 'line',
|
||||
'yAxis' => 1,
|
||||
'name' => 'Spent pct for envelope',
|
||||
'data' => $left
|
||||
]
|
||||
|
||||
]
|
||||
];
|
||||
return Response::json($return);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param LimitRepetition $rep
|
||||
*/
|
||||
public function budgetLimit(\LimitRepetition $rep)
|
||||
{
|
||||
$budget = $rep->limit->budget;
|
||||
$current = clone $rep->startdate;
|
||||
$expense = [];
|
||||
$leftInLimit = [];
|
||||
$currentLeftInLimit = floatval($rep->limit->amount);
|
||||
while ($current <= $rep->enddate) {
|
||||
$spent = \Transaction::
|
||||
leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id')
|
||||
->leftJoin(
|
||||
'component_transaction_journal', 'component_transaction_journal.transaction_journal_id', '=',
|
||||
'transaction_journals.id'
|
||||
)->where('component_transaction_journal.component_id', '=', $budget->id)->where(
|
||||
'transaction_journals.date', $current->format('Y-m-d')
|
||||
)->where('amount', '>', 0)->sum('amount');
|
||||
$spent = floatval($spent) == 0 ? null : floatval($spent);
|
||||
$entry = [$current->timestamp * 1000, $spent];
|
||||
$expense[] = $entry;
|
||||
$currentLeftInLimit = $currentLeftInLimit - $spent;
|
||||
$leftInLimit[] = [$current->timestamp * 1000, $currentLeftInLimit];
|
||||
$current->addDay();
|
||||
}
|
||||
|
||||
$return = [
|
||||
'chart_title' => 'Overview for budget ' . $budget->name,
|
||||
'subtitle' => 'Between ' . $rep->startdate->format('d M Y') . ' and ' . $rep->startdate->format('d M Y'),
|
||||
'series' => [
|
||||
[
|
||||
'type' => 'column',
|
||||
'name' => 'Expenses per day',
|
||||
'yAxis' => 1,
|
||||
'data' => $expense
|
||||
],
|
||||
[
|
||||
'type' => 'line',
|
||||
'name' => 'Left in envelope',
|
||||
'data' => $leftInLimit
|
||||
]
|
||||
|
||||
]
|
||||
];
|
||||
|
||||
return Response::json($return);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public function budgetNoLimits(\Budget $budget)
|
||||
{
|
||||
$inRepetitions = [];
|
||||
foreach ($budget->limits as $limit) {
|
||||
foreach ($limit->limitrepetitions as $repetition) {
|
||||
$set = $budget->transactionjournals()->leftJoin(
|
||||
'transaction_types', 'transaction_types.id', '=', 'transaction_journals.transaction_type_id'
|
||||
)->where('transaction_types.type', 'Withdrawal')->where(
|
||||
'date', '>=', $repetition->startdate->format('Y-m-d')
|
||||
)->where('date', '<=', $repetition->enddate->format('Y-m-d'))->orderBy('date', 'DESC')->get(
|
||||
['transaction_journals.id']
|
||||
);
|
||||
foreach ($set as $item) {
|
||||
$inRepetitions[] = $item->id;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
$query = $budget->transactionjournals()->whereNotIn(
|
||||
'transaction_journals.id', $inRepetitions
|
||||
)->orderBy('date', 'DESC')->orderBy(
|
||||
'transaction_journals.id', 'DESC'
|
||||
);
|
||||
|
||||
|
||||
$result = $query->get(['transaction_journals.id']);
|
||||
$set = [];
|
||||
foreach ($result as $entry) {
|
||||
$set[] = $entry->id;
|
||||
}
|
||||
// all transactions for these journals, grouped by date and SUM
|
||||
$transactions = \Transaction::whereIn('transaction_journal_id', $set)->leftJoin(
|
||||
'transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id'
|
||||
)
|
||||
->groupBy('transaction_journals.date')->where('amount', '>', 0)->get(
|
||||
['transaction_journals.date', DB::Raw('SUM(`amount`) as `aggregate`')]
|
||||
);
|
||||
|
||||
|
||||
// this set builds the chart:
|
||||
$expense = [];
|
||||
|
||||
foreach ($transactions as $t) {
|
||||
$date = new Carbon($t->date);
|
||||
$expense[] = [$date->timestamp * 1000, floatval($t->aggregate)];
|
||||
}
|
||||
$return = [
|
||||
'chart_title' => 'Overview for ' . $budget->name,
|
||||
'subtitle' => 'Not organized by an envelope',
|
||||
'series' => [
|
||||
[
|
||||
'type' => 'spline',
|
||||
'name' => 'Expenses per day',
|
||||
'data' => $expense
|
||||
]
|
||||
|
||||
]
|
||||
];
|
||||
|
||||
return Response::json($return);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public function budgetSession(\Budget $budget)
|
||||
{
|
||||
$expense = [];
|
||||
$repetitionSeries = [];
|
||||
$current = clone Session::get('start');
|
||||
$end = clone Session::get('end');
|
||||
while ($current <= $end) {
|
||||
$spent = \Transaction::
|
||||
leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id')
|
||||
->leftJoin(
|
||||
'component_transaction_journal', 'component_transaction_journal.transaction_journal_id', '=',
|
||||
'transaction_journals.id'
|
||||
)->where('component_transaction_journal.component_id', '=', $budget->id)->where(
|
||||
'transaction_journals.date', $current->format('Y-m-d')
|
||||
)->where('amount', '>', 0)->sum('amount');
|
||||
$spent = floatval($spent) == 0 ? null : floatval($spent);
|
||||
if (!is_null($spent)) {
|
||||
$expense[] = [$current->timestamp * 1000, $spent];
|
||||
}
|
||||
|
||||
$current->addDay();
|
||||
}
|
||||
|
||||
// find all limit repetitions (for this budget) between start and end.
|
||||
$start = clone Session::get('start');
|
||||
$repetitionSeries[] = [
|
||||
'type' => 'column',
|
||||
'name' => 'Something something expenses',
|
||||
'data' => $expense
|
||||
];
|
||||
|
||||
|
||||
/** @var \Limit $limit */
|
||||
foreach ($budget->limits as $limit) {
|
||||
$reps = $limit->limitrepetitions()->where(
|
||||
function ($q) use ($start, $end) {
|
||||
// startdate is between range
|
||||
$q->where(
|
||||
function ($q) use ($start, $end) {
|
||||
$q->where('startdate', '>=', $start->format('Y-m-d'));
|
||||
$q->where('startdate', '<=', $end->format('Y-m-d'));
|
||||
}
|
||||
);
|
||||
|
||||
// or enddate is between range.
|
||||
$q->orWhere(
|
||||
function ($q) use ($start, $end) {
|
||||
$q->where('enddate', '>=', $start->format('Y-m-d'));
|
||||
$q->where('enddate', '<=', $end->format('Y-m-d'));
|
||||
}
|
||||
);
|
||||
}
|
||||
)
|
||||
->get();
|
||||
$currentLeftInLimit = floatval($limit->amount);
|
||||
/** @var \LimitRepetition $repetition */
|
||||
foreach ($reps as $repetition) {
|
||||
// create a serie for the repetition.
|
||||
$currentSerie = [
|
||||
'type' => 'spline',
|
||||
'id' => 'rep-' . $repetition->id,
|
||||
'yAxis' => 1,
|
||||
'name' => 'Serie ' . $repetition->startdate->format('Y-m-d') . ' to ' .
|
||||
$repetition->enddate->format('Y-m-d') . '.',
|
||||
'data' => []
|
||||
];
|
||||
$current = clone $repetition->startdate;
|
||||
while ($current <= $repetition->enddate) {
|
||||
if ($current >= Session::get('start') && $current <= Session::get('end')) {
|
||||
// spent on limit:
|
||||
$spentSoFar = \Transaction::
|
||||
leftJoin(
|
||||
'transaction_journals', 'transaction_journals.id', '=',
|
||||
'transactions.transaction_journal_id'
|
||||
)
|
||||
->leftJoin(
|
||||
'component_transaction_journal', 'component_transaction_journal.transaction_journal_id',
|
||||
'=',
|
||||
'transaction_journals.id'
|
||||
)->where('component_transaction_journal.component_id', '=', $budget->id)->where(
|
||||
'transaction_journals.date', '>=', $repetition->startdate->format('Y-m-d')
|
||||
)->where('transaction_journals.date', '<=', $current->format('Y-m-d'))->where(
|
||||
'amount', '>', 0
|
||||
)->sum('amount');
|
||||
$spent = floatval($spent) == 0 ? null : floatval($spent);
|
||||
$currentLeftInLimit = floatval($limit->amount) - floatval($spentSoFar);
|
||||
|
||||
$currentSerie['data'][] = [$current->timestamp * 1000, $currentLeftInLimit];
|
||||
}
|
||||
$current->addDay();
|
||||
}
|
||||
|
||||
// do something here.
|
||||
$repetitionSeries[] = $currentSerie;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
$return = [
|
||||
'chart_title' => 'Overview for budget ' . $budget->name,
|
||||
'subtitle' => 'Between Bla bla bla',
|
||||
'series' => $repetitionSeries
|
||||
];
|
||||
|
||||
return Response::json($return);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Category $category
|
||||
*
|
||||
|
Reference in New Issue
Block a user