From aac5c2b13ca7d5ddb16d49577998974b49c83820 Mon Sep 17 00:00:00 2001 From: James Cole Date: Thu, 31 Dec 2015 08:26:04 +0100 Subject: [PATCH] Optimised another chart. --- app/Helpers/Report/ReportQuery.php | 93 +++++++++++++++++++ app/Helpers/Report/ReportQueryInterface.php | 24 +++++ .../Controllers/Chart/ReportController.php | 47 ++++++---- 3 files changed, 148 insertions(+), 16 deletions(-) diff --git a/app/Helpers/Report/ReportQuery.php b/app/Helpers/Report/ReportQuery.php index ae484d8095..f6a7119217 100644 --- a/app/Helpers/Report/ReportQuery.php +++ b/app/Helpers/Report/ReportQuery.php @@ -5,6 +5,7 @@ namespace FireflyIII\Helpers\Report; use Auth; use Carbon\Carbon; use Crypt; +use DB; use FireflyIII\Models\Account; use FireflyIII\Models\Budget; use FireflyIII\Models\TransactionJournal; @@ -101,6 +102,7 @@ class ReportQuery implements ReportQueryInterface return $query; } + /** * This method works the same way as ReportQueryInterface::incomeInPeriod does, but instead of returning results * will simply list the transaction journals only. This should allow any follow up counting to be accurate with @@ -231,4 +233,95 @@ class ReportQuery implements ReportQueryInterface return $data; } + + + /** + * Returns an array of the amount of money spent in the given accounts (on withdrawals, opening balances and transfers) + * grouped by month like so: "2015-01" => '123.45' + * + * @param Collection $accounts + * @param Carbon $start + * @param Carbon $end + * + * @return array + */ + public function spentPerMonth(Collection $accounts, Carbon $start, Carbon $end) + { + $ids = $accounts->pluck('id')->toArray(); + $query = Auth::user()->transactionjournals() + ->leftJoin( + 'transactions AS t_from', function (JoinClause $join) { + $join->on('transaction_journals.id', '=', 't_from.transaction_journal_id')->where('t_from.amount', '<', 0); + } + ) + ->leftJoin( + 'transactions AS t_to', function (JoinClause $join) { + $join->on('transaction_journals.id', '=', 't_to.transaction_journal_id')->where('t_to.amount', '>', 0); + } + ) + ->whereIn('t_from.account_id', $ids) + ->whereNotIn('t_to.account_id', $ids) + ->after($start) + ->before($end) + ->transactionTypes([TransactionType::WITHDRAWAL, TransactionType::TRANSFER, TransactionType::OPENING_BALANCE]) + ->groupBy('dateFormatted') + ->get( + [ + DB::Raw('DATE_FORMAT(`transaction_journals`.`date`,"%Y-%m") AS `dateFormatted`'), + DB::Raw('SUM(`t_from`.`amount`) AS `sum`') + ] + ); + $array = []; + foreach ($query as $result) { + $array[$result->dateFormatted] = $result->sum; + } + + return $array; + + } + + /** + * Returns an array of the amount of money spent in the given accounts (on withdrawals, opening balances and transfers) + * grouped by month like so: "2015-01" => '123.45' + * + * @param Collection $accounts + * @param Carbon $start + * @param Carbon $end + * + * @return array + */ + public function earnedPerMonth(Collection $accounts, Carbon $start, Carbon $end) + { + $ids = $accounts->pluck('id')->toArray(); + $query = Auth::user()->transactionjournals() + ->leftJoin( + 'transactions AS t_from', function (JoinClause $join) { + $join->on('transaction_journals.id', '=', 't_from.transaction_journal_id')->where('t_from.amount', '<', 0); + } + ) + ->leftJoin( + 'transactions AS t_to', function (JoinClause $join) { + $join->on('transaction_journals.id', '=', 't_to.transaction_journal_id')->where('t_to.amount', '>', 0); + } + ) + ->whereIn('t_to.account_id', $ids) + ->whereNotIn('t_from.account_id', $ids) + ->after($start) + ->before($end) + ->transactionTypes([TransactionType::DEPOSIT, TransactionType::TRANSFER, TransactionType::OPENING_BALANCE]) + ->groupBy('dateFormatted') + ->get( + [ + DB::Raw('DATE_FORMAT(`transaction_journals`.`date`,"%Y-%m") AS `dateFormatted`'), + DB::Raw('SUM(`t_from`.`amount`) AS `sum`') + ] + ); + $array = []; + foreach ($query as $result) { + $array[$result->dateFormatted] = $result->sum; + } + + return $array; + } + } diff --git a/app/Helpers/Report/ReportQueryInterface.php b/app/Helpers/Report/ReportQueryInterface.php index d7fa9cf085..ed9892534f 100644 --- a/app/Helpers/Report/ReportQueryInterface.php +++ b/app/Helpers/Report/ReportQueryInterface.php @@ -65,5 +65,29 @@ interface ReportQueryInterface */ public function spentNoBudget(Account $account, Carbon $start, Carbon $end); + /** + * Returns an array of the amount of money spent in the given accounts (on withdrawals, opening balances and transfers) + * grouped by month like so: "2015-01" => '123.45' + * + * @param Collection $accounts + * @param Carbon $start + * @param Carbon $end + * + * @return array + */ + public function spentPerMonth(Collection $accounts, Carbon $start, Carbon $end); + + /** + * Returns an array of the amount of money spent in the given accounts (on withdrawals, opening balances and transfers) + * grouped by month like so: "2015-01" => '123.45' + * + * @param Collection $accounts + * @param Carbon $start + * @param Carbon $end + * + * @return array + */ + public function earnedPerMonth(Collection $accounts, Carbon $start, Carbon $end); + } diff --git a/app/Http/Controllers/Chart/ReportController.php b/app/Http/Controllers/Chart/ReportController.php index f289262064..08492fd4e1 100644 --- a/app/Http/Controllers/Chart/ReportController.php +++ b/app/Http/Controllers/Chart/ReportController.php @@ -55,20 +55,18 @@ class ReportController extends Controller return Response::json($cache->get()); // @codeCoverageIgnore } + // spent per month, and earned per month. For a specific set of accounts + // grouped by month + $spentArray = $query->spentPerMonth($accounts, $start, $end); + $earnedArray = $query->earnedPerMonth($accounts, $start, $end); - // per year? + // per year? put all months together. if ($start->diffInMonths($end) > 12) { - $entries = new Collection; while ($start < $end) { - $startOfYear = clone $start; - $startOfYear->startOfYear(); - $endOfYear = clone $startOfYear; - $endOfYear->endOfYear(); - // total income and total expenses: - $incomeSum = $query->incomeInPeriod($startOfYear, $endOfYear, $accounts)->sum('amount_positive'); - $expenseSum = $query->expenseInPeriod($startOfYear, $endOfYear, $accounts)->sum('amount_positive'); + $incomeSum = $this->pluckFromArray($start->year, $earnedArray); + $expenseSum = $this->pluckFromArray($start->year, $spentArray); $entries->push([clone $start, $incomeSum, $expenseSum]); $start->addYear(); @@ -77,16 +75,14 @@ class ReportController extends Controller $data = $this->generator->multiYearInOut($entries); $cache->store($data); } else { - // per month: + // per month? simply use each month. $entries = new Collection; while ($start < $end) { - $month = clone $start; - $month->endOfMonth(); // total income and total expenses: - $incomeSum = $query->incomeInPeriod($start, $month, $accounts)->sum('amount_positive'); - $expenseSum = $query->expenseInPeriod($start, $month, $accounts)->sum('amount_positive'); - + $date = $start->format('Y-m'); + $incomeSum = isset($earnedArray[$date]) ? $earnedArray[$date] : 0; + $expenseSum = isset($spentArray[$date]) ? $spentArray[$date] : 0; $entries->push([clone $start, $incomeSum, $expenseSum]); $start->addMonth(); @@ -96,7 +92,6 @@ class ReportController extends Controller $cache->store($data); } - return Response::json($data); } @@ -174,4 +169,24 @@ class ReportController extends Controller return Response::json($data); } + + /** + * @param int $year + * @param array $set + * + * @return string + */ + protected function pluckFromArray($year, array $set) + { + bcscale(2); + $sum = '0'; + foreach ($set as $date => $amount) { + if (substr($date, 0, 4) == $year) { + $sum = bcadd($sum, $amount); + } + } + + return $sum; + + } }