firefly-iii/app/Http/Controllers/GoogleChartController.php

639 lines
21 KiB
PHP
Raw Normal View History

<?php namespace FireflyIII\Http\Controllers;
2015-04-03 16:05:50 -05:00
use Amount;
2015-02-22 08:40:13 -06:00
use App;
use Auth;
use Carbon\Carbon;
2015-04-03 14:05:01 -05:00
use Crypt;
use DB;
2015-02-23 13:25:48 -06:00
use Exception;
use FireflyIII\Helpers\Report\ReportQueryInterface;
use FireflyIII\Models\Account;
use FireflyIII\Models\Bill;
use FireflyIII\Models\Budget;
2015-02-25 09:10:02 -06:00
use FireflyIII\Models\Category;
use FireflyIII\Models\LimitRepetition;
2015-02-25 09:10:02 -06:00
use FireflyIII\Models\PiggyBank;
2015-03-04 02:42:47 -06:00
use FireflyIII\Models\Preference;
2015-02-25 08:19:14 -06:00
use FireflyIII\Models\Transaction;
2015-02-25 09:10:02 -06:00
use FireflyIII\Models\TransactionJournal;
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
2015-03-03 10:40:17 -06:00
use FireflyIII\Repositories\Bill\BillRepositoryInterface;
2015-02-23 13:25:48 -06:00
use FireflyIII\Repositories\Budget\BudgetRepositoryInterface;
use FireflyIII\Repositories\Category\CategoryRepositoryInterface;
use Grumpydictator\Gchart\GChart;
use Illuminate\Support\Collection;
2015-02-25 09:10:02 -06:00
use Navigation;
use Preferences;
use Response;
use Session;
use Steam;
/**
* Class GoogleChartController
*
* @package FireflyIII\Http\Controllers
*/
class GoogleChartController extends Controller
{
2015-02-07 06:15:40 -06:00
2015-02-22 08:40:13 -06:00
/**
* @param Account $account
* @param string $view
*
* @return \Illuminate\Http\JsonResponse
*/
2015-03-02 13:05:28 -06:00
public function accountBalanceChart(Account $account, GChart $chart)
2015-02-22 08:40:13 -06:00
{
$chart->addColumn('Day of month', 'date');
$chart->addColumn('Balance for ' . $account->name, 'number');
2015-02-22 08:40:13 -06:00
$chart->addCertainty(1);
2015-03-02 13:05:28 -06:00
$start = Session::get('start', Carbon::now()->startOfMonth());
$end = Session::get('end', Carbon::now()->endOfMonth());
2015-02-22 08:40:13 -06:00
$current = clone $start;
2015-03-29 14:27:51 -05:00
$today = new Carbon;
2015-02-22 08:40:13 -06:00
while ($end >= $current) {
2015-03-27 13:47:31 -05:00
$certain = $current < $today;
2015-03-27 13:45:47 -05:00
$chart->addRow(clone $current, Steam::balance($account, $current), $certain);
2015-02-22 08:40:13 -06:00
$current->addDay();
}
$chart->generate();
return Response::json($chart->getData());
}
/**
* @param GChart $chart
*
* @return \Symfony\Component\HttpFoundation\Response
*/
public function allAccountsBalanceChart(GChart $chart, AccountRepositoryInterface $repository)
{
$chart->addColumn('Day of the month', 'date');
$frontPage = Preferences::get('frontPageAccounts', []);
$start = Session::get('start', Carbon::now()->startOfMonth());
$end = Session::get('end', Carbon::now()->endOfMonth());
$accounts = $repository->getFrontpageAccounts($frontPage);
$index = 1;
/** @var Account $account */
foreach ($accounts as $account) {
$accountName = $account->name;
$chart->addColumn('Balance for ' . $accountName, 'number');
$chart->addCertainty($index);
$index++;
}
$current = clone $start;
$current->subDay();
$today = Carbon::now();
while ($end >= $current) {
$row = [clone $current];
$certain = $current < $today;
foreach ($accounts as $account) {
$row[] = Steam::balance($account, $current);
$row[] = $certain;
}
$chart->addRowArray($row);
$current->addDay();
}
$chart->generate();
return Response::json($chart->getData());
}
2015-02-25 09:10:02 -06:00
/**
* @param int $year
*
* @return $this|\Illuminate\Http\JsonResponse
*/
public function allBudgetsAndSpending($year, GChart $chart, BudgetRepositoryInterface $repository)
{
$budgets = $repository->getBudgets();
2015-02-25 09:10:02 -06:00
$chart->addColumn('Month', 'date');
foreach ($budgets as $budget) {
$chart->addColumn($budget->name, 'number');
}
2015-02-25 09:10:02 -06:00
$start = Carbon::createFromDate(intval($year), 1, 1);
$end = clone $start;
$end->endOfYear();
while ($start <= $end) {
$row = [clone $start];
foreach ($budgets as $budget) {
$spent = $repository->spentInMonth($budget, $start);
$row[] = $spent;
}
$chart->addRowArray($row);
$start->addMonth();
}
$chart->generate();
return Response::json($chart->getData());
}
/**
* @param GChart $chart
*
* @return \Symfony\Component\HttpFoundation\Response
*/
public function allBudgetsHomeChart(GChart $chart, BudgetRepositoryInterface $repository)
{
$chart->addColumn('Budget', 'string');
$chart->addColumn('Budgeted', 'number');
$chart->addColumn('Spent', 'number');
$budgets = $repository->getBudgets();
$start = Session::get('start', Carbon::now()->startOfMonth());
$end = Session::get('end', Carbon::now()->endOfMonth());
$allEntries = new Collection;
foreach ($budgets as $budget) {
$repetitions = $repository->getBudgetLimitRepetitions($budget, $start, $end);
if ($repetitions->count() == 0) {
$expenses = $repository->sumBudgetExpensesInPeriod($budget, $start, $end);
$allEntries->push([$budget->name, 0, $expenses]);
continue;
}
/** @var LimitRepetition $repetition */
foreach ($repetitions as $repetition) {
$expenses = $repository->sumBudgetExpensesInPeriod($budget, $repetition->startdate, $repetition->enddate);
$allEntries->push([$budget->name . ' (' . $repetition->startdate->format('j M Y') . ')', floatval($repetition->amount), $expenses]);
}
}
$noBudgetExpenses = $repository->getWithoutBudgetSum($start, $end);
$allEntries->push(['(no budget)', 0, $noBudgetExpenses]);
foreach ($allEntries as $entry) {
if ($entry[2] > 0) {
$chart->addRow($entry[0], $entry[1], $entry[2]);
}
}
$chart->generate();
return Response::json($chart->getData());
}
2015-02-11 00:35:10 -06:00
/**
* @param GChart $chart
*
* @return \Symfony\Component\HttpFoundation\Response
*/
public function allCategoriesHomeChart(GChart $chart, CategoryRepositoryInterface $repository)
{
$chart->addColumn('Category', 'string');
$chart->addColumn('Spent', 'number');
$start = Session::get('start', Carbon::now()->startOfMonth());
$end = Session::get('end', Carbon::now()->endOfMonth());
$set = $repository->getCategoriesAndExpenses($start, $end);
foreach ($set as $entry) {
2015-03-31 08:10:22 -05:00
$isEncrypted = intval($entry->encrypted) == 1 ? true : false;
2015-04-03 14:05:01 -05:00
$name = strlen($entry->name) == 0 ? '(no category)' : $entry->name;
$name = $isEncrypted ? Crypt::decrypt($name) : $name;
2015-03-31 08:10:22 -05:00
$chart->addRow($name, floatval($entry->sum));
}
$chart->generate();
return Response::json($chart->getData());
}
2015-02-25 09:10:02 -06:00
/**
* @param Bill $bill
* @param GChart $chart
2015-02-25 09:10:02 -06:00
*
* @return \Symfony\Component\HttpFoundation\Response
2015-02-25 09:10:02 -06:00
*/
public function billOverview(Bill $bill, GChart $chart, BillRepositoryInterface $repository)
2015-02-25 09:10:02 -06:00
{
$chart->addColumn('Date', 'date');
$chart->addColumn('Max amount', 'number');
$chart->addColumn('Min amount', 'number');
2015-04-03 14:05:41 -05:00
$chart->addColumn('Recorded bill entry', 'number');
2015-02-25 09:10:02 -06:00
// get first transaction or today for start:
$results = $repository->getJournals($bill);
2015-04-03 14:05:01 -05:00
/** @var TransactionJournal $result */
foreach ($results as $result) {
$chart->addRow(clone $result->date, floatval($bill->amount_max), floatval($bill->amount_min), floatval($result->amount));
2015-02-25 09:10:02 -06:00
}
$chart->generate();
return Response::json($chart->getData());
}
2015-02-11 00:35:10 -06:00
/**
* @param GChart $chart
*
* @return \Symfony\Component\HttpFoundation\Response
*/
2015-03-03 10:40:17 -06:00
public function billsOverview(GChart $chart, BillRepositoryInterface $repository)
{
2015-03-03 10:40:17 -06:00
$chart->addColumn('Name', 'string');
$chart->addColumn('Amount', 'number');
$paid = ['items' => [], 'amount' => 0];
$unpaid = ['items' => [], 'amount' => 0];
$start = Session::get('start', Carbon::now()->startOfMonth());
$end = Session::get('end', Carbon::now()->endOfMonth());
$bills = $repository->getActiveBills();
2015-03-03 10:40:17 -06:00
/** @var Bill $bill */
foreach ($bills as $bill) {
$ranges = $repository->getRanges($bill, $start, $end);
foreach ($ranges as $range) {
// paid a bill in this range?
$count = $bill->transactionjournals()->before($range['end'])->after($range['start'])->count();
if ($count == 0) {
$unpaid['items'][] = $bill->name . ' (' . $range['start']->format('jS M Y') . ')';
$unpaid['amount'] += ($bill->amount_max + $bill->amount_min / 2);
} else {
$journal = $bill->transactionjournals()->with('transactions')->before($range['end'])->after($range['start'])->first();
$paid['items'][] = $journal->description;
$amount = 0;
foreach ($journal->transactions as $t) {
if (floatval($t->amount) > 0) {
$amount = floatval($t->amount);
}
}
$paid['amount'] += $amount;
}
}
}
2015-03-03 10:40:17 -06:00
2015-04-03 15:54:21 -05:00
/**
* Find credit card accounts and possibly unpaid credit card bills.
*/
$creditCards = Auth::user()->accounts()
->hasMetaValue('accountRole', 'ccAsset')
->hasMetaValue('ccType', 'monthlyFull')
->get(
[
'accounts.*',
'ccType.data as ccType',
'accountRole.data as accountRole'
]
);
// if the balance is not zero, the monthly payment is still underway.
/** @var Account $creditCard */
foreach ($creditCards as $creditCard) {
$balance = Steam::balance($creditCard, null, true);
$date = new Carbon($creditCard->getMeta('ccMonthlyPaymentDate'));
if ($balance < 0) {
// unpaid!
$unpaid['amount'] += $balance * -1;
2015-04-03 16:05:50 -05:00
$unpaid['items'][] = $creditCard->name . ' (expected ' . Amount::format(($balance * -1), false) . ') on the ' . $date->format('jS') . ')';
2015-04-03 15:54:21 -05:00
}
if ($balance == 0) {
// find a transfer TO the credit card which should account for
// anything paid. If not, the CC is not yet used.
$transactions = $creditCard->transactions()
->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id')
->before($end)->after($start)->get();
if ($transactions->count() > 0) {
/** @var Transaction $transaction */
foreach ($transactions as $transaction) {
$journal = $transaction->transactionJournal;
if ($journal->transactionType->type == 'Transfer') {
$paid['amount'] += floatval($transaction->amount);
2015-04-03 16:05:50 -05:00
$paid['items'][] = $creditCard->name .
' (paid ' . Amount::format((floatval($transaction->amount)), false) .
' on the ' . $journal->date->format('jS') . ')';
2015-04-03 15:54:21 -05:00
}
}
}
}
}
$chart->addRow('Unpaid: ' . join(', ', $unpaid['items']), $unpaid['amount']);
$chart->addRow('Paid: ' . join(', ', $paid['items']), $paid['amount']);
$chart->generate();
return Response::json($chart->getData());
}
2015-02-22 01:38:46 -06:00
/**
2015-02-22 08:40:13 -06:00
*
* @param Budget $budget
* @param LimitRepetition $repetition
2015-02-22 01:38:46 -06:00
*
* @return \Illuminate\Http\JsonResponse
*/
2015-02-22 08:40:13 -06:00
public function budgetLimitSpending(Budget $budget, LimitRepetition $repetition, GChart $chart)
2015-02-22 01:38:46 -06:00
{
2015-02-22 08:40:13 -06:00
$start = clone $repetition->startdate;
$end = $repetition->enddate;
2015-02-22 01:38:46 -06:00
2015-02-22 08:40:13 -06:00
$chart->addColumn('Day', 'date');
$chart->addColumn('Left', 'number');
2015-02-22 01:38:46 -06:00
2015-02-22 08:40:13 -06:00
$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();
2015-02-22 01:38:46 -06:00
}
2015-02-22 08:40:13 -06:00
$chart->generate();
2015-02-22 01:38:46 -06:00
2015-02-22 08:40:13 -06:00
return Response::json($chart->getData());
2015-02-22 01:38:46 -06:00
2015-02-22 08:40:13 -06:00
}
/**
*
* @param Budget $budget
*
* @param int $year
*
* @return \Illuminate\Http\JsonResponse
*/
public function budgetsAndSpending(Budget $budget, $year = 0)
{
$chart = App::make('Grumpydictator\Gchart\GChart');
$repository = App::make('FireflyIII\Repositories\Budget\BudgetRepository');
$chart->addColumn('Month', 'date');
$chart->addColumn('Budgeted', 'number');
$chart->addColumn('Spent', 'number');
if ($year == 0) {
// grab the first budgetlimit ever:
$firstLimit = $budget->budgetlimits()->orderBy('startdate', 'ASC')->first();
if ($firstLimit) {
$start = new Carbon($firstLimit->startdate);
} else {
$start = Carbon::now()->startOfYear();
}
// grab the last budget limit ever:
$lastLimit = $budget->budgetlimits()->orderBy('startdate', 'DESC')->first();
if ($lastLimit) {
$end = new Carbon($lastLimit->startdate);
} else {
$end = Carbon::now()->endOfYear();
}
} else {
$start = Carbon::createFromDate(intval($year), 1, 1);
$end = clone $start;
$end->endOfYear();
2015-02-22 01:38:46 -06:00
}
2015-02-22 08:40:13 -06:00
while ($start <= $end) {
$spent = $repository->spentInMonth($budget, $start);
$repetition = LimitRepetition::leftJoin('budget_limits', 'limit_repetitions.budget_limit_id', '=', 'budget_limits.id')
->where('limit_repetitions.startdate', $start->format('Y-m-d 00:00:00'))
->where('budget_limits.budget_id', $budget->id)
->first(['limit_repetitions.*']);
if ($repetition) {
$budgeted = floatval($repetition->amount);
\Log::debug('Found a repetition on ' . $start->format('Y-m-d') . ' for budget ' . $budget->name . '!');
} else {
\Log::debug('No repetition on ' . $start->format('Y-m-d') . ' for budget ' . $budget->name);
$budgeted = null;
}
$chart->addRow(clone $start, $budgeted, $spent);
$start->addMonth();
}
2015-02-22 01:38:46 -06:00
$chart->generate();
return Response::json($chart->getData());
2015-02-22 08:40:13 -06:00
2015-02-22 01:38:46 -06:00
}
2015-02-25 09:10:02 -06:00
/**
*
2015-03-04 02:42:47 -06:00
* @param Category $category
2015-02-25 09:10:02 -06:00
*
* @return \Illuminate\Http\JsonResponse
*/
2015-03-04 02:42:47 -06:00
public function categoryOverviewChart(Category $category, GChart $chart)
2015-02-25 09:10:02 -06:00
{
2015-03-04 02:42:47 -06:00
// oldest transaction in category:
/** @var TransactionJournal $first */
$first = $category->transactionjournals()->orderBy('date', 'ASC')->first();
$start = $first->date;
/** @var Preference $range */
$range = Preferences::get('viewRange', '1M');
// jump to start of week / month / year / etc (TODO).
$start = Navigation::startOfPeriod($start, $range->data);
$chart->addColumn('Period', 'date');
2015-02-25 09:10:02 -06:00
$chart->addColumn('Spent', 'number');
2015-03-04 02:42:47 -06:00
$end = new Carbon;
2015-02-25 09:10:02 -06:00
while ($start <= $end) {
2015-03-04 02:42:47 -06:00
$currentEnd = Navigation::endOfPeriod($start, $range->data);
$spent = floatval($category->transactionjournals()->before($currentEnd)->after($start)->lessThan(0)->sum('amount')) * -1;
$chart->addRow(clone $start, $spent);
2015-02-25 09:10:02 -06:00
2015-03-04 02:42:47 -06:00
$start = Navigation::addPeriod($start, $range->data, 0);
2015-02-25 09:10:02 -06:00
}
$chart->generate();
return Response::json($chart->getData());
}
2015-03-04 02:42:47 -06:00
/**
*
* @param Category $category
*
* @return \Illuminate\Http\JsonResponse
*/
public function categoryPeriodChart(Category $category, GChart $chart)
{
// oldest transaction in category:
/** @var TransactionJournal $first */
$start = clone Session::get('start');
2015-03-04 02:42:47 -06:00
$chart->addColumn('Period', 'date');
$chart->addColumn('Spent', 'number');
$end = Session::get('end');
while ($start <= $end) {
2015-03-10 11:26:31 -05:00
$spent = floatval($category->transactionjournals()->onDate($start)->lessThan(0)->sum('amount')) * -1;
2015-03-04 02:42:47 -06:00
$chart->addRow(clone $start, $spent);
$start->addDay();
}
$chart->generate();
return Response::json($chart->getData());
}
2015-02-25 09:10:02 -06:00
/**
* @param PiggyBank $piggyBank
*
* @return \Illuminate\Http\JsonResponse
*/
public function piggyBankHistory(PiggyBank $piggyBank, GChart $chart)
{
$chart->addColumn('Date', 'date');
$chart->addColumn('Balance', 'number');
2015-03-24 15:04:53 -05:00
/** @var Collection $set */
$set = DB::table('piggy_bank_events')->where('piggy_bank_id', $piggyBank->id)->groupBy('date')->get(['date', DB::Raw('SUM(`amount`) AS `sum`')]);
2015-03-24 15:05:15 -05:00
$sum = 0;
2015-02-25 09:10:02 -06:00
foreach ($set as $entry) {
2015-03-24 15:04:53 -05:00
$sum += floatval($entry->sum);
$chart->addRow(new Carbon($entry->date), $sum);
2015-02-25 09:10:02 -06:00
}
$chart->generate();
return Response::json($chart->getData());
}
2015-02-23 13:25:48 -06:00
/**
*
* @param $year
*
* @return \Illuminate\Http\JsonResponse
*/
public function yearInExp($year, GChart $chart, ReportQueryInterface $query)
{
try {
$start = new Carbon('01-01-' . $year);
} catch (Exception $e) {
return view('error')->with('message', 'Invalid year.');
}
$chart->addColumn('Month', 'date');
$chart->addColumn('Income', 'number');
$chart->addColumn('Expenses', 'number');
2015-03-10 14:26:52 -05:00
$pref = Preferences::get('showSharedReports', false);
$showSharedReports = $pref->data;
2015-02-23 13:25:48 -06:00
// get report query interface.
$end = clone $start;
$end->endOfYear();
while ($start < $end) {
$currentEnd = clone $start;
$currentEnd->endOfMonth();
// total income:
2015-03-10 14:26:52 -05:00
$income = $query->incomeByPeriod($start, $currentEnd, $showSharedReports);
2015-02-23 13:25:48 -06:00
$incomeSum = 0;
foreach ($income as $entry) {
$incomeSum += floatval($entry->amount);
}
// total expenses:
2015-03-10 14:26:52 -05:00
$expense = $query->journalsByExpenseAccount($start, $currentEnd, $showSharedReports);
2015-02-23 13:25:48 -06:00
$expenseSum = 0;
foreach ($expense as $entry) {
$expenseSum += floatval($entry->amount);
}
$chart->addRow(clone $start, $incomeSum, $expenseSum);
$start->addMonth();
}
$chart->generate();
return Response::json($chart->getData());
}
/**
*
* @param $year
*
* @return \Illuminate\Http\JsonResponse
*/
public function yearInExpSum($year, GChart $chart, ReportQueryInterface $query)
{
try {
$start = new Carbon('01-01-' . $year);
} catch (Exception $e) {
return view('error')->with('message', 'Invalid year.');
}
$chart->addColumn('Summary', 'string');
$chart->addColumn('Income', 'number');
$chart->addColumn('Expenses', 'number');
2015-03-10 14:26:52 -05:00
$pref = Preferences::get('showSharedReports', false);
$showSharedReports = $pref->data;
2015-02-23 13:25:48 -06:00
$income = 0;
$expense = 0;
$count = 0;
$end = clone $start;
$end->endOfYear();
while ($start < $end) {
$currentEnd = clone $start;
$currentEnd->endOfMonth();
// total income:
2015-03-10 14:26:52 -05:00
$incomeResult = $query->incomeByPeriod($start, $currentEnd, $showSharedReports);
2015-02-23 13:25:48 -06:00
$incomeSum = 0;
foreach ($incomeResult as $entry) {
$incomeSum += floatval($entry->amount);
}
// total expenses:
2015-03-10 14:26:52 -05:00
$expenseResult = $query->journalsByExpenseAccount($start, $currentEnd, $showSharedReports);
2015-02-23 13:25:48 -06:00
$expenseSum = 0;
foreach ($expenseResult as $entry) {
$expenseSum += floatval($entry->amount);
}
$income += $incomeSum;
$expense += $expenseSum;
$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());
}
}