diff --git a/app/controllers/ReportController.php b/app/controllers/ReportController.php
index 81e7de76b8..a759ba17cc 100644
--- a/app/controllers/ReportController.php
+++ b/app/controllers/ReportController.php
@@ -62,18 +62,20 @@ class ReportController extends BaseController
} catch (Exception $e) {
View::make('error')->with('message', 'Invalid date');
}
- $date = new Carbon($year . '-' . $month . '-01');
+ $date = new Carbon($year . '-' . $month . '-01');
$subTitle = 'Report for ' . $date->format('F Y');
$subTitleIcon = 'fa-calendar';
- $income = $this->_repository->getIncomeForMonth($date,false);
+ $displaySum = true; // to show sums in report.
+ $income = $this->_repository->getIncomeForMonth($date);
+ $expenses = $this->_repository->getExpenseGroupedForMonth($date, 10);
+ $budgets = $this->_repository->getBudgetsForMonth($date);
+ $categories = $this->_repository->getCategoriesForMonth($date, 10);
+ $accounts = $this->_repository->getAccountsForMonth($date);
-// var_dump($income->toArray());
-// exit;
-
-
-
-
- return View::make('reports.month', compact('date', 'subTitle', 'subTitleIcon','income'));
+ return View::make(
+ 'reports.month',
+ compact('accounts', 'categories', 'budgets', 'expenses', 'subTitle', 'displaySum', 'subTitleIcon', 'income')
+ );
}
/**
diff --git a/app/database/migrations/2014_12_24_191544_changes_for_v322.php b/app/database/migrations/2014_12_24_191544_changes_for_v322.php
index 143c4fe376..4d400e97b7 100644
--- a/app/database/migrations/2014_12_24_191544_changes_for_v322.php
+++ b/app/database/migrations/2014_12_24_191544_changes_for_v322.php
@@ -13,7 +13,29 @@ class ChangesForV322 extends Migration
*/
public function down()
{
- // TODO
+ // rename tables:
+ Schema::rename('piggy_bank_repetitions', 'piggybank_repetitions');
+ Schema::rename('piggy_banks', 'piggybanks');
+
+ // rename fields
+ Schema::table(
+ 'piggy_bank_events', function (Blueprint $table) {
+ $table->renameColumn('piggy_bank_id', 'piggybank_id');
+ }
+ );
+
+ Schema::table(
+ 'piggybank_repetitions', function (Blueprint $table) {
+ $table->renameColumn('piggy_bank_id', 'piggybank_id');
+ }
+ );
+
+ // remove soft delete to piggy banks
+ Schema::table(
+ 'piggybanks', function (Blueprint $table) {
+ $table->dropSoftDeletes();
+ }
+ );
}
@@ -28,6 +50,19 @@ class ChangesForV322 extends Migration
Schema::rename('piggybank_repetitions', 'piggy_bank_repetitions');
Schema::rename('piggybanks', 'piggy_banks');
+ // drop an invalid index.
+ Schema::table(
+ 'budget_limits', function (Blueprint $table) {
+ $table->dropIndex('limits_component_id_startdate_repeat_freq_unique');
+ }
+ );
+ // recreate it the correct way:
+ Schema::table(
+ 'budget_limits', function (Blueprint $table) {
+ $table->unique(['budget_id', 'startdate', 'repeat_freq'], 'unique_bl_combi');
+ }
+ );
+
// rename fields
Schema::table(
'piggy_bank_events', function (Blueprint $table) {
diff --git a/app/lib/FireflyIII/Report/Report.php b/app/lib/FireflyIII/Report/Report.php
index 0b59efcc4c..eb3afeb88b 100644
--- a/app/lib/FireflyIII/Report/Report.php
+++ b/app/lib/FireflyIII/Report/Report.php
@@ -6,7 +6,9 @@ use Carbon\Carbon;
use FireflyIII\Database\Account\Account as AccountRepository;
use FireflyIII\Database\SwitchUser;
use FireflyIII\Database\TransactionJournal\TransactionJournal as JournalRepository;
+use Illuminate\Database\Query\JoinClause;
use Illuminate\Support\Collection;
+use stdClass;
// todo add methods to itnerface
@@ -80,6 +82,273 @@ class Report implements ReportInterface
}
+ /**
+ * @param Carbon $date
+ *
+ * @return Collection
+ */
+ public function getAccountsForMonth(Carbon $date)
+ {
+ $start = clone $date;
+ $start->startOfMonth();
+ $end = clone $date;
+ $end->endOfMonth();
+ $list = \Auth::user()->accounts()
+ ->leftJoin('account_types', 'account_types.id', '=', 'accounts.account_type_id')
+ ->leftJoin(
+ 'account_meta', function (JoinClause $join) {
+ $join->on('account_meta.account_id', '=', 'accounts.id')->where('account_meta.name', '=', "accountRole");
+ }
+ )
+ ->whereIn('account_types.type', ['Default account', 'Cash account', 'Asset account'])
+ ->where('active', 1)
+ ->where(
+ function ($query) {
+ $query->where('account_meta.data', '!=', '"sharedExpense"');
+ $query->orWhereNull('account_meta.data');
+ }
+ )
+ ->get(['accounts.*']);
+ $list->each(
+ function (\Account $account) use ($start, $end) {
+ $account->startBalance = \Steam::balance($account, $start);
+ $account->endBalance = \Steam::balance($account, $end);
+ $account->difference = $account->endBalance - $account->startBalance;
+ }
+ );
+
+ return $list;
+ }
+
+ /**
+ * @param Carbon $date
+ *
+ * @return Collection
+ */
+ public function getBudgetsForMonth(Carbon $date)
+ {
+ $start = clone $date;
+ $start->startOfMonth();
+ $end = clone $date;
+ $end->endOfMonth();
+ // all budgets
+ /** @var Collection $budgets */
+ $budgets = \Auth::user()->budgets()
+ ->leftJoin(
+ 'budget_limits', function (JoinClause $join) use ($date) {
+ $join->on('budget_limits.budget_id', '=', 'budgets.id')->where('budget_limits.startdate', '=', $date->format('Y-m-d'));
+ }
+ )
+ ->get(['budgets.*', 'budget_limits.amount as budget_amount']);
+ $amounts = \Auth::user()->transactionjournals()
+ ->leftJoin('budget_transaction_journal', 'budget_transaction_journal.transaction_journal_id', '=', 'transaction_journals.id')
+ ->leftJoin('budgets', 'budget_transaction_journal.budget_id', '=', 'budgets.id')
+ ->leftJoin(
+ 'transactions', function (JoinClause $join) {
+ $join->on('transaction_journals.id', '=', 'transactions.transaction_journal_id')->where('transactions.amount', '<', 0);
+ }
+ )
+ ->leftJoin('accounts', 'accounts.id', '=', 'transactions.account_id')
+ ->leftJoin(
+ 'account_meta', function (JoinClause $join) {
+ $join->on('account_meta.account_id', '=', 'accounts.id')->where('account_meta.name', '=', 'accountRole');
+ }
+ )
+ ->leftJoin('transaction_types', 'transaction_journals.transaction_type_id', '=', 'transaction_types.id')
+ ->where('transaction_journals.date', '>=', $start->format('Y-m-d'))
+ ->where('transaction_journals.date', '<=', $end->format('Y-m-d'))
+ ->where('account_meta.data', '!=', '"sharedExpense"')
+ ->where('transaction_types.type', 'Withdrawal')
+ ->groupBy('budgets.id')
+ ->orderBy('name','ASC')
+ ->get(['budgets.id', 'budgets.name', \DB::Raw('SUM(`transactions`.`amount`) AS `sum`')]);
+
+
+ $spentNoBudget = 0;
+ foreach ($budgets as $budget) {
+ $budget->spent = 0;
+ foreach ($amounts as $amount) {
+ if (intval($budget->id) == intval($amount->id)) {
+ $budget->spent = floatval($amount->sum) * -1;
+ }
+ if (is_null($amount->id)) {
+ $spentNoBudget = floatval($amount->sum) * -1;
+ }
+ }
+ }
+
+ $noBudget = new stdClass;
+ $noBudget->id = 0;
+ $noBudget->name = '(no budget)';
+ $noBudget->budget_amount = 0;
+ $noBudget->spent = $spentNoBudget;
+
+ // also get transfers to expense accounts (which are without a budget, and grouped).
+ $transfers = $this->getTransfersToSharedAccounts($date);
+ foreach($transfers as $transfer) {
+ $noBudget->spent += floatval($transfer->sum) * -1;
+ }
+
+
+ $budgets->push($noBudget);
+
+ return $budgets;
+ }
+
+ /**
+ * @param Carbon $date
+ * @param int $limit
+ *
+ * @return Collection
+ */
+ public function getCategoriesForMonth(Carbon $date, $limit = 15)
+ {
+ $start = clone $date;
+ $start->startOfMonth();
+ $end = clone $date;
+ $end->endOfMonth();
+ // all categories.
+ $amounts = \Auth::user()->transactionjournals()
+ ->leftJoin(
+ 'category_transaction_journal', 'category_transaction_journal.transaction_journal_id', '=', 'transaction_journals.id'
+ )
+ ->leftJoin('categories', 'category_transaction_journal.category_id', '=', 'categories.id')
+ ->leftJoin(
+ 'transactions', function (JoinClause $join) {
+ $join->on('transaction_journals.id', '=', 'transactions.transaction_journal_id')->where('transactions.amount', '<', 0);
+ }
+ )
+ ->leftJoin('accounts', 'accounts.id', '=', 'transactions.account_id')
+ ->leftJoin(
+ 'account_meta', function (JoinClause $join) {
+ $join->on('account_meta.account_id', '=', 'accounts.id')->where('account_meta.name', '=', 'accountRole');
+ }
+ )
+ ->leftJoin('transaction_types', 'transaction_journals.transaction_type_id', '=', 'transaction_types.id')
+ ->where('transaction_journals.date', '>=', $start->format('Y-m-d'))
+ ->where('transaction_journals.date', '<=', $end->format('Y-m-d'))
+ ->where('account_meta.data', '!=', '"sharedExpense"')
+ ->where('transaction_types.type', 'Withdrawal')
+ ->groupBy('categories.id')
+ ->orderBy('sum')
+ ->get(['categories.id', 'categories.name', \DB::Raw('SUM(`transactions`.`amount`) AS `sum`')]);
+ $spentNoCategory = 0;
+ foreach ($amounts as $amount) {
+ if (is_null($amount->id)) {
+ $spentNoCategory = floatval($amount->sum) * -1;
+ }
+ }
+ $noCategory = new stdClass;
+ $noCategory->id = 0;
+ $noCategory->name = '(no category)';
+ $noCategory->sum = $spentNoCategory;
+ $amounts->push($noCategory);
+
+ $return = new Collection;
+ $bottom = new stdClass();
+ $bottom->name = 'Others';
+ $bottom->id = 0;
+ $bottom->sum = 0;
+
+ foreach ($amounts as $index => $entry) {
+ if ($index < $limit) {
+ $return->push($entry);
+ } else {
+ $bottom->sum += floatval($entry->sum);
+ }
+ }
+ $return->push($bottom);
+
+ return $return;
+ }
+
+ /**
+ * @param Carbon $date
+ * @param int $limit
+ *
+ * @return Collection
+ */
+ public function getExpenseGroupedForMonth(Carbon $date, $limit = 15)
+ {
+ $start = clone $date;
+ $start->startOfMonth();
+ $end = clone $date;
+ $end->endOfMonth();
+ $userId = $this->_accounts->getUser()->id;
+
+ $set = \TransactionJournal::
+ leftJoin('transaction_types', 'transaction_types.id', '=', 'transaction_journals.transaction_type_id')
+ ->leftJoin(
+ 'transactions', function (JoinClause $join) {
+ $join->on('transaction_journals.id', '=', 'transactions.transaction_journal_id')->where(
+ 'transactions.amount', '>', 0
+ );
+ }
+ )
+ ->leftJoin('accounts', 'accounts.id', '=', 'transactions.account_id')
+ ->leftJoin(
+ 'transactions AS otherTransactions', function (JoinClause $join) {
+ $join->on('transaction_journals.id', '=', 'otherTransactions.transaction_journal_id')->where(
+ 'otherTransactions.amount', '<', 0
+ );
+ }
+ )
+ ->leftJoin('accounts as otherAccounts', 'otherAccounts.id', '=', 'otherTransactions.account_id')
+ ->leftJoin(
+ 'account_meta', function (JoinClause $join) {
+ $join->on('otherAccounts.id', '=', 'account_meta.account_id')->where('account_meta.name', '=', 'accountRole');
+ }
+ )
+ ->where('date', '>=', $start->format('Y-m-d'))
+ ->where('date', '<=', $end->format('Y-m-d'))
+ ->where('account_meta.data', '!=', '"sharedExpense"')
+ ->where('transaction_types.type', 'Withdrawal')
+ ->whereNull('transaction_journals.deleted_at')
+ ->where('transaction_journals.user_id', $userId)
+ ->groupBy('account_id')
+ ->orderBy('sum', 'ASC')
+ ->get(
+ [
+ 'transactions.account_id',
+ 'accounts.name',
+ \DB::Raw('SUM(`transactions`.`amount`) * -1 AS `sum`')
+ ]
+ );
+ $transfers = $this->getTransfersToSharedAccounts($date);
+ // merge $transfers into $set
+ foreach ($transfers as $transfer) {
+ if (!is_null($transfer->account_id)) {
+ $set->push($transfer);
+ }
+ }
+ // sort the list.
+ $set = $set->sortBy(
+ function ($entry) {
+ return floatval($entry->sum);
+ }
+ );
+ $return = new Collection;
+ $bottom = new stdClass();
+ $bottom->name = 'Others';
+ $bottom->account_id = 0;
+ $bottom->sum = 0;
+
+ $count = 0;
+ foreach ($set as $entry) {
+ if ($count < $limit) {
+ $return->push($entry);
+ } else {
+ $bottom->sum += floatval($entry->sum);
+ }
+ $count++;
+ }
+
+ $return->push($bottom);
+
+ return $return;
+
+ }
+
/**
* @param Carbon $date
* @param bool $shared
@@ -95,15 +364,87 @@ class Report implements ReportInterface
$userId = $this->_accounts->getUser()->id;
$list = \TransactionJournal::withRelevantData()
+ ->leftJoin('transactions', 'transaction_journals.id', '=', 'transactions.transaction_journal_id')
+ ->leftJoin('accounts', 'transactions.account_id', '=', 'accounts.id')
+ ->leftJoin(
+ 'account_meta', function (JoinClause $join) {
+ $join->on('account_meta.account_id', '=', 'accounts.id')->where('account_meta.name', '=', 'accountRole');
+ }
+ )
->transactionTypes(['Deposit'])
- ->where('user_id', $userId)
- ->orderBy('date','DESC')
+ ->where('transaction_journals.user_id', $userId)
+ ->where('transactions.amount', '>', 0)
+ ->where('account_meta.data', '!=', '"sharedExpense"')
+ ->orderBy('date', 'ASC')
->before($end)->after($start)->get(['transaction_journals.*']);
+ // incoming from a shared account: it's profit (income):
+ $transfers = \TransactionJournal::withRelevantData()
+ ->leftJoin('transactions', 'transaction_journals.id', '=', 'transactions.transaction_journal_id')
+ ->leftJoin('accounts', 'transactions.account_id', '=', 'accounts.id')
+ ->leftJoin(
+ 'account_meta', function (JoinClause $join) {
+ $join->on('account_meta.account_id', '=', 'accounts.id')->where('account_meta.name', '=', 'accountRole');
+ }
+ )
+ ->transactionTypes(['Transfer'])
+ ->where('transaction_journals.user_id', $userId)
+ ->where('transactions.amount', '<', 0)
+ ->where('account_meta.data', '=', '"sharedExpense"')
+ ->orderBy('date', 'ASC')
+ ->before($end)->after($start)->get(['transaction_journals.*']);
+
+ $list = $list->merge($transfers);
+ $list->sort(
+ function (\TransactionJournal $journal) {
+ return $journal->date->format('U');
+ }
+ );
return $list;
}
+ /**
+ * @param Carbon $date
+ *
+ * @return Collection
+ */
+ public function getTransfersToSharedAccounts(Carbon $date)
+ {
+ $start = clone $date;
+ $start->startOfMonth();
+ $end = clone $date;
+ $end->endOfMonth();
+
+ return \TransactionJournal::
+ leftJoin('transaction_types', 'transaction_types.id', '=', 'transaction_journals.transaction_type_id')
+ ->leftJoin(
+ 'transactions', function (JoinClause $join) {
+ $join->on('transactions.transaction_journal_id', '=', 'transaction_journals.id')->where(
+ 'transactions.amount', '>', 0
+ );
+ }
+ )
+ ->leftJoin('accounts', 'accounts.id', '=', 'transactions.account_id')
+ ->leftJoin(
+ 'account_meta', function (JoinClause $join) {
+ $join->on('account_meta.account_id', '=', 'accounts.id')->where('account_meta.name', '=', 'accountRole');
+ }
+ )
+ ->where('account_meta.data', '"sharedExpense"')
+ ->where('date', '>=', $start->format('Y-m-d'))
+ ->where('date', '<=', $end->format('Y-m-d'))
+ ->where('transaction_types.type', 'Transfer')
+ ->where('transaction_journals.user_id', \Auth::user()->id)
+ ->get(
+ [
+ 'transactions.account_id',
+ 'accounts.name',
+ \DB::Raw('SUM(`transactions`.`amount`) * -1 AS `sum`')
+ ]
+ );
+ }
+
/**
* @param Carbon $start
*
diff --git a/app/lib/FireflyIII/Report/ReportInterface.php b/app/lib/FireflyIII/Report/ReportInterface.php
index 7cef787cb4..c3dbc57b03 100644
--- a/app/lib/FireflyIII/Report/ReportInterface.php
+++ b/app/lib/FireflyIII/Report/ReportInterface.php
@@ -15,21 +15,57 @@ interface ReportInterface
/**
* @param Carbon $start
* @param Carbon $end
- * @param int $limit
- *
- * @return Collection
- */
- public function revenueGroupedByAccount(Carbon $start, Carbon $end, $limit = 15);
-
- /**
- * @param Carbon $start
- * @param Carbon $end
- * @param int $limit
+ * @param int $limit
*
* @return Collection
*/
public function expensesGroupedByAccount(Carbon $start, Carbon $end, $limit = 15);
+ /**
+ * @param Carbon $date
+ *
+ * @return Collection
+ */
+ public function getBudgetsForMonth(Carbon $date);
+
+ /**
+ * @param Carbon $date
+ *
+ * @return Collection
+ */
+ public function getTransfersToSharedAccounts(Carbon $date);
+
+ /**
+ * @param Carbon $date
+ * @param int $limit
+ *
+ * @return Collection
+ */
+ public function getCategoriesForMonth(Carbon $date, $limit = 15);
+
+ /**
+ * @param Carbon $date
+ *
+ * @return Collection
+ */
+ public function getAccountsForMonth(Carbon $date);
+
+ /**
+ * @param Carbon $date
+ * @param int $limit
+ *
+ * @return Collection
+ */
+ public function getExpenseGroupedForMonth(Carbon $date, $limit = 15);
+
+ /**
+ * @param Carbon $date
+ * @param bool $shared
+ *
+ * @return Collection
+ */
+ public function getIncomeForMonth(Carbon $date, $shared = false);
+
/**
* @param Carbon $start
*
@@ -44,18 +80,19 @@ interface ReportInterface
*/
public function listOfYears(Carbon $start);
+ /**
+ * @param Carbon $start
+ * @param Carbon $end
+ * @param int $limit
+ *
+ * @return Collection
+ */
+ public function revenueGroupedByAccount(Carbon $start, Carbon $end, $limit = 15);
+
/**
* @param Carbon $date
*
* @return array
*/
public function yearBalanceReport(Carbon $date);
-
- /**
- * @param Carbon $date
- * @param bool $shared
- *
- * @return Collection
- */
- public function getIncomeForMonth(Carbon $date, $shared = false);
}
\ No newline at end of file
diff --git a/app/views/list/journals-small.blade.php b/app/views/list/journals-small.blade.php
index 31af0154ff..02ea6c7939 100644
--- a/app/views/list/journals-small.blade.php
+++ b/app/views/list/journals-small.blade.php
@@ -1,10 +1,13 @@
+
@foreach($journals as $journal)
+
|
{{{$journal->description}}}
|
+ transactions[1]->amount);?>
@if($journal->transactiontype->type == 'Withdrawal')
{{mf($journal->transactions[1]->amount,false)}}
@endif
@@ -26,6 +29,12 @@
@endif
|
-
@endforeach
+ @if(isset($displaySum) && $displaySum === true)
+
+ | Sum |
+ {{mf($tableSum)}} |
+
+
+ @endif
\ No newline at end of file
diff --git a/app/views/reports/month.blade.php b/app/views/reports/month.blade.php
index 44ff3e529a..796de9cd9c 100644
--- a/app/views/reports/month.blade.php
+++ b/app/views/reports/month.blade.php
@@ -11,7 +11,24 @@
Expenses (top 10)
-
Body
+
+
+ @foreach($expenses as $expense)
+ sum);?>
+
+ @if($expense->account_id != 0)
+ | {{{$expense->name}}} |
+ @else
+ {{{$expense->name}}} |
+ @endif
+ {{mf($expense->sum)}} |
+
+ @endforeach
+
+ | Sum |
+ {{mf($sum)}} |
+
+
@@ -19,13 +36,69 @@
Budgets
-
Body
+
+
+ | Budget |
+ Envelope |
+ Spent |
+ Left |
+
+
+ @foreach($budgets as $budget)
+ spent);?>
+
+ |
+ @if($budget->id > 0)
+ {{{$budget->name}}}
+ @else
+ {{{$budget->name}}}
+ @endif
+ |
+ {{mf($budget->budget_amount)}} |
+ {{mf($budget->spent,false)}} |
+ {{mf(floatval($budget->budget_amount) - floatval($budget->spent))}} |
+
+ @endforeach
+
+ | Sum |
+ {{mf($sum)}} |
+
+
+
+ This list does not take in account outgoing transfers to shared accounts.
+
Categories
-
Body
+
+
+ | Category |
+ Spent |
+
+
+ @foreach($categories as $category)
+ sum);?>
+
+ |
+ @if($category->id > 0)
+ {{{$category->name}}}
+ @else
+ {{{$category->name}}}
+ @endif
+ |
+ {{mf($category->sum,false)}} |
+
+ @endforeach
+
+ | Sum |
+ {{mf($sum)}} |
+
+
+
+ This list does not take in account outgoing transfers to shared accounts.
+
@@ -33,7 +106,32 @@
Accounts
-
Body
+
+
+ @foreach($accounts as $account)
+ startBalance;
+ $sumEnd += $account->endBalance;
+ $sumDiff += $account->difference;
+ ?>
+
+ | {{{$account->name}}} |
+ {{mf($account->startBalance)}} |
+ {{mf($account->endBalance)}} |
+ {{mf($account->difference)}} |
+
+ @endforeach
+
+ | Sum |
+ {{mf($sumStart)}} |
+ {{mf($sumEnd)}} |
+ {{mf($sumDiff)}} |
+
+