firefly-iii/app/controllers/GoogleChartController.php
2014-11-14 11:43:08 +01:00

643 lines
20 KiB
PHP

<?php
use Carbon\Carbon;
/**
* Class GoogleChartController
*/
class GoogleChartController extends BaseController
{
/**
* @param Account $account
*/
public function accountBalanceChart(Account $account)
{
/** @var \Grumpydictator\Gchart\GChart $chart */
$chart = App::make('gchart');
$chart->addColumn('Day of month', 'date');
$chart->addColumn('Balance for ' . $account->name, 'number');
/*
* Loop the date, then loop the accounts, then add balance.
*/
$start = Session::get('start');
$end = Session::get('end');
$current = clone $start;
while ($end >= $current) {
$row = [clone $current];
if ($current > Carbon::now()) {
$row[] = null;
} else {
$row[] = $account->balance($current);
}
$chart->addRowArray($row);
$current->addDay();
}
$chart->generate();
return Response::json($chart->getData());
}
/**
* @param Account $account
*
* @return \Illuminate\Http\JsonResponse
*/
public function accountSankeyInChart(Account $account)
{
// collect all relevant entries.
$set = [];
/** @var \Grumpydictator\Gchart\GChart $chart */
$chart = App::make('gchart');
$chart->addColumn('From', 'string');
$chart->addColumn('To', 'string', 'domain');
$chart->addColumn('Weight', 'number');
$transactions = $account->transactions()->with(
['transactionjournal', 'transactionjournal.transactions' => function ($q) {
$q->where('amount', '<', 0);
}, 'transactionjournal.budgets', 'transactionjournal.transactiontype', 'transactionjournal.categories']
)->before(Session::get('end'))->after(
Session::get('start')
)->get();
/** @var Transaction $transaction */
foreach ($transactions as $transaction) {
$amount = floatval($transaction->amount);
$type = $transaction->transactionJournal->transactionType->type;
if ($amount > 0 && $type != 'Transfer') {
$otherAccount = $transaction->transactionJournal->transactions[0]->account->name;
$categoryName = isset($transaction->transactionJournal->categories[0]) ? $transaction->transactionJournal->categories[0]->name : '(no cat)';
$set[] = [$otherAccount, $categoryName, $amount];
$set[] = [$categoryName, $account->name, $amount];
}
}
// loop the set, group everything together:
$grouped = [];
foreach ($set as $entry) {
$key = $entry[0] . $entry[1];
if (isset($grouped[$key])) {
$grouped[$key][2] += $entry[2];
} else {
$grouped[$key] = $entry;
}
}
// add rows to the chart:
foreach ($grouped as $entry) {
$chart->addRow($entry[0], $entry[1], $entry[2]);
}
$chart->generate();
return Response::json($chart->getData());
}
/**
* @param Account $account
*
* @return \Illuminate\Http\JsonResponse
*/
public function accountSankeyOutChart(Account $account)
{
// collect all relevant entries.
$set = [];
/** @var \Grumpydictator\Gchart\GChart $chart */
$chart = App::make('gchart');
$chart->addColumn('From', 'string');
$chart->addColumn('To', 'string', 'domain');
$chart->addColumn('Weight', 'number');
$transactions = $account->transactions()->with(
['transactionjournal', 'transactionjournal.transactions', 'transactionjournal.budgets', 'transactionjournal.transactiontype',
'transactionjournal.categories']
)->before(Session::get('end'))->after(
Session::get('start')
)->get();
/** @var Transaction $transaction */
foreach ($transactions as $transaction) {
$amount = floatval($transaction->amount);
$type = $transaction->transactionJournal->transactionType->type;
if ($amount < 0 && $type != 'Transfer') {
// from account to a budget (if present).
$budgetName = isset($transaction->transactionJournal->budgets[0]) ? $transaction->transactionJournal->budgets[0]->name : '(no budget)';
$set[] = [$account->name, $budgetName, $amount * -1];
// from budget to category.
$categoryName = isset($transaction->transactionJournal->categories[0]) ? ' ' . $transaction->transactionJournal->categories[0]->name
: '(no cat)';
$set[] = [$budgetName, $categoryName, $amount * -1];
}
}
// loop the set, group everything together:
$grouped = [];
foreach ($set as $entry) {
$key = $entry[0] . $entry[1];
if (isset($grouped[$key])) {
$grouped[$key][2] += $entry[2];
} else {
$grouped[$key] = $entry;
}
}
// add rows to the chart:
foreach ($grouped as $entry) {
$chart->addRow($entry[0], $entry[1], $entry[2]);
}
$chart->generate();
return Response::json($chart->getData());
}
/**
* This method renders the b
*/
public function allAccountsBalanceChart()
{
/** @var \Grumpydictator\Gchart\GChart $chart */
$chart = App::make('gchart');
$chart->addColumn('Day of the month', 'date');
/** @var \FireflyIII\Shared\Preferences\Preferences $preferences */
$preferences = App::make('FireflyIII\Shared\Preferences\Preferences');
$pref = $preferences->get('frontpageAccounts', []);
/** @var \FireflyIII\Database\Account $acct */
$acct = App::make('FireflyIII\Database\Account');
if (count($pref->data) > 0) {
$accounts = $acct->getByIds($pref->data);
} else {
$accounts = $acct->getAssetAccounts();
}
/*
* Add a column for each account.
*/
/** @var Account $account */
foreach ($accounts as $account) {
$chart->addColumn('Balance for ' . $account->name, 'number');
}
/*
* Loop the date, then loop the accounts, then add balance.
*/
$start = Session::get('start');
$end = Session::get('end');
$current = clone $start;
while ($end >= $current) {
$row = [clone $current];
foreach ($accounts as $account) {
//if ($current > Carbon::now()) {
// $row[] = 0;
//} else {
$row[] = $account->balance($current);
//}
}
$chart->addRowArray($row);
$current->addDay();
}
$chart->generate();
return Response::json($chart->getData());
}
/**
* @return \Illuminate\Http\JsonResponse
*/
public function allBudgetsHomeChart()
{
/** @var \Grumpydictator\Gchart\GChart $chart */
$chart = App::make('gchart');
$chart->addColumn('Budget', 'string');
$chart->addColumn('Budgeted', 'number');
$chart->addColumn('Spent', 'number');
/** @var \FireflyIII\Database\Budget $bdt */
$bdt = App::make('FireflyIII\Database\Budget');
$budgets = $bdt->get();
/*
* Loop budgets:
*/
/** @var Budget $budget */
foreach ($budgets as $budget) {
/*
* Is there a repetition starting on this particular date? We can use that.
*/
/** @var \LimitRepetition $repetition */
$repetition = $bdt->repetitionOnStartingOnDate($budget, Session::get('start'));
/*
* If there is, use it. Otherwise, forget it.
*/
if (is_null($repetition)) {
// use the session start and end for our search query
$searchStart = Session::get('start');
$searchEnd = Session::get('end');
// the limit is zero:
$limit = 0;
} else {
// use the limit's start and end for our search query
$searchStart = $repetition->startdate;
$searchEnd = $repetition->enddate;
// the limit is the repetitions limit:
$limit = floatval($repetition->amount);
}
/*
* No matter the result of the search for the repetition, get all the transactions associated
* with the budget, and sum up the expenses made.
*/
$expenses = floatval($budget->transactionjournals()->before($searchEnd)->after($searchStart)->lessThan(0)->sum('amount')) * -1;
if ($expenses > 0) {
$chart->addRow($budget->name, $limit, $expenses);
}
}
/*
* Finally, get all transactions WITHOUT a budget and add those as well.
* (yes this method is oddly specific).
*/
$noBudgetSet = $bdt->transactionsWithoutBudgetInDateRange(Session::get('start'), Session::get('end'));
$sum = $noBudgetSet->sum('amount') * -1;
$chart->addRow('No budget', 0, $sum);
$chart->generate();
return Response::json($chart->getData());
}
/**
* @return \Illuminate\Http\JsonResponse
*/
public function allCategoriesHomeChart()
{
$data = [];
/** @var \Grumpydictator\Gchart\GChart $chart */
$chart = App::make('gchart');
$chart->addColumn('Category', 'string');
$chart->addColumn('Spent', 'number');
/** @var \FireflyIII\Database\TransactionJournal $tj */
$tj = App::make('FireflyIII\Database\TransactionJournal');
/*
* Get the journals:
*/
$journals = $tj->getInDateRange(Session::get('start'), Session::get('end'));
/** @var \TransactionJournal $journal */
foreach ($journals as $journal) {
if ($journal->transactionType->type == 'Withdrawal') {
$amount = $journal->getAmount();
$category = $journal->categories()->first();
if (!is_null($category)) {
if (isset($data[$category->name])) {
$data[$category->name] += $amount;
} else {
$data[$category->name] = $amount;
}
}
}
}
arsort($data);
foreach ($data as $key => $entry) {
$chart->addRow($key, $entry);
}
$chart->generate();
return Response::json($chart->getData());
}
/**
* @return \Illuminate\Http\JsonResponse
*/
public function budgetsReportChart($year)
{
try {
$start = new Carbon('01-01-' . $year);
} catch (Exception $e) {
App::abort(500);
}
/** @var \Grumpydictator\Gchart\GChart $chart */
$chart = App::make('gchart');
/** @var \FireflyIII\Database\Budget $bdt */
$bdt = App::make('FireflyIII\Database\Budget');
$budgets = $bdt->get();
$chart->addColumn('Month', 'date');
/** @var \Budget $budget */
foreach ($budgets as $budget) {
$chart->addColumn($budget->name, 'number');
}
$chart->addColumn('No budget', 'number');
/*
* Loop budgets this year.
*/
$end = clone $start;
$end->endOfYear();
while ($start <= $end) {
$row = [clone $start];
foreach ($budgets as $budget) {
$row[] = $bdt->spentInMonth($budget, $start);
}
/*
* Without a budget:
*/
$endOfMonth = clone $start;
$endOfMonth->endOfMonth();
$set = $bdt->transactionsWithoutBudgetInDateRange($start, $endOfMonth);
$row[] = floatval($set->sum('amount')) * -1;
$chart->addRowArray($row);
$start->addMonth();
}
$chart->generate();
return Response::json($chart->getData());
}
/**
* @param Component $component
* @param $year
*
* @return \Illuminate\Http\JsonResponse
*/
public function componentsAndSpending(Component $component, $year)
{
try {
$start = new Carbon('01-01-' . $year);
} catch (Exception $e) {
App::abort(500);
}
if ($component->class == 'Budget') {
/** @var \FireflyIII\Database\Budget $repos */
$repos = App::make('FireflyIII\Database\Budget');
} else {
/** @var \FireflyIII\Database\Category $repos */
$repos = App::make('FireflyIII\Database\Category');
}
/** @var \Grumpydictator\Gchart\GChart $chart */
$chart = App::make('gchart');
$chart->addColumn('Month', 'date');
$chart->addColumn('Budgeted', 'number');
$chart->addColumn('Spent', 'number');
$end = clone $start;
$end->endOfYear();
while ($start <= $end) {
$spent = $repos->spentInMonth($component, $start);
$repetition = $repos->repetitionOnStartingOnDate($component, $start);
if ($repetition) {
$budgeted = floatval($repetition->amount);
} else {
$budgeted = null;
}
$chart->addRow(clone $start, $budgeted, $spent);
$start->addMonth();
}
$chart->generate();
return Response::json($chart->getData());
}
public function budgetLimitSpending(\Budget $budget, \LimitRepetition $repetition) {
$start = clone $repetition->startdate;
$end = $repetition->enddate;
/** @var \Grumpydictator\Gchart\GChart $chart */
$chart = App::make('gchart');
$chart->addColumn('Day', 'date');
$chart->addColumn('Left', 'number');
$amount = $repetition->amount;
while($start <= $end) {
/*
* Sum of expenses on this day:
*/
$sum = floatval($budget->transactionjournals()->lessThan(0)->transactionTypes(['Withdrawal'])->onDate($start)->sum('amount'));
$amount += $sum;
$chart->addRow(clone $start, $amount);
$start->addDay();
}
$chart->generate();
return Response::json($chart->getData());
}
/**
* @return \Illuminate\Http\JsonResponse
* @throws \FireflyIII\Exception\FireflyException
*/
public function recurringTransactionsOverview()
{
/*
* Set of paid transaction journals.
* Set of unpaid recurring transactions.
*/
$paid = ['items' => [], 'amount' => 0];
$unpaid = ['items' => [], 'amount' => 0];
/** @var \Grumpydictator\Gchart\GChart $chart */
$chart = App::make('gchart');
$chart->addColumn('Name', 'string');
$chart->addColumn('Amount', 'number');
/** @var \FireflyIII\Database\Recurring $rcr */
$rcr = App::make('FireflyIII\Database\Recurring');
/** @var \FireflyIII\Shared\Toolkit\Date $dateKit */
$dateKit = App::make('FireflyIII\Shared\Toolkit\Date');
$recurring = $rcr->get();
/** @var \RecurringTransaction $entry */
foreach ($recurring as $entry) {
/*
* Start another loop starting at the $date.
*/
$start = clone $entry->date;
$end = Carbon::now();
/*
* The jump we make depends on the $repeat_freq
*/
$current = clone $start;
while ($current <= $end) {
/*
* Get end of period for $current:
*/
$currentEnd = clone $current;
$dateKit->endOfPeriod($currentEnd, $entry->repeat_freq);
/*
* In the current session range?
*/
if (\Session::get('end') >= $current and $currentEnd >= \Session::get('start')) {
/*
* Lets see if we've already spent money on this recurring transaction (it hath recurred).
*/
/** @var TransactionJournal $set */
$journal = $rcr->getJournalForRecurringInRange($entry, $current, $currentEnd);
if (is_null($journal)) {
$unpaid['items'][] = $entry->name;
$unpaid['amount'] += (($entry->amount_max + $entry->amount_min) / 2);
} else {
$amount = $journal->getAmount();
$paid['items'][] = $journal->description;
$paid['amount'] += $amount;
}
}
/*
* Add some time for the next loop!
*/
$dateKit->addPeriod($current, $entry->repeat_freq, intval($entry->skip));
}
}
/** @var \RecurringTransaction $entry */
$chart->addRow('Unpaid: ' . join(', ', $unpaid['items']), $unpaid['amount']);
$chart->addRow('Paid: ' . join(', ', $paid['items']), $paid['amount']);
$chart->generate();
return Response::json($chart->getData());
}
/**
* @param $year
*
* @return \Illuminate\Http\JsonResponse
*/
public function yearInExp($year)
{
try {
$start = new Carbon('01-01-' . $year);
} catch (Exception $e) {
App::abort(500);
}
/** @var \Grumpydictator\Gchart\GChart $chart */
$chart = App::make('gchart');
$chart->addColumn('Month', 'date');
$chart->addColumn('Income', 'number');
$chart->addColumn('Expenses', 'number');
/** @var \FireflyIII\Database\TransactionJournal $tj */
$tj = App::make('FireflyIII\Database\TransactionJournal');
$end = clone $start;
$end->endOfYear();
while ($start < $end) {
// total income:
$income = $tj->getSumOfIncomesByMonth($start);
$expense = $tj->getSumOfExpensesByMonth($start);
$chart->addRow(clone $start, $income, $expense);
$start->addMonth();
}
$chart->generate();
return Response::json($chart->getData());
}
/**
* @param $year
*
* @return \Illuminate\Http\JsonResponse
*/
public function yearInExpSum($year)
{
try {
$start = new Carbon('01-01-' . $year);
} catch (Exception $e) {
App::abort(500);
}
/** @var \Grumpydictator\Gchart\GChart $chart */
$chart = App::make('gchart');
$chart->addColumn('Summary', 'string');
$chart->addColumn('Income', 'number');
$chart->addColumn('Expenses', 'number');
/** @var \FireflyIII\Database\TransactionJournal $tj */
$tj = App::make('FireflyIII\Database\TransactionJournal');
$end = clone $start;
$end->endOfYear();
$income = 0;
$expense = 0;
$count = 0;
while ($start < $end) {
// total income:
$income += $tj->getSumOfIncomesByMonth($start);
$expense += $tj->getSumOfExpensesByMonth($start);
$count++;
$start->addMonth();
}
$chart->addRow('Sum', $income, $expense);
$count = $count > 0 ? $count : 1;
$chart->addRow('Average', ($income / $count), ($expense / $count));
$chart->generate();
return Response::json($chart->getData());
}
}