Journal collector may not have been a bad idea after all!

This commit is contained in:
James Cole 2016-11-05 08:27:25 +01:00
parent 47bebb614e
commit 9c5d192d90
No known key found for this signature in database
GPG Key ID: C16961E655E74B5E
5 changed files with 405 additions and 16 deletions

View File

@ -0,0 +1,360 @@
<?php
declare(strict_types = 1);
namespace FireflyIII\Helpers\Collector;
use Carbon\Carbon;
use Crypt;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Models\Transaction;
use FireflyIII\User;
use Illuminate\Database\Eloquent\Builder as EloquentBuilder;
use Illuminate\Pagination\LengthAwarePaginator;
use Illuminate\Support\Collection;
use Log;
/**
* Maybe this is a good idea after all...
*
* Class JournalCollector
*
* @package FireflyIII\Helpers\Collector
*/
class JournalCollector
{
/** @var int */
private $count = 0;
/** @var array */
private $fields
= [
'transaction_journals.id as journal_id',
'transaction_journals.description',
'transaction_journals.date',
'transaction_journals.encrypted',
//'transaction_journals.transaction_currency_id',
'transaction_currencies.code as transaction_currency_code',
//'transaction_currencies.symbol as transaction_currency_symbol',
'transaction_types.type as transaction_type_type',
'transaction_journals.bill_id',
'bills.name as bill_name',
'transactions.id as id',
'transactions.amount as transaction_amount',
'transactions.description as transaction_description',
'transactions.account_id',
'transactions.identifier',
'transactions.transaction_journal_id',
'accounts.name as account_name',
'accounts.encrypted as account_encrypted',
'account_types.type as account_type',
];
/** @var int */
private $limit;
/** @var int */
private $offset;
/** @var int */
private $page = 1;
/** @var EloquentBuilder */
private $query;
/** @var bool */
private $run = false;
/** @var User */
private $user;
/**
* JournalCollector constructor.
*
* @param User $user
*/
public function __construct(User $user)
{
$this->user = $user;
$this->query = $this->startQuery();
}
/**
* @return int
* @throws FireflyException
*/
public function count(): int
{
if ($this->run === true) {
throw new FireflyException('Cannot count after run in JournalCollector.');
}
$countQuery = clone $this->query;
// dont need some fields:
$countQuery->getQuery()->limit = null;
$countQuery->getQuery()->offset = null;
$countQuery->getQuery()->unionLimit = null;
$countQuery->getQuery()->groups = null;
$countQuery->groupBy('accounts.user_id');
$this->count = $countQuery->count();
return $this->count;
}
/**
* @return Collection
*/
public function getJournals(): Collection
{
$this->run = true;
$set = $this->query->get($this->fields);
// loop for decryption.
$set->each(
function (Transaction $transaction) {
$transaction->date = new Carbon($transaction->date);
$transaction->description = intval($transaction->encrypted) === 1 ? Crypt::decrypt($transaction->description) : $transaction->description;
$transaction->bill_name = !is_null($transaction->bill_name) ? Crypt::decrypt($transaction->bill_name) : '';
}
);
return $set;
}
/**
* It might be worth it to expand this query to include all account information required.
*
* @param Collection $accounts
* @param array $types
* @param Carbon $start
* @param Carbon $end
*
* @return Collection
*/
public function getJournalsInPeriod(Collection $accounts, array $types, Carbon $start, Carbon $end): Collection
{
$accountIds = $accounts->pluck('id')->toArray();
$query = Transaction
::leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id')
->leftJoin('transaction_currencies', 'transaction_currencies.id', 'transaction_journals.transaction_currency_id')
->leftJoin('transaction_types', 'transaction_types.id', 'transaction_journals.transaction_type_id')
->leftJoin('bills', 'bills.id', 'transaction_journals.bill_id')
->leftJoin('accounts', 'accounts.id', '=', 'transactions.account_id')
->leftJoin('account_types', 'accounts.account_type_id', 'account_types.id')
->whereIn('transactions.account_id', $accountIds)
->whereNull('transactions.deleted_at')
->whereNull('transaction_journals.deleted_at')
->where('transaction_journals.date', '>=', $start->format('Y-m-d'))
->where('transaction_journals.date', '<=', $end->format('Y-m-d'))
->where('transaction_journals.user_id', $this->user->id)
->orderBy('transaction_journals.date', 'DESC')
->orderBy('transaction_journals.order', 'ASC')
->orderBy('transaction_journals.id', 'DESC');
if (count($types) > 0) {
$query->whereIn('transaction_types.type', $types);
}
$set = $query->get(
[
'transaction_journals.id as journal_id',
'transaction_journals.description',
'transaction_journals.date',
'transaction_journals.encrypted',
//'transaction_journals.transaction_currency_id',
'transaction_currencies.code as transaction_currency_code',
//'transaction_currencies.symbol as transaction_currency_symbol',
'transaction_types.type as transaction_type_type',
'transaction_journals.bill_id',
'bills.name as bill_name',
'transactions.id as id',
'transactions.amount as transaction_amount',
'transactions.description as transaction_description',
'transactions.account_id',
'transactions.identifier',
'transactions.transaction_journal_id',
'accounts.name as account_name',
'accounts.encrypted as account_encrypted',
'account_types.type as account_type',
]
);
// loop for decryption.
$set->each(
function (Transaction $transaction) {
$transaction->date = new Carbon($transaction->date);
$transaction->description = intval($transaction->encrypted) === 1 ? Crypt::decrypt($transaction->description) : $transaction->description;
$transaction->bill_name = !is_null($transaction->bill_name) ? Crypt::decrypt($transaction->bill_name) : '';
}
);
return $set;
}
/**
* @return LengthAwarePaginator
* @throws FireflyException
*/
public function getPaginatedJournals():LengthAwarePaginator
{
if ($this->run === true) {
throw new FireflyException('Cannot getPaginatedJournals after run in JournalCollector.');
}
$this->count();
$set = $this->getJournals();
$journals = new LengthAwarePaginator($set, $this->count, $this->limit, $this->page);
return $journals;
}
/**
* @param Collection $accounts
*
* @return JournalCollector
*/
public function setAccounts(Collection $accounts): JournalCollector
{
if ($accounts->count() > 0) {
$accountIds = $accounts->pluck('id')->toArray();
$this->query->whereIn('transactions.account_id', $accountIds);
}
return $this;
}
/**
* @param int $limit
*
* @return JournalCollector
*/
public function setLimit(int $limit): JournalCollector
{
$this->limit = $limit;
$this->query->limit($limit);
Log::debug(sprintf('Set limit to %d', $limit));
return $this;
}
/**
* @param int $offset
*
* @return JournalCollector
*/
public function setOffset(int $offset): JournalCollector
{
$this->offset = $offset;
}
/**
* @param int $page
*
* @return JournalCollector
*/
public function setPage(int $page): JournalCollector
{
$this->page = $page;
if ($page > 0) {
$page--;
}
Log::debug(sprintf('Page is %d', $page));
if (!is_null($this->limit)) {
$offset = ($this->limit * $page);
$this->offset = $offset;
$this->query->skip($offset);
Log::debug(sprintf('Changed offset to %d', $offset));
}
if (is_null($this->limit)) {
Log::debug('The limit is zero, cannot set the page.');
}
return $this;
}
/**
* @param Carbon $start
* @param Carbon $end
*
* @return JournalCollector
*/
public function setRange(Carbon $start, Carbon $end): JournalCollector
{
if ($start <= $end) {
$this->query->where('transaction_journals.date', '>=', $start->format('Y-m-d'));
$this->query->where('transaction_journals.date', '<=', $end->format('Y-m-d'));
}
return $this;
}
/**
* @param Collection $accounts
*
* @return JournalCollector
*/
public function setDestinationAccounts(Collection $accounts): JournalCollector
{
if ($accounts->count() > 0) {
$accountIds = $accounts->pluck('id')->toArray();
$this->query->whereIn('transactions.account_id', $accountIds);
$this->query->where('transactions.amount', '>', 0);
}
return $this;
}
/**
* @param Collection $accounts
*
* @return JournalCollector
*/
public function setSourceAccounts(Collection $accounts): JournalCollector
{
if ($accounts->count() > 0) {
$accountIds = $accounts->pluck('id')->toArray();
$this->query->whereIn('transactions.account_id', $accountIds);
$this->query->where('transactions.amount', '<', 0);
}
return $this;
}
/**
* @param array $types
*
* @return JournalCollector
*/
public function setTypes(array $types): JournalCollector
{
if (count($types) > 0) {
$this->query->whereIn('transaction_types.type', $types);
}
return $this;
}
/**
* @return EloquentBuilder
*/
private function startQuery(): EloquentBuilder
{
$query = Transaction
::leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id')
->leftJoin('transaction_currencies', 'transaction_currencies.id', 'transaction_journals.transaction_currency_id')
->leftJoin('transaction_types', 'transaction_types.id', 'transaction_journals.transaction_type_id')
->leftJoin('bills', 'bills.id', 'transaction_journals.bill_id')
->leftJoin('accounts', 'accounts.id', '=', 'transactions.account_id')
->leftJoin('account_types', 'accounts.account_type_id', 'account_types.id')
->whereNull('transactions.deleted_at')
->whereNull('transaction_journals.deleted_at')
->where('transaction_journals.user_id', $this->user->id)
->orderBy('transaction_journals.date', 'DESC')
->orderBy('transaction_journals.order', 'ASC')
->orderBy('transaction_journals.id', 'DESC');
return $query;
}
}

View File

@ -15,6 +15,7 @@ namespace FireflyIII\Http\Controllers;
use Amount;
use Carbon\Carbon;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Helpers\Collector\JournalCollector;
use FireflyIII\Models\AccountType;
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use FireflyIII\Repositories\Account\AccountTaskerInterface;
@ -270,17 +271,20 @@ class JsonController extends Controller
}
/**
* @param JournalTaskerInterface $tasker
* @param $what
* @param $what
*
* @return \Symfony\Component\HttpFoundation\Response
* @return \Illuminate\Http\JsonResponse
*/
public function transactionJournals(JournalTaskerInterface $tasker, $what)
public function transactionJournals($what)
{
$descriptions = [];
$type = config('firefly.transactionTypesByWhat.' . $what);
$types = [$type];
$journals = $tasker->getJournals($types, 1, 50);
// use journal collector instead:
$collector = new JournalCollector(auth()->user());
$collector->setTypes($types)->setLimit(100)->setPage(1);
$journals = $collector->getJournals();
foreach ($journals as $j) {
$descriptions[] = $j->description;
}

View File

@ -14,7 +14,10 @@ declare(strict_types = 1);
namespace FireflyIII\Http\Controllers;
use Carbon\Carbon;
use FireflyIII\Helpers\Collector\JournalCollector;
use FireflyIII\Models\AccountType;
use FireflyIII\Models\TransactionJournal;
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use FireflyIII\Repositories\Journal\JournalRepositoryInterface;
use FireflyIII\Repositories\Journal\JournalTaskerInterface;
use Illuminate\Http\Request;
@ -49,21 +52,35 @@ class TransactionController extends Controller
}
/**
* @param Request $request
* @param JournalTaskerInterface $tasker
* @param string $what
* @param Request $request
* @param AccountRepositoryInterface $repository
* @param string $what
*
* @return View
*/
public function index(Request $request, JournalTaskerInterface $tasker, string $what)
public function index(Request $request, AccountRepositoryInterface $repository, string $what)
{
$pageSize = intval(Preferences::get('transactionPageSize', 50)->data);
$subTitleIcon = config('firefly.transactionIconsByWhat.' . $what);
$types = config('firefly.transactionTypesByWhat.' . $what);
$subTitle = trans('firefly.title_' . $what);
$page = intval($request->get('page'));
$journals = $tasker->getJournals($types, $page, $pageSize);
$pageSize = intval(Preferences::get('transactionPageSize', 50)->data);
$subTitleIcon = config('firefly.transactionIconsByWhat.' . $what);
$types = config('firefly.transactionTypesByWhat.' . $what);
$subTitle = trans('firefly.title_' . $what);
$page = intval($request->get('page'));
$assetAccounts = $repository->getAccountsByType([AccountType::DEFAULT, AccountType::ASSET]);
$collector = new JournalCollector(auth()->user());
$collector->setTypes($types)->setLimit($pageSize)->setPage($page);
// depending on the view, we filter the collector to grab the right stuff.
switch ($what) {
default:
$collector->setAccounts($assetAccounts);
break;
case 'transfer':
case 'transfers':
$collector->setDestinationAccounts($assetAccounts);
break;
}
$journals = $collector->getPaginatedJournals();
$journals->setPath('transactions/' . $what);
return view('transactions.index', compact('subTitle', 'what', 'subTitleIcon', 'journals'));

View File

@ -1,5 +1,12 @@
{{ journals.render|raw }}
{% if journals.count == 0 %}
<p>
<em>{{ 'nothing_to_display'|_ }}</em>
</p>
{% endif %}
{% if journals.count > 0 %}
<table class="table table-hover table-compressed {% if sorting %}sortable-table{% endif %}">
<thead>
<tr class="ignore">
@ -130,3 +137,4 @@
var edit_selected_txt = "{{ 'edit_selected'|_ }}";
var delete_selected_txt = "{{ 'delete_selected'|_ }}";
</script>
{% endif %}

View File

@ -12,7 +12,7 @@
<h3 class="box-title">{{ subTitle }}</h3>
</div>
<div class="box-body">
{% include 'list.journals' %}
{% include 'list.journals-tasker' %}
</div>
</div>
</div>