mirror of
				https://github.com/firefly-iii/firefly-iii.git
				synced 2025-10-31 18:54:58 +00:00 
			
		
		
		
	Expanded reports.
This commit is contained in:
		| @@ -71,6 +71,7 @@ class ReportController extends BaseController | ||||
|         $budgets      = $this->_repository->getBudgetsForMonth($date); | ||||
|         $categories   = $this->_repository->getCategoriesForMonth($date, 10); | ||||
|         $accounts     = $this->_repository->getAccountsForMonth($date); | ||||
|         $piggyBanks   = $this->_repository->getPiggyBanksForMonth($date); | ||||
|  | ||||
|         return View::make( | ||||
|             'reports.month', | ||||
|   | ||||
| @@ -389,7 +389,12 @@ class TransactionJournal implements TransactionJournalInterface, CUD, CommonData | ||||
|             if ($category) { | ||||
|                 $journal->categories()->sync([$category->id]); | ||||
|             } | ||||
|  | ||||
|             return; | ||||
|         } | ||||
|         $journal->categories()->sync([]); | ||||
|  | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|   | ||||
| @@ -96,6 +96,8 @@ class FF3ServiceProvider extends ServiceProvider | ||||
|  | ||||
|         // reports | ||||
|         $this->app->bind('FireflyIII\Report\ReportInterface', 'FireflyIII\Report\Report'); | ||||
|         $this->app->bind('FireflyIII\Report\ReportQueryInterface', 'FireflyIII\Report\ReportQuery'); | ||||
|         $this->app->bind('FireflyIII\Report\ReportHelperInterface', 'FireflyIII\Report\ReportHelper'); | ||||
|  | ||||
|         // chart | ||||
|         $this->app->bind('FireflyIII\Chart\ChartInterface', 'FireflyIII\Chart\Chart'); | ||||
|   | ||||
| @@ -6,11 +6,12 @@ use Carbon\Carbon; | ||||
| use FireflyIII\Database\Account\Account as AccountRepository; | ||||
| use FireflyIII\Database\SwitchUser; | ||||
| use FireflyIII\Database\TransactionJournal\TransactionJournal as JournalRepository; | ||||
| use Illuminate\Database\Eloquent\Builder; | ||||
| use Illuminate\Database\Query\JoinClause; | ||||
| use Illuminate\Support\Collection; | ||||
| use stdClass; | ||||
|  | ||||
| // todo add methods to itnerface | ||||
| // todo add methods to interface | ||||
|  | ||||
| /** | ||||
|  * Class Report | ||||
| @@ -25,9 +26,12 @@ class Report implements ReportInterface | ||||
|  | ||||
|     /** @var AccountRepository */ | ||||
|     protected $_accounts; | ||||
|  | ||||
|     /** @var  \FireflyIII\Report\ReportHelperInterface */ | ||||
|     protected $_helper; | ||||
|     /** @var JournalRepository */ | ||||
|     protected $_journals; | ||||
|     /** @var  \FireflyIII\Report\ReportQueryInterface */ | ||||
|     protected $_queries; | ||||
|  | ||||
|     /** | ||||
|      * @param AccountRepository $accounts | ||||
| @@ -36,10 +40,15 @@ class Report implements ReportInterface | ||||
|     { | ||||
|         $this->_accounts = $accounts; | ||||
|         $this->_journals = $journals; | ||||
|         $this->_queries  = \App::make('FireflyIII\Report\ReportQueryInterface'); | ||||
|         $this->_helper   = \App::make('FireflyIII\Report\ReportHelperInterface'); | ||||
|  | ||||
|  | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * TODO Used in yearly report, so not ready for cleanup. | ||||
|      * | ||||
|      * @param Carbon $start | ||||
|      * @param Carbon $end | ||||
|      * @param int    $limit | ||||
| @@ -76,7 +85,7 @@ class Report implements ReportInterface | ||||
|                                   ->where('acm_from.data', '!=', '"sharedExpense"') | ||||
|                                   ->before($end)->after($start) | ||||
|                                   ->where('transaction_journals.user_id', \Auth::user()->id) | ||||
|                                   ->groupBy('account_id')->orderBy('sum', 'DESC')->limit(15) | ||||
|                                   ->groupBy('account_id')->orderBy('sum', 'DESC')->limit($limit) | ||||
|                                   ->get(['t_to.account_id as account_id', 'ac_to.name as name', \DB::Raw('SUM(t_to.amount) as `sum`')]); | ||||
|  | ||||
|  | ||||
| @@ -85,7 +94,7 @@ class Report implements ReportInterface | ||||
|     /** | ||||
|      * @param Carbon $date | ||||
|      * | ||||
|      * @return Collection | ||||
|      * @return array | ||||
|      */ | ||||
|     public function getAccountsForMonth(Carbon $date) | ||||
|     { | ||||
| @@ -93,31 +102,21 @@ class Report implements ReportInterface | ||||
|         $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; | ||||
|             } | ||||
|         ); | ||||
|         $list     = $this->_queries->accountList(); | ||||
|         $accounts = []; | ||||
|         /** @var \Account $account */ | ||||
|         foreach ($list as $account) { | ||||
|             $id            = intval($account->id); | ||||
|             $accounts[$id] = [ | ||||
|                 'name'         => $account->name, | ||||
|                 'startBalance' => \Steam::balance($account, $start), | ||||
|                 'endBalance'   => \Steam::balance($account, $end) | ||||
|             ]; | ||||
|  | ||||
|         return $list; | ||||
|             $accounts[$id]['difference'] = $accounts[$id]['endBalance'] - $accounts[$id]['startBalance']; | ||||
|         } | ||||
|  | ||||
|         return $accounts; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
| @@ -132,74 +131,29 @@ class Report implements ReportInterface | ||||
|         $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`')]); | ||||
|         $set                   = $this->_queries->getAllBudgets($date); | ||||
|         $budgets               = $this->_helper->makeArray($set); | ||||
|         $amountSet             = $this->_queries->journalsByBudget($start, $end); | ||||
|         $amounts               = $this->_helper->makeArray($amountSet); | ||||
|         $combined              = $this->_helper->mergeArrays($budgets, $amounts); | ||||
|         $combined[0]['spent']  = isset($combined[0]['spent']) ? $combined[0]['spent'] : 0.0; | ||||
|         $combined[0]['amount'] = isset($combined[0]['amount']) ? $combined[0]['amount'] : 0.0; | ||||
|         $combined[0]['name']   = 'No budget'; | ||||
|  | ||||
|  | ||||
|         $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; | ||||
|                 } | ||||
|             } | ||||
|         // find transactions to shared expense accounts, which are without a budget by default: | ||||
|         $transfers = $this->_queries->sharedExpenses($start, $end); | ||||
|         foreach ($transfers as $transfer) { | ||||
|             $combined[0]['spent'] += floatval($transfer->amount) * -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; | ||||
|         return $combined; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @param Carbon $date | ||||
|      * @param int    $limit | ||||
|      * | ||||
|      * @return Collection | ||||
|      * @return array | ||||
|      */ | ||||
|     public function getCategoriesForMonth(Carbon $date, $limit = 15) | ||||
|     { | ||||
| @@ -208,58 +162,21 @@ class Report implements ReportInterface | ||||
|         $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); | ||||
|         $result     = $this->_queries->journalsByCategory($start, $end); | ||||
|         $categories = $this->_helper->makeArray($result); | ||||
|  | ||||
|         $return       = new Collection; | ||||
|         $bottom       = new stdClass(); | ||||
|         $bottom->name = 'Others'; | ||||
|         $bottom->id   = 0; | ||||
|         $bottom->sum  = 0; | ||||
|         // all transfers | ||||
|         $result    = $this->_queries->sharedExpensesByCategory($start, $end); | ||||
|         $transfers = $this->_helper->makeArray($result); | ||||
|         $merged    = $this->_helper->mergeArrays($categories, $transfers); | ||||
|  | ||||
|         foreach ($amounts as $index => $entry) { | ||||
|             if ($index < $limit) { | ||||
|                 $return->push($entry); | ||||
|             } else { | ||||
|                 $bottom->sum += floatval($entry->sum); | ||||
|             } | ||||
|         } | ||||
|         $return->push($bottom); | ||||
|         // sort. | ||||
|         $sorted = $this->_helper->sortNegativeArray($merged); | ||||
|  | ||||
|         return $return; | ||||
|         // limit to $limit: | ||||
|         $cut = $this->_helper->limitArray($sorted, $limit); | ||||
|  | ||||
|         return $cut; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
| @@ -314,7 +231,7 @@ class Report implements ReportInterface | ||||
|                                                 \DB::Raw('SUM(`transactions`.`amount`) * -1 AS `sum`') | ||||
|                                             ] | ||||
|                                         ); | ||||
|         $transfers = $this->getTransfersToSharedAccounts($date); | ||||
|         $transfers = $this->getTransfersToSharedGroupedByAccounts($date); | ||||
|         // merge $transfers into $set | ||||
|         foreach ($transfers as $transfer) { | ||||
|             if (!is_null($transfer->account_id)) { | ||||
| @@ -409,7 +326,40 @@ class Report implements ReportInterface | ||||
|      * | ||||
|      * @return Collection | ||||
|      */ | ||||
|     public function getTransfersToSharedAccounts(Carbon $date) | ||||
|     public function getPiggyBanksForMonth(Carbon $date) | ||||
|     { | ||||
|         $start = clone $date; | ||||
|         $start->startOfMonth(); | ||||
|         $end = clone $date; | ||||
|         $end->endOfMonth(); | ||||
|  | ||||
|         $set = \PiggyBank:: | ||||
|         leftJoin('accounts', 'accounts.id', '=', 'piggy_banks.account_id') | ||||
|                          ->where('accounts.user_id', \Auth::user()->id) | ||||
|                          ->where('repeats', 0) | ||||
|                          ->where( | ||||
|                              function (Builder $query) use ($start, $end) { | ||||
|                                  $query->whereNull('piggy_banks.deleted_at'); | ||||
|                                  $query->orWhere( | ||||
|                                      function (Builder $query) use ($start, $end) { | ||||
|                                          $query->whereNotNull('piggy_banks.deleted_at'); | ||||
|                                          $query->where('piggy_banks.deleted_at', '>=', $start->format('Y-m-d 00:00:00')); | ||||
|                                          $query->where('piggy_banks.deleted_at', '<=', $end->format('Y-m-d 00:00:00')); | ||||
|                                      } | ||||
|                                  ); | ||||
|                              } | ||||
|                          ) | ||||
|                          ->get(['piggy_banks.*']); | ||||
|  | ||||
|  | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @param Carbon $date | ||||
|      * | ||||
|      * @return Collection | ||||
|      */ | ||||
|     public function getTransfersToSharedGroupedByAccounts(Carbon $date) | ||||
|     { | ||||
|         $start = clone $date; | ||||
|         $start->startOfMonth(); | ||||
| @@ -436,6 +386,7 @@ class Report implements ReportInterface | ||||
|                                   ->where('date', '<=', $end->format('Y-m-d')) | ||||
|                                   ->where('transaction_types.type', 'Transfer') | ||||
|                                   ->where('transaction_journals.user_id', \Auth::user()->id) | ||||
|                                   ->groupBy('accounts.name') | ||||
|                                   ->get( | ||||
|                                       [ | ||||
|                                           'transactions.account_id', | ||||
| @@ -445,6 +396,7 @@ class Report implements ReportInterface | ||||
|                                   ); | ||||
|     } | ||||
|  | ||||
|  | ||||
|     /** | ||||
|      * @param Carbon $start | ||||
|      * | ||||
|   | ||||
							
								
								
									
										119
									
								
								app/lib/FireflyIII/Report/ReportHelper.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										119
									
								
								app/lib/FireflyIII/Report/ReportHelper.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,119 @@ | ||||
| <?php | ||||
|  | ||||
| namespace FireflyIII\Report; | ||||
|  | ||||
| use Illuminate\Support\Collection; | ||||
|  | ||||
| /** | ||||
|  * Class ReportHelper | ||||
|  * | ||||
|  * @package FireflyIII\Report | ||||
|  */ | ||||
| class ReportHelper implements ReportHelperInterface | ||||
| { | ||||
|     /** | ||||
|      * Only return the top X entries, group the rest by amount | ||||
|      * and described as 'Others'. id = 0 as well | ||||
|      * | ||||
|      * @param array $array | ||||
|      * @param int   $limit | ||||
|      * | ||||
|      * @return array | ||||
|      */ | ||||
|     public function limitArray(array $array, $limit = 10) | ||||
|     { | ||||
|         $others = [ | ||||
|             'name'   => 'Others', | ||||
|             'amount' => 0 | ||||
|         ]; | ||||
|         $return = []; | ||||
|         $count  = 0; | ||||
|         foreach ($array as $id => $entry) { | ||||
|             if ($count < ($limit - 1)) { | ||||
|                 $return[$id] = $entry; | ||||
|             } else { | ||||
|                 $others['amount'] += $entry['amount']; | ||||
|             } | ||||
|  | ||||
|             $count++; | ||||
|         } | ||||
|         $return[0] = $others; | ||||
|  | ||||
|         return $return; | ||||
|  | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Turns a collection into an array. Needs the field 'id' for the key, | ||||
|      * and saves only 'name' and 'amount' as a subarray. | ||||
|      * | ||||
|      * @param Collection $collection | ||||
|      * | ||||
|      * @return array | ||||
|      */ | ||||
|     public function makeArray(Collection $collection) | ||||
|     { | ||||
|         $array = []; | ||||
|         foreach ($collection as $entry) { | ||||
|             $entry->spent = isset($entry->spent) ? floatval($entry->spent) : 0.0; | ||||
|             $id           = intval($entry->id); | ||||
|             if (isset($array[$id])) { | ||||
|                 $array[$id]['amount'] += floatval($entry->amount); | ||||
|                 $array[$id]['spent'] += floatval($entry->spent); | ||||
|             } else { | ||||
|                 $array[$id] = [ | ||||
|                     'amount' => floatval($entry->amount), | ||||
|                     'spent'  => floatval($entry->spent), | ||||
|                     'name'   => $entry->name | ||||
|                 ]; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         return $array; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Merges two of the arrays as defined above. Can't handle more (yet) | ||||
|      * | ||||
|      * @param array $one | ||||
|      * @param array $two | ||||
|      * | ||||
|      * @return array | ||||
|      */ | ||||
|     public function mergeArrays(array $one, array $two) | ||||
|     { | ||||
|         foreach ($two as $id => $value) { | ||||
|             // $otherId also exists in $one: | ||||
|             if (isset($one[$id])) { | ||||
|                 $one[$id]['amount'] += $value['amount']; | ||||
|                 $one[$id]['spent'] += $value['spent']; | ||||
|             } else { | ||||
|                 $one[$id] = $value; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         return $one; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Sort an array where all 'amount' keys are negative floats. | ||||
|      * | ||||
|      * @param array $array | ||||
|      * | ||||
|      * @return array | ||||
|      */ | ||||
|     public function sortNegativeArray(array $array) | ||||
|     { | ||||
|         uasort( | ||||
|             $array, function ($left, $right) { | ||||
|             if ($left['amount'] == $right['amount']) { | ||||
|                 return 0; | ||||
|             } | ||||
|  | ||||
|             return ($left['amount'] < $right['amount']) ? -1 : 1; | ||||
|         } | ||||
|         ); | ||||
|  | ||||
|         return $array; | ||||
|     } | ||||
| } | ||||
							
								
								
									
										55
									
								
								app/lib/FireflyIII/Report/ReportHelperInterface.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										55
									
								
								app/lib/FireflyIII/Report/ReportHelperInterface.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,55 @@ | ||||
| <?php | ||||
|  | ||||
| namespace FireflyIII\Report; | ||||
|  | ||||
| use Illuminate\Support\Collection; | ||||
|  | ||||
| /** | ||||
|  * Interface ReportHelperInterface | ||||
|  * | ||||
|  * @package FireflyIII\Report | ||||
|  */ | ||||
| interface ReportHelperInterface | ||||
| { | ||||
|  | ||||
|     /** | ||||
|      * Only return the top X entries, group the rest by amount | ||||
|      * and described as 'Others'. id = 0 as well | ||||
|      * | ||||
|      * @param array $array | ||||
|      * @param int   $limit | ||||
|      * | ||||
|      * @return array | ||||
|      */ | ||||
|     public function limitArray(array $array, $limit = 10); | ||||
|  | ||||
|     /** | ||||
|      * Turns a collection into an array. Needs the field 'id' for the key, | ||||
|      * and saves 'name', 'amount','spent' (if present) as a subarray. | ||||
|      * | ||||
|      * @param Collection $collection | ||||
|      * | ||||
|      * @return array | ||||
|      */ | ||||
|     public function makeArray(Collection $collection); | ||||
|  | ||||
|     /** | ||||
|      * Merges two of the arrays as defined above. Can't handle more (yet) | ||||
|      * | ||||
|      * @param array $one | ||||
|      * @param array $two | ||||
|      * | ||||
|      * @return array | ||||
|      */ | ||||
|     public function mergeArrays(array $one, array $two); | ||||
|  | ||||
|     /** | ||||
|      * Sort an array where all 'amount' keys are negative floats. | ||||
|      * | ||||
|      * @param array $array | ||||
|      * | ||||
|      * @return array | ||||
|      */ | ||||
|     public function sortNegativeArray(array $array); | ||||
|  | ||||
| } | ||||
| @@ -33,20 +33,27 @@ interface ReportInterface | ||||
|      * | ||||
|      * @return Collection | ||||
|      */ | ||||
|     public function getTransfersToSharedAccounts(Carbon $date); | ||||
|     public function getTransfersToSharedGroupedByAccounts(Carbon $date); | ||||
|  | ||||
|     /** | ||||
|      * @param Carbon $date | ||||
|      * | ||||
|      * @return Collection | ||||
|      */ | ||||
|     public function getPiggyBanksForMonth(Carbon $date); | ||||
|  | ||||
|     /** | ||||
|      * @param Carbon $date | ||||
|      * @param int $limit | ||||
|      * | ||||
|      * @return Collection | ||||
|      * @return array | ||||
|      */ | ||||
|     public function getCategoriesForMonth(Carbon $date, $limit = 15); | ||||
|  | ||||
|     /** | ||||
|      * @param Carbon $date | ||||
|      * | ||||
|      * @return Collection | ||||
|      * @return array | ||||
|      */ | ||||
|     public function getAccountsForMonth(Carbon $date); | ||||
|  | ||||
| @@ -58,6 +65,7 @@ interface ReportInterface | ||||
|      */ | ||||
|     public function getExpenseGroupedForMonth(Carbon $date,  $limit = 15); | ||||
|  | ||||
|  | ||||
|     /** | ||||
|      * @param Carbon $date | ||||
|      * @param bool   $shared | ||||
|   | ||||
							
								
								
									
										227
									
								
								app/lib/FireflyIII/Report/ReportQuery.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										227
									
								
								app/lib/FireflyIII/Report/ReportQuery.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,227 @@ | ||||
| <?php | ||||
|  | ||||
| namespace FireflyIII\Report; | ||||
|  | ||||
| use Carbon\Carbon; | ||||
| use Illuminate\Database\Query\JoinClause; | ||||
| use Illuminate\Support\Collection; | ||||
|  | ||||
| /** | ||||
|  * Class ReportQuery | ||||
|  * | ||||
|  * @package FireflyIII\Report | ||||
|  */ | ||||
| class ReportQuery implements ReportQueryInterface | ||||
| { | ||||
|     /** | ||||
|      * This query retrieves a list of accounts that are active and not shared. | ||||
|      * | ||||
|      * @return Collection | ||||
|      */ | ||||
|     public function accountList() | ||||
|     { | ||||
|         return \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.*']); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Gets a list of all budgets and if present, the amount of the current BudgetLimit | ||||
|      * as well | ||||
|      * | ||||
|      * @param Carbon $date | ||||
|      * | ||||
|      * @return Collection | ||||
|      */ | ||||
|     public function getAllBudgets(Carbon $date) | ||||
|     { | ||||
|         return \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 amount']); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Gets a list of expenses grouped by the budget they were filed under. | ||||
|      * | ||||
|      * @param Carbon $start | ||||
|      * @param Carbon $end | ||||
|      * | ||||
|      * @return Collection | ||||
|      */ | ||||
|     public function journalsByBudget(Carbon $start, Carbon $end) | ||||
|     { | ||||
|         return \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 `spent`')]); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Gets a list of categories and the expenses therein, grouped by the relevant category. | ||||
|      * This result excludes transfers to shared accounts which are expenses, technically. | ||||
|      * | ||||
|      * @param Carbon $start | ||||
|      * @param Carbon $end | ||||
|      * | ||||
|      * @return Collection | ||||
|      */ | ||||
|     public function journalsByCategory(Carbon $start, Carbon $end) | ||||
|     { | ||||
|         return \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('amount') | ||||
|                     ->get(['categories.id', 'categories.name', \DB::Raw('SUM(`transactions`.`amount`) AS `amount`')]); | ||||
|  | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Gets a list of expense accounts and the expenses therein, grouped by that expense account. | ||||
|      * This result excludes transfers to shared accounts which are expenses, technically. | ||||
|      * | ||||
|      * @param Carbon $start | ||||
|      * @param Carbon $end | ||||
|      * | ||||
|      * @return Collection | ||||
|      */ | ||||
|     public function journalsByExpenseAccount(Carbon $start, Carbon $end) | ||||
|     { | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * With an equally misleading name, this query returns are transfers to shared accounts. These are considered | ||||
|      * expenses. | ||||
|      * | ||||
|      * @param Carbon $start | ||||
|      * @param Carbon $end | ||||
|      * | ||||
|      * @return Collection | ||||
|      */ | ||||
|     public function sharedExpenses(Carbon $start, Carbon $end) | ||||
|     { | ||||
|         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"') | ||||
|                                   ->after($start) | ||||
|                                   ->before($end) | ||||
|                                   ->where('transaction_types.type', 'Transfer') | ||||
|                                   ->where('transaction_journals.user_id', \Auth::user()->id) | ||||
|                                   ->get( | ||||
|                                       ['transaction_journals.id', 'transaction_journals.description', 'transactions.account_id', 'accounts.name', | ||||
|                                        'transactions.amount'] | ||||
|                                   ); | ||||
|  | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * With a slightly misleading name, this query returns all transfers to shared accounts | ||||
|      * which are technically expenses, since it won't be just your money that gets spend. | ||||
|      * | ||||
|      * @param Carbon $start | ||||
|      * @param Carbon $end | ||||
|      * | ||||
|      * @return Collection | ||||
|      */ | ||||
|     public function sharedExpensesByCategory(Carbon $start, Carbon $end) | ||||
|     { | ||||
|         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'); | ||||
|                                   } | ||||
|                                   ) | ||||
|                                   ->leftJoin( | ||||
|                                       'category_transaction_journal', 'category_transaction_journal.transaction_journal_id', '=', 'transaction_journals.id' | ||||
|                                   ) | ||||
|                                   ->leftJoin('categories', 'category_transaction_journal.category_id', '=', 'categories.id') | ||||
|                                   ->where('account_meta.data', '"sharedExpense"') | ||||
|                                   ->after($start) | ||||
|                                   ->before($end) | ||||
|                                   ->where('transaction_types.type', 'Transfer') | ||||
|                                   ->where('transaction_journals.user_id', \Auth::user()->id) | ||||
|                                   ->groupBy('categories.name') | ||||
|                                   ->get( | ||||
|                                       [ | ||||
|                                           'categories.id', | ||||
|                                           'categories.name as name', | ||||
|                                           \DB::Raw('SUM(`transactions`.`amount`) * -1 AS `amount`') | ||||
|                                       ] | ||||
|                                   ); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										89
									
								
								app/lib/FireflyIII/Report/ReportQueryInterface.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										89
									
								
								app/lib/FireflyIII/Report/ReportQueryInterface.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,89 @@ | ||||
| <?php | ||||
|  | ||||
| namespace FireflyIII\Report; | ||||
|  | ||||
| use Carbon\Carbon; | ||||
| use Illuminate\Support\Collection; | ||||
|  | ||||
|  | ||||
| /** | ||||
|  * Interface ReportQueryInterface | ||||
|  * | ||||
|  * @package FireflyIII\Report | ||||
|  */ | ||||
| interface ReportQueryInterface | ||||
| { | ||||
|  | ||||
|     /** | ||||
|      * This query retrieves a list of accounts that are active and not shared. | ||||
|      * | ||||
|      * @return Collection | ||||
|      */ | ||||
|     public function accountList(); | ||||
|  | ||||
|     /** | ||||
|      * Gets a list of expenses grouped by the budget they were filed under. | ||||
|      * | ||||
|      * @param Carbon $start | ||||
|      * @param Carbon $end | ||||
|      * | ||||
|      * @return Collection | ||||
|      */ | ||||
|     public function journalsByBudget(Carbon $start, Carbon $end); | ||||
|  | ||||
|     /** | ||||
|      * Gets a list of all budgets and if present, the amount of the current BudgetLimit | ||||
|      * as well | ||||
|      * | ||||
|      * @param Carbon $date | ||||
|      * | ||||
|      * @return Collection | ||||
|      */ | ||||
|     public function getAllBudgets(Carbon $date); | ||||
|  | ||||
|     /** | ||||
|      * Gets a list of categories and the expenses therein, grouped by the relevant category. | ||||
|      * This result excludes transfers to shared accounts which are expenses, technically. | ||||
|      * | ||||
|      * @param Carbon $start | ||||
|      * @param Carbon $end | ||||
|      * | ||||
|      * @return Collection | ||||
|      */ | ||||
|     public function journalsByCategory(Carbon $start, Carbon $end); | ||||
|  | ||||
|     /** | ||||
|      * Gets a list of expense accounts and the expenses therein, grouped by that expense account. | ||||
|      * This result excludes transfers to shared accounts which are expenses, technically. | ||||
|      * | ||||
|      * @param Carbon $start | ||||
|      * @param Carbon $end | ||||
|      * | ||||
|      * @return Collection | ||||
|      */ | ||||
|     public function journalsByExpenseAccount(Carbon $start, Carbon $end); | ||||
|  | ||||
|  | ||||
|     /** | ||||
|      * With a slightly misleading name, this query returns all transfers to shared accounts | ||||
|      * grouped by category (which are technically expenses, since it won't be just your money that gets spend). | ||||
|      * | ||||
|      * @param Carbon $start | ||||
|      * @param Carbon $end | ||||
|      * | ||||
|      * @return Collection | ||||
|      */ | ||||
|     public function sharedExpensesByCategory(Carbon $start, Carbon $end); | ||||
|  | ||||
|     /** | ||||
|      * With an equally misleading name, this query returns are transfers to shared accounts. These are considered | ||||
|      * expenses. | ||||
|      * | ||||
|      * @param Carbon $start | ||||
|      * @param Carbon $end | ||||
|      * | ||||
|      * @return Collection | ||||
|      */ | ||||
|     public function sharedExpenses(Carbon $start, Carbon $end); | ||||
|  | ||||
| } | ||||
| @@ -2,13 +2,13 @@ | ||||
| @section('content') | ||||
| {{ Breadcrumbs::renderIfExists(Route::getCurrentRoute()->getName()) }} | ||||
| <div class="row"> | ||||
|     <div class="col-lg-6 col-md-6 col-sm-12"> | ||||
|     <div class="col-lg-5 col-md-5 col-sm-12"> | ||||
|         <div class="panel panel-default"> | ||||
|             <div class="panel-heading">Income</div> | ||||
|             @include('list.journals-small',['journals' => $income]) | ||||
|         </div> | ||||
|     </div> | ||||
|     <div class="col-lg-6 col-md-6 col-sm-12"> | ||||
|     <div class="col-lg-4 col-md-4 col-sm-12"> | ||||
|         <div class="panel panel-default"> | ||||
|             <div class="panel-heading">Expenses (top 10)</div> | ||||
|             <table class="table table-bordered"> | ||||
| @@ -31,6 +31,31 @@ | ||||
|             </table> | ||||
|         </div> | ||||
|     </div> | ||||
|     <div class="col-lg-3 col-md-4 col-sm-12"> | ||||
|         <div class="panel panel-default"> | ||||
|             <div class="panel-heading">Sums</div> | ||||
|             <?php | ||||
|                 $in = 0; | ||||
|                 foreach($income as $entry) { | ||||
|                     $in += floatval($entry->transactions[1]->amount); | ||||
|                 } | ||||
|             ?> | ||||
|             <table class="table table-bordered"> | ||||
|                 <tr> | ||||
|                     <td>In</td> | ||||
|                     <td>{{mf($in)}}</td> | ||||
|                 </tr> | ||||
|                 <tr> | ||||
|                     <td>Out</td> | ||||
|                     <td>{{mf($sum)}}</td> | ||||
|                 </tr> | ||||
|                 <tr> | ||||
|                     <td>Difference</td> | ||||
|                     <td>{{mf($sum + $in)}}</td> | ||||
|                 </tr> | ||||
|             </table> | ||||
|         </div> | ||||
|     </div> | ||||
| </div> | ||||
| <div class="row"> | ||||
|     <div class="col-lg-6 col-md-6 col-sm-12"> | ||||
| @@ -48,23 +73,23 @@ | ||||
|                         $sumEnvelope = 0; | ||||
|                         $sumLeft = 0; | ||||
|                     ?> | ||||
|                     @foreach($budgets as $budget) | ||||
|                     @foreach($budgets as $id => $budget) | ||||
|                         <?php | ||||
|                             $sumSpent += floatval($budget->spent); | ||||
|                             $sumEnvelope += floatval($budget->budget_amount); | ||||
|                             $sumLeft += floatval($budget->budget_amount) - floatval($budget->spent); | ||||
|                             $sumSpent += $budget['spent']; | ||||
|                             $sumEnvelope += $budget['amount']; | ||||
|                             $sumLeft += $budget['amount'] + $budget['spent']; | ||||
|                         ?> | ||||
|                     <tr> | ||||
|                         <td> | ||||
|                             @if($budget->id > 0) | ||||
|                                 <a href="{{route('budgets.show',$budget->id)}}">{{{$budget->name}}}</a> | ||||
|                             @if($id > 0) | ||||
|                                 <a href="{{route('budgets.show',$id)}}">{{{$budget['name']}}}</a> | ||||
|                             @else | ||||
|                                 <em>{{{$budget->name}}}</em> | ||||
|                                 <em>{{{$budget['name']}}}</em> | ||||
|                             @endif | ||||
|                         </td> | ||||
|                         <td>{{mf($budget->budget_amount)}}</td> | ||||
|                         <td>{{mf($budget->spent,false)}}</td> | ||||
|                         <td>{{mf(floatval($budget->budget_amount) - floatval($budget->spent))}}</td> | ||||
|                         <td>{{mf($budget['amount'])}}</td> | ||||
|                         <td>{{mf($budget['spent'],false)}}</td> | ||||
|                         <td>{{mf($budget['amount'] + $budget['spent'])}}</td> | ||||
|                     </tr> | ||||
|                     @endforeach | ||||
|                     <tr> | ||||
| @@ -74,9 +99,6 @@ | ||||
|                         <td>{{mf($sumLeft)}}</td> | ||||
|                     </tr> | ||||
|                 </table> | ||||
|             <div class="panel-body"> | ||||
|                 <em>This list does not take in account outgoing transfers to shared accounts.</em> | ||||
|             </div> | ||||
|         </div> | ||||
|     </div> | ||||
|     <div class="col-lg-6 col-md-6 col-sm-12"> | ||||
| @@ -88,17 +110,17 @@ | ||||
|                     <th>Spent</th> | ||||
|                 </tr> | ||||
|                 <?php $sum = 0;?> | ||||
|                 @foreach($categories as $category) | ||||
|                     <?php $sum += floatval($category->sum);?> | ||||
|                 @foreach($categories as $id => $category) | ||||
|                     <?php $sum += floatval($category['amount']);?> | ||||
|                     <tr> | ||||
|                         <td> | ||||
|                             @if($category->id > 0) | ||||
|                                 <a href="{{route('categories.show',$category->id)}}">{{{$category->name}}}</a> | ||||
|                             @if($id > 0) | ||||
|                                 <a href="{{route('categories.show',$id)}}">{{{$category['name']}}}</a> | ||||
|                             @else | ||||
|                                 <em>{{{$category->name}}}</em> | ||||
|                                 <em>{{{$category['name']}}}</em> | ||||
|                             @endif | ||||
|                         </td> | ||||
|                         <td>{{mf($category->sum,false)}}</td> | ||||
|                         <td>{{mf($category['amount'],false)}}</td> | ||||
|                     </tr> | ||||
|                 @endforeach | ||||
|                 <tr> | ||||
| @@ -106,9 +128,6 @@ | ||||
|                     <td>{{mf($sum)}}</td> | ||||
|                 </tr> | ||||
|             </table> | ||||
|             <div class="panel-body"> | ||||
|                 <em>This list does not take in account outgoing transfers to shared accounts.</em> | ||||
|             </div> | ||||
|         </div> | ||||
|     </div> | ||||
| </div> | ||||
| @@ -122,17 +141,17 @@ | ||||
|                     $sumEnd = 0; | ||||
|                     $sumDiff = 0; | ||||
|                 ?> | ||||
|             @foreach($accounts as $account) | ||||
|             @foreach($accounts as $id => $account) | ||||
|                 <?php | ||||
|                     $sumStart += $account->startBalance; | ||||
|                     $sumEnd += $account->endBalance; | ||||
|                     $sumDiff += $account->difference; | ||||
|                     $sumStart += $account['startBalance']; | ||||
|                     $sumEnd += $account['endBalance']; | ||||
|                     $sumDiff += $account['difference']; | ||||
|                 ?> | ||||
|                 <tr> | ||||
|                     <td><a href="#">{{{$account->name}}}</a></td> | ||||
|                     <td>{{mf($account->startBalance)}}</td> | ||||
|                     <td>{{mf($account->endBalance)}}</td> | ||||
|                     <td>{{mf($account->difference)}}</td> | ||||
|                     <td><a href="{{route('accounts.show',$id)}}">{{{$account['name']}}}</a></td> | ||||
|                     <td>{{mf($account['startBalance'])}}</td> | ||||
|                     <td>{{mf($account['endBalance'])}}</td> | ||||
|                     <td>{{mf($account['difference'])}}</td> | ||||
|                 </tr> | ||||
|             @endforeach | ||||
|                 <tr> | ||||
|   | ||||
		Reference in New Issue
	
	Block a user