mirror of
https://github.com/firefly-iii/firefly-iii.git
synced 2026-01-10 12:24:50 +00:00
Merge branch 'feature/google-charts' into develop
Conflicts: app/views/accounts/show.blade.php
This commit is contained in:
421
app/controllers/GoogleChartController.php
Normal file
421
app/controllers/GoogleChartController.php
Normal file
@@ -0,0 +1,421 @@
|
||||
<?php
|
||||
use Carbon\Carbon;
|
||||
|
||||
/**
|
||||
* Class GoogleChartController
|
||||
*/
|
||||
class GoogleChartController extends BaseController
|
||||
{
|
||||
|
||||
/**
|
||||
* 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');
|
||||
$accounts = $acct->getByIds($pref->data);
|
||||
|
||||
|
||||
/*
|
||||
* 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[] = null;
|
||||
} 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 = floatval($journal->transactions[1]->amount);
|
||||
$amount = $amount < 0 ? $amount * -1 : $amount;
|
||||
$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
|
||||
* @throws \Firefly\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 = floatval($journal->transactions[0]->amount);
|
||||
$amount = $amount < 0 ? $amount * -1 : $amount;
|
||||
$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 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 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());
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @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());
|
||||
|
||||
}
|
||||
}
|
||||
110
app/controllers/GoogleTableController.php
Normal file
110
app/controllers/GoogleTableController.php
Normal file
@@ -0,0 +1,110 @@
|
||||
<?php
|
||||
use Carbon\Carbon;
|
||||
|
||||
/**
|
||||
* Class GoogleTableController
|
||||
*/
|
||||
class GoogleTableController extends BaseController
|
||||
{
|
||||
/**
|
||||
* @param Account $account
|
||||
*/
|
||||
public function transactionsByAccount(Account $account)
|
||||
{
|
||||
$chart = App::make('gchart');
|
||||
$chart->addColumn('ID', 'number');
|
||||
$chart->addColumn('ID_Edit', 'string');
|
||||
$chart->addColumn('ID_Delete', 'string');
|
||||
$chart->addColumn('Date', 'date');
|
||||
$chart->addColumn('Description_URL', 'string');
|
||||
$chart->addColumn('Description', 'string');
|
||||
$chart->addColumn('Amount', 'number');
|
||||
$chart->addColumn('From_URL', 'string');
|
||||
$chart->addColumn('From', 'string');
|
||||
$chart->addColumn('To_URL', 'string');
|
||||
$chart->addColumn('To', 'string');
|
||||
$chart->addColumn('Budget_URL', 'string');
|
||||
$chart->addColumn('Budget', 'string');
|
||||
$chart->addColumn('Category_URL', 'string');
|
||||
$chart->addColumn('Category', 'string');
|
||||
|
||||
/*
|
||||
* Find transactions:
|
||||
*/
|
||||
$accountID = $account->id;
|
||||
$transactions = $account->transactions()->with(
|
||||
['transactionjournal', 'transactionjournal.transactions' => function ($q) use ($accountID) {
|
||||
$q->where('account_id', '!=', $accountID);
|
||||
}, 'transactionjournal.budgets', 'transactionjournal.transactiontype',
|
||||
'transactionjournal.categories']
|
||||
)->before(Session::get('end'))->after(
|
||||
Session::get('start')
|
||||
)->orderBy('date', 'DESC')->get();
|
||||
|
||||
/** @var Transaction $transaction */
|
||||
foreach ($transactions as $transaction) {
|
||||
$date = $transaction->transactionJournal->date;
|
||||
$descriptionURL = route('transactions.show', $transaction->transaction_journal_id);
|
||||
$description = $transaction->transactionJournal->description;
|
||||
$amount = floatval($transaction->amount);
|
||||
|
||||
if ($transaction->transactionJournal->transactions[0]->account->id == $account->id) {
|
||||
$opposingAccountURI = route('accounts.show', $transaction->transactionJournal->transactions[1]->account->id);
|
||||
$opposingAccountName = $transaction->transactionJournal->transactions[1]->account->name;
|
||||
} else {
|
||||
$opposingAccountURI = route('accounts.show', $transaction->transactionJournal->transactions[0]->account->id);
|
||||
$opposingAccountName = $transaction->transactionJournal->transactions[0]->account->name;
|
||||
}
|
||||
if (isset($transaction->transactionJournal->budgets[0])) {
|
||||
$budgetURL = route('budgets.show', $transaction->transactionJournal->budgets[0]->id);
|
||||
$budget = $transaction->transactionJournal->budgets[0]->name;
|
||||
} else {
|
||||
$budgetURL = '';
|
||||
$budget = '';
|
||||
}
|
||||
|
||||
if (isset($transaction->transactionJournal->categories[0])) {
|
||||
$categoryURL = route('categories.show', $transaction->transactionJournal->categories[0]->id);
|
||||
$category = $transaction->transactionJournal->categories[0]->name;
|
||||
} else {
|
||||
$budgetURL = '';
|
||||
$budget = '';
|
||||
}
|
||||
|
||||
|
||||
if ($amount < 0) {
|
||||
$from = $account->name;
|
||||
$fromURL = route('accounts.show', $account->id);
|
||||
|
||||
$to = $opposingAccountName;
|
||||
$toURL = $opposingAccountURI;
|
||||
} else {
|
||||
$to = $account->name;
|
||||
$toURL = route('accounts.show', $account->id);
|
||||
|
||||
$from = $opposingAccountName;
|
||||
$fromURL = $opposingAccountURI;
|
||||
}
|
||||
|
||||
$budcat = 'Budcat';
|
||||
$id = $transaction->transactionJournal->id;
|
||||
$edit = route('transactions.edit', $transaction->transactionJournal->id);
|
||||
$delete = route('transactions.delete', $transaction->transactionJournal->id);
|
||||
$chart->addRow(
|
||||
$id, $edit, $delete, $date, $descriptionURL, $description, $amount, $fromURL, $from, $toURL, $to, $budgetURL, $budget, $categoryURL, $category
|
||||
);
|
||||
}
|
||||
|
||||
// <th>Date</th>
|
||||
// <th>Description</th>
|
||||
// <th>Amount (€)</th>
|
||||
// <th>From</th>
|
||||
// <th>To</th>
|
||||
// <th>Budget / category</th>
|
||||
// <th>ID</th>
|
||||
|
||||
|
||||
$chart->generate();
|
||||
return Response::json($chart->getData());
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user