Some query optimisations for the audit report

This commit is contained in:
James Cole
2016-04-08 15:10:07 +02:00
parent 33bf373151
commit d783d05462
2 changed files with 71 additions and 91 deletions

View File

@@ -7,7 +7,7 @@ use FireflyIII\Helpers\Report\BalanceReportHelperInterface;
use FireflyIII\Helpers\Report\BudgetReportHelperInterface; use FireflyIII\Helpers\Report\BudgetReportHelperInterface;
use FireflyIII\Helpers\Report\ReportHelperInterface; use FireflyIII\Helpers\Report\ReportHelperInterface;
use FireflyIII\Models\Account; use FireflyIII\Models\Account;
use FireflyIII\Models\Transaction; use FireflyIII\Models\TransactionJournal;
use FireflyIII\Repositories\Account\AccountRepositoryInterface as ARI; use FireflyIII\Repositories\Account\AccountRepositoryInterface as ARI;
use Illuminate\Support\Collection; use Illuminate\Support\Collection;
use Log; use Log;
@@ -102,22 +102,22 @@ class ReportController extends Controller
$start = session('first'); $start = session('first');
} }
View::share(
'subTitle', trans(
'firefly.report_' . $reportType,
[
'start' => $start->formatLocalized($this->monthFormat),
'end' => $end->formatLocalized($this->monthFormat),
]
)
);
View::share('subTitleIcon', 'fa-calendar');
switch ($reportType) { switch ($reportType) {
default: default:
throw new FireflyException('Unfortunately, reports of the type "' . e($reportType) . '" are not yet available. '); throw new FireflyException('Unfortunately, reports of the type "' . e($reportType) . '" are not yet available. ');
case 'default': case 'default':
View::share(
'subTitle', trans(
'firefly.report_default',
[
'start' => $start->formatLocalized($this->monthFormat),
'end' => $end->formatLocalized($this->monthFormat),
]
)
);
View::share('subTitleIcon', 'fa-calendar');
// more than one year date difference means year report. // more than one year date difference means year report.
if ($start->diffInMonths($end) > 12) { if ($start->diffInMonths($end) > 12) {
return $this->defaultMultiYear($reportType, $start, $end, $accounts); return $this->defaultMultiYear($reportType, $start, $end, $accounts);
@@ -127,9 +127,10 @@ class ReportController extends Controller
return $this->defaultYear($reportType, $start, $end, $accounts); return $this->defaultYear($reportType, $start, $end, $accounts);
} }
// otherwise default
return $this->defaultMonth($reportType, $start, $end, $accounts); return $this->defaultMonth($reportType, $start, $end, $accounts);
case 'audit': case 'audit':
// always default
return $this->auditReport($start, $end, $accounts); return $this->auditReport($start, $end, $accounts);
} }
@@ -145,26 +146,14 @@ class ReportController extends Controller
*/ */
private function auditReport(Carbon $start, Carbon $end, Collection $accounts) private function auditReport(Carbon $start, Carbon $end, Collection $accounts)
{ {
bcscale(2);
/** @var ARI $repos */ /** @var ARI $repos */
$repos = app('FireflyIII\Repositories\Account\AccountRepositoryInterface');
$repos = app('FireflyIII\Repositories\Account\AccountRepositoryInterface');
View::share(
'subTitle', trans(
'firefly.report_audit',
[
'start' => $start->formatLocalized($this->monthFormat),
'end' => $end->formatLocalized($this->monthFormat),
]
)
);
View::share('subTitleIcon', 'fa-calendar');
$auditData = []; $auditData = [];
$dayBefore = clone $start; $dayBefore = clone $start;
$dayBefore->subDay(); $dayBefore->subDay();
/** @var Account $account */ /** @var Account $account */
foreach ($accounts as $account) { foreach ($accounts as $account) {
// balance the day before: // balance the day before:
$id = $account->id; $id = $account->id;
$first = $repos->oldestJournalDate($account); $first = $repos->oldestJournalDate($account);
@@ -173,34 +162,38 @@ class ReportController extends Controller
$journals = new Collection; $journals = new Collection;
$dayBeforeBalance = Steam::balance($account, $dayBefore); $dayBeforeBalance = Steam::balance($account, $dayBefore);
/*
* Is there even activity on this account between the requested dates?
*/
if ($start->between($first, $last) || $end->between($first, $last)) { if ($start->between($first, $last) || $end->between($first, $last)) {
$exists = true; $exists = true;
$journals = $repos->getJournalsInRange($account, $start, $end); $journals = $repos->getJournalsInRange($account, $start, $end);
$journals = $journals->reverse();
} }
/*
* Reverse set, get balances.
*/
$journals = $journals->reverse();
$startBalance = $dayBeforeBalance; $startBalance = $dayBeforeBalance;
/** @var TransactionJournal $journal */
foreach ($journals as $journal) { foreach ($journals as $journal) {
$journal->before = $startBalance; $journal->before = $startBalance;
$transactionAmount = $journal->source_amount;
// get currently relevant transaction: // get currently relevant transaction:
$transaction = $journal->transactions->filter( if (intval($journal->destination_account_id) === $account->id) {
function (Transaction $t) use ($account) { $transactionAmount = $journal->destination_amount;
return $t->account_id === $account->id; }
} $newBalance = bcadd($startBalance, $transactionAmount);
)->first();
$newBalance = bcadd($startBalance, $transaction->amount);
$journal->after = $newBalance; $journal->after = $newBalance;
$startBalance = $newBalance; $startBalance = $newBalance;
} }
$journals = $journals->reverse(); /*
* Reverse set again.
*/
$auditData[$id]['journals'] = $journals; $auditData[$id]['journals'] = $journals->reverse();
$auditData[$id]['exists'] = $exists; $auditData[$id]['exists'] = $exists;
$auditData[$id]['end'] = $end->formatLocalized(trans('config.month_and_day')); $auditData[$id]['end'] = $end->formatLocalized(trans('config.month_and_day'));
$auditData[$id]['endBalance'] = Steam::balance($account, $end); $auditData[$id]['endBalance'] = Steam::balance($account, $end);

View File

@@ -14,6 +14,7 @@ use FireflyIII\Models\Transaction;
use FireflyIII\Models\TransactionJournal; use FireflyIII\Models\TransactionJournal;
use FireflyIII\Models\TransactionType; use FireflyIII\Models\TransactionType;
use FireflyIII\User; use FireflyIII\User;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Relations\HasMany; use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Pagination\LengthAwarePaginator; use Illuminate\Pagination\LengthAwarePaginator;
use Illuminate\Support\Collection; use Illuminate\Support\Collection;
@@ -253,6 +254,31 @@ class AccountRepository implements AccountRepositoryInterface
return $set; return $set;
} }
/**
* Returns a list of transactions TO the given (asset) $account, but none from the
* given list of accounts
*
* @param Account $account
* @param Collection $accounts
* @param Carbon $start
* @param Carbon $end
*
* @return Collection
*/
public function getIncomeByDestination(Account $account, Collection $accounts, Carbon $start, Carbon $end): Collection
{
$ids = $accounts->pluck('id')->toArray();
$journals = $this->user->transactionjournals()
->expanded()
->before($end)
->where('source_account.id', $account->id)
->whereIn('destination_account.id', $ids)
->after($start)
->get(TransactionJournal::QUERYFIELDS);
return $journals;
}
/** /**
* @param Account $account * @param Account $account
* @param int $page * @param int $page
@@ -290,27 +316,16 @@ class AccountRepository implements AccountRepositoryInterface
public function getJournalsInRange(Account $account, Carbon $start, Carbon $end): Collection public function getJournalsInRange(Account $account, Carbon $start, Carbon $end): Collection
{ {
$query = $this->user $query = $this->user
->transactionJournals() ->transactionJournals()
->expanded() ->expanded()
->with( ->where(
[ function (Builder $q) use ($account) {
'transactions' => function (HasMany $q) { $q->where('destination_account.id', $account->id);
$q->orderBy('amount', 'ASC'); $q->orWhere('source_account.id', $account->id);
}, }
'transactionType', )
'transactionCurrency', ->after($start)
'budgets', ->before($end);
'categories',
'bill',
]
)
->leftJoin('transactions', 'transactions.transaction_journal_id', '=', 'transaction_journals.id')
->where('transactions.account_id', $account->id)
->after($start)
->before($end)
->orderBy('transaction_journals.date', 'DESC')
->orderBy('transaction_journals.order', 'ASC')
->orderBy('transaction_journals.id', 'DESC');
$set = $query->get(TransactionJournal::QUERYFIELDS); $set = $query->get(TransactionJournal::QUERYFIELDS);
@@ -334,7 +349,6 @@ class AccountRepository implements AccountRepositoryInterface
if (count($ids) > 0) { if (count($ids) > 0) {
$accounts = $this->user->accounts()->whereIn('id', $ids)->where('accounts.active', 1)->get(); $accounts = $this->user->accounts()->whereIn('id', $ids)->where('accounts.active', 1)->get();
} }
bcscale(2);
$accounts->each( $accounts->each(
function (Account $account) use ($start, $end) { function (Account $account) use ($start, $end) {
@@ -375,8 +389,6 @@ class AccountRepository implements AccountRepositoryInterface
$start = clone Session::get('start', new Carbon); $start = clone Session::get('start', new Carbon);
$end = clone Session::get('end', new Carbon); $end = clone Session::get('end', new Carbon);
bcscale(2);
$accounts->each( $accounts->each(
function (Account $account) use ($start, $end) { function (Account $account) use ($start, $end) {
$account->startBalance = Steam::balance($account, $start); $account->startBalance = Steam::balance($account, $start);
@@ -761,29 +773,4 @@ class AccountRepository implements AccountRepositoryInterface
} }
} }
/**
* Returns a list of transactions TO the given (asset) $account, but none from the
* given list of accounts
*
* @param Account $account
* @param Collection $accounts
* @param Carbon $start
* @param Carbon $end
*
* @return Collection
*/
public function getIncomeByDestination(Account $account, Collection $accounts, Carbon $start, Carbon $end): Collection
{
$ids = $accounts->pluck('id')->toArray();
$journals = $this->user->transactionjournals()
->expanded()
->before($end)
->where('source_account.id', $account->id)
->whereIn('destination_account.id', $ids)
->after($start)
->get(TransactionJournal::QUERYFIELDS);
return $journals;
}
} }