diff --git a/app/Helpers/Collection/Expense.php b/app/Helpers/Collection/Expense.php index a703ee7a15..ce489c5118 100644 --- a/app/Helpers/Collection/Expense.php +++ b/app/Helpers/Collection/Expense.php @@ -2,6 +2,7 @@ namespace FireflyIII\Helpers\Collection; +use Crypt; use FireflyIII\Models\TransactionJournal; use Illuminate\Support\Collection; use stdClass; @@ -36,7 +37,7 @@ class Expense bcscale(2); $accountId = $entry->account_id; - $amount = strval(round($entry->amount, 2)); + $amount = strval(round($entry->journalAmount, 2)); if (bccomp('0', $amount) === -1) { $amount = bcmul($amount, '-1'); } @@ -44,7 +45,7 @@ class Expense if (!$this->expenses->has($accountId)) { $newObject = new stdClass; $newObject->amount = $amount; - $newObject->name = $entry->name; + $newObject->name = Crypt::decrypt($entry->account_name); $newObject->count = 1; $newObject->id = $accountId; $this->expenses->put($accountId, $newObject); diff --git a/app/Helpers/Collection/Income.php b/app/Helpers/Collection/Income.php index 9d1389dfcb..6a66de8fef 100644 --- a/app/Helpers/Collection/Income.php +++ b/app/Helpers/Collection/Income.php @@ -2,6 +2,7 @@ namespace FireflyIII\Helpers\Collection; +use Crypt; use FireflyIII\Models\TransactionJournal; use Illuminate\Support\Collection; use stdClass; @@ -38,15 +39,15 @@ class Income $accountId = $entry->account_id; if (!$this->incomes->has($accountId)) { $newObject = new stdClass; - $newObject->amount = strval(round($entry->amount_positive, 2)); - $newObject->name = $entry->name; + $newObject->amount = strval(round($entry->journalAmount, 2)); + $newObject->name = Crypt::decrypt($entry->account_name); $newObject->count = 1; $newObject->id = $accountId; $this->incomes->put($accountId, $newObject); } else { bcscale(2); $existing = $this->incomes->get($accountId); - $existing->amount = bcadd($existing->amount, $entry->amount_positive); + $existing->amount = bcadd($existing->amount, $entry->journalAmount); $existing->count++; $this->incomes->put($accountId, $existing); } diff --git a/app/Helpers/Report/ReportHelper.php b/app/Helpers/Report/ReportHelper.php index 7dc00d2fd3..00f58a310a 100644 --- a/app/Helpers/Report/ReportHelper.php +++ b/app/Helpers/Report/ReportHelper.php @@ -2,7 +2,9 @@ namespace FireflyIII\Helpers\Report; +use Auth; use Carbon\Carbon; +use DB; use FireflyIII\Helpers\Collection\Account as AccountCollection; use FireflyIII\Helpers\Collection\Balance; use FireflyIII\Helpers\Collection\BalanceEntry; @@ -19,8 +21,9 @@ use FireflyIII\Models\Account; use FireflyIII\Models\Bill; use FireflyIII\Models\Budget as BudgetModel; use FireflyIII\Models\LimitRepetition; +use FireflyIII\Models\TransactionType; +use Illuminate\Database\Query\JoinClause; use Illuminate\Support\Collection; -use Steam; /** * Class ReportHelper @@ -127,21 +130,59 @@ class ReportHelper implements ReportHelperInterface $startAmount = '0'; $endAmount = '0'; $diff = '0'; + $ids = $accounts->pluck('id')->toArray(); + + $yesterday = clone $start; + $yesterday->subDay(); + bcscale(2); + // get balances for start. + $startSet = Account::leftJoin('transactions', 'transactions.account_id', '=', 'accounts.id') + ->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id') + ->whereIn('accounts.id', $ids) + ->whereNull('transaction_journals.deleted_at') + ->whereNull('transactions.deleted_at') + ->where('transaction_journals.date', '<=', $yesterday->format('Y-m-d')) + ->groupBy('accounts.id') + ->get(['accounts.id', DB::Raw('SUM(`transactions`.`amount`) as `balance`')]); + + // and for end: + $endSet = Account::leftJoin('transactions', 'transactions.account_id', '=', 'accounts.id') + ->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id') + ->whereIn('accounts.id', $ids) + ->whereNull('transaction_journals.deleted_at') + ->whereNull('transactions.deleted_at') + ->where('transaction_journals.date', '<=', $end->format('Y-m-d')) + ->groupBy('accounts.id') + ->get(['accounts.id', DB::Raw('SUM(`transactions`.`amount`) as `balance`')]); + + $accounts->each( - function (Account $account) use ($start, $end) { + function (Account $account) use ($startSet, $endSet) { /** * The balance for today always incorporates transactions * made on today. So to get todays "start" balance, we sub one * day. */ - $yesterday = clone $start; - $yesterday->subDay(); + // + $currentStart = $startSet->filter( + function (Account $entry) use ($account) { + return $account->id == $entry->id; + } + ); + if ($currentStart->first()) { + $account->startBalance = $currentStart->first()->balance; + } - /** @noinspection PhpParamsInspection */ - $account->startBalance = Steam::balance($account, $yesterday); - $account->endBalance = Steam::balance($account, $end); + $currentEnd = $endSet->filter( + function (Account $entry) use ($account) { + return $account->id == $entry->id; + } + ); + if ($currentEnd->first()) { + $account->endBalance = $currentEnd->first()->balance; + } } ); @@ -174,9 +215,32 @@ class ReportHelper implements ReportHelperInterface public function getIncomeReport($start, $end, Collection $accounts) { $object = new Income; - $set = $this->query->incomeInPeriod($start, $end, $accounts); + + /* + * TODO move to ReportQuery class. + */ + $ids = $accounts->pluck('id')->toArray(); + $set = Auth::user()->transactionjournals() + ->leftJoin( + 'transactions as t_from', function (JoinClause $join) { + $join->on('t_from.transaction_journal_id', '=', 'transaction_journals.id')->where('t_from.amount', '<', 0); + } + ) + ->leftJoin( + 'transactions as t_to', function (JoinClause $join) { + $join->on('t_to.transaction_journal_id', '=', 'transaction_journals.id')->where('t_to.amount', '>', 0); + } + ) + ->leftJoin('accounts', 't_from.account_id', '=', 'accounts.id') + ->transactionTypes([TransactionType::DEPOSIT, TransactionType::TRANSFER, TransactionType::OPENING_BALANCE]) + ->before($end) + ->after($start) + ->whereIn('t_to.account_id', $ids) + ->whereNotIn('t_from.account_id', $ids) + ->get(['transaction_journals.*', 't_to.amount as journalAmount', 'accounts.id as account_id', 'accounts.name as account_name']); + foreach ($set as $entry) { - $object->addToTotal($entry->amount_positive); + $object->addToTotal($entry->journalAmount); $object->addOrCreateIncome($entry); } @@ -195,9 +259,33 @@ class ReportHelper implements ReportHelperInterface public function getExpenseReport($start, $end, Collection $accounts) { $object = new Expense; - $set = $this->query->expenseInPeriod($start, $end, $accounts); + + + /* + * TODO move to ReportQuery class. + */ + $ids = $accounts->pluck('id')->toArray(); + $set = Auth::user()->transactionjournals() + ->leftJoin( + 'transactions as t_from', function (JoinClause $join) { + $join->on('t_from.transaction_journal_id', '=', 'transaction_journals.id')->where('t_from.amount', '<', 0); + } + ) + ->leftJoin( + 'transactions as t_to', function (JoinClause $join) { + $join->on('t_to.transaction_journal_id', '=', 'transaction_journals.id')->where('t_to.amount', '>', 0); + } + ) + ->leftJoin('accounts', 't_to.account_id', '=', 'accounts.id') + ->transactionTypes([TransactionType::WITHDRAWAL, TransactionType::TRANSFER, TransactionType::OPENING_BALANCE]) + ->before($end) + ->after($start) + ->whereIn('t_from.account_id', $ids) + ->whereNotIn('t_to.account_id', $ids) + ->get(['transaction_journals.*', 't_from.amount as journalAmount', 'accounts.id as account_id', 'accounts.name as account_name']); + foreach ($set as $entry) { - $object->addToTotal($entry->amount); // can be positive, if it's a transfer + $object->addToTotal($entry->journalAmount); // can be positive, if it's a transfer $object->addOrCreateExpense($entry); } diff --git a/app/Helpers/Report/ReportQuery.php b/app/Helpers/Report/ReportQuery.php index 8015b2e150..de29c6ed29 100644 --- a/app/Helpers/Report/ReportQuery.php +++ b/app/Helpers/Report/ReportQuery.php @@ -103,69 +103,69 @@ class ReportQuery implements ReportQueryInterface } - /** - * 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 - * regards to tags. It will only get the incomes to the specified accounts. - * - * @param Carbon $start - * @param Carbon $end - * @param Collection $accounts - * - * @return Collection - */ - public function incomeInPeriod(Carbon $start, Carbon $end, Collection $accounts) - { - $query = $this->queryJournalsWithTransactions($start, $end); - - $ids = []; - /** @var Account $account */ - foreach ($accounts as $account) { - $ids[] = $account->id; - } - - // OR is a deposit - // OR any transfer TO the accounts in $accounts, not FROM any of the accounts in $accounts. - $query->where( - function (Builder $query) use ($ids) { - $query->where( - function (Builder $q) { - $q->where('transaction_types.type', TransactionType::DEPOSIT); - } - ); - $query->orWhere( - function (Builder $q) use ($ids) { - $q->where('transaction_types.type', TransactionType::TRANSFER); - $q->whereNotIn('ac_from.id', $ids); - $q->whereIn('ac_to.id', $ids); - } - ); - } - ); - - // only include selected accounts. - $query->whereIn('ac_to.id', $ids); - $query->orderBy('transaction_journals.date'); - - // get everything - $data = $query->get( - ['transaction_journals.*', - 'transaction_types.type', 'ac_from.name as name', - 't_from.amount as from_amount', - 't_to.amount as to_amount', - 'ac_from.id as account_id', 'ac_from.encrypted as account_encrypted'] - ); - - $data->each( - function (TransactionJournal $journal) { - if (intval($journal->account_encrypted) == 1) { - $journal->name = Crypt::decrypt($journal->name); - } - } - ); - - return $data; - } +// /** +// * 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 +// * regards to tags. It will only get the incomes to the specified accounts. +// * +// * @param Carbon $start +// * @param Carbon $end +// * @param Collection $accounts +// * +// * @return Collection +// */ +// public function incomeInPeriod(Carbon $start, Carbon $end, Collection $accounts) +// { +// $query = $this->queryJournalsWithTransactions($start, $end); +// +// $ids = []; +// /** @var Account $account */ +// foreach ($accounts as $account) { +// $ids[] = $account->id; +// } +// +// // OR is a deposit +// // OR any transfer TO the accounts in $accounts, not FROM any of the accounts in $accounts. +// $query->where( +// function (Builder $query) use ($ids) { +// $query->where( +// function (Builder $q) { +// $q->where('transaction_types.type', TransactionType::DEPOSIT); +// } +// ); +// $query->orWhere( +// function (Builder $q) use ($ids) { +// $q->where('transaction_types.type', TransactionType::TRANSFER); +// $q->whereNotIn('ac_from.id', $ids); +// $q->whereIn('ac_to.id', $ids); +// } +// ); +// } +// ); +// +// // only include selected accounts. +// $query->whereIn('ac_to.id', $ids); +// $query->orderBy('transaction_journals.date'); +// +// // get everything +// $data = $query->get( +// ['transaction_journals.*', +// 'transaction_types.type', 'ac_from.name as name', +// 't_from.amount as from_amount', +// 't_to.amount as to_amount', +// 'ac_from.id as account_id', 'ac_from.encrypted as account_encrypted'] +// ); +// +// $data->each( +// function (TransactionJournal $journal) { +// if (intval($journal->account_encrypted) == 1) { +// $journal->name = Crypt::decrypt($journal->name); +// } +// } +// ); +// +// return $data; +// } /** * See ReportQueryInterface::incomeInPeriod diff --git a/app/Helpers/Report/ReportQueryInterface.php b/app/Helpers/Report/ReportQueryInterface.php index ed9892534f..90eb200b6e 100644 --- a/app/Helpers/Report/ReportQueryInterface.php +++ b/app/Helpers/Report/ReportQueryInterface.php @@ -31,18 +31,18 @@ interface ReportQueryInterface */ public function expenseInPeriod(Carbon $start, Carbon $end, Collection $accounts); - /** - * 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 - * regards to tags. It will only get the incomes to the specified accounts. - * - * @param Carbon $start - * @param Carbon $end - * @param Collection $accounts - * - * @return Collection - */ - public function incomeInPeriod(Carbon $start, Carbon $end, Collection $accounts); +// /** +// * 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 +// * regards to tags. It will only get the incomes to the specified accounts. +// * +// * @param Carbon $start +// * @param Carbon $end +// * @param Collection $accounts +// * +// * @return Collection +// */ +// public function incomeInPeriod(Carbon $start, Carbon $end, Collection $accounts); /** * Covers tags as well. diff --git a/app/Http/Controllers/ReportController.php b/app/Http/Controllers/ReportController.php index 28ed6f1322..d43661064d 100644 --- a/app/Http/Controllers/ReportController.php +++ b/app/Http/Controllers/ReportController.php @@ -125,9 +125,9 @@ class ReportController extends Controller $expenseTopLength = 8; // get report stuff! - $accountReport = $this->helper->getAccountReport($start, $end, $accounts); - $incomes = $this->helper->getIncomeReport($start, $end, $accounts); - $expenses = $this->helper->getExpenseReport($start, $end, $accounts); + $accountReport = $this->helper->getAccountReport($start, $end, $accounts); // done + $incomes = $this->helper->getIncomeReport($start, $end, $accounts); // done + $expenses = $this->helper->getExpenseReport($start, $end, $accounts); // done $budgets = $this->helper->getBudgetReport($start, $end, $accounts); $categories = $this->helper->getCategoryReport($start, $end, $accounts); $balance = $this->helper->getBalanceReport($start, $end, $accounts);