Update internal filters.

This commit is contained in:
James Cole 2017-04-28 20:08:04 +02:00
parent 68a01b1735
commit c83dfc44d6
No known key found for this signature in database
GPG Key ID: C16961E655E74B5E
8 changed files with 116 additions and 146 deletions

View File

@ -18,12 +18,15 @@ use Carbon\Carbon;
use Crypt;
use DB;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Helpers\Filter\FilterInterface;
use FireflyIII\Helpers\Filter\InternalTransferFilter;
use FireflyIII\Helpers\Filter\OpposingAccountFilter;
use FireflyIII\Helpers\Filter\TransferFilter;
use FireflyIII\Models\AccountType;
use FireflyIII\Models\Budget;
use FireflyIII\Models\Category;
use FireflyIII\Models\Tag;
use FireflyIII\Models\Transaction;
use FireflyIII\Models\TransactionType;
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use FireflyIII\User;
use Illuminate\Contracts\Encryption\DecryptException;
@ -74,6 +77,9 @@ class JournalCollector implements JournalCollectorInterface
private $filterInternalTransfers;
/** @var bool */
private $filterTransfers = false;
/** @var array */
private $filters = [InternalTransferFilter::class];
/** @var bool */
private $joinedBudget = false;
/** @var bool */
@ -95,6 +101,22 @@ class JournalCollector implements JournalCollectorInterface
/** @var User */
private $user;
/**
* @param string $filter
*
* @return JournalCollectorInterface
*/
public function addFilter(string $filter): JournalCollectorInterface
{
$interfaces = class_implements($filter);
if (in_array(FilterInterface::class, $interfaces)) {
Log::debug(sprintf('Enabled filter %s', $filter));
$this->filters[] = $filter;
}
return $this;
}
/**
* @return int
* @throws FireflyException
@ -119,36 +141,6 @@ class JournalCollector implements JournalCollectorInterface
return $this->count;
}
/**
* @return JournalCollectorInterface
*/
public function disableFilter(): JournalCollectorInterface
{
$this->filterTransfers = false;
return $this;
}
/**
* @return JournalCollectorInterface
*/
public function disableInternalFilter(): JournalCollectorInterface
{
$this->filterInternalTransfers = false;
return $this;
}
/**
* @return JournalCollectorInterface
*/
public function enableInternalFilter(): JournalCollectorInterface
{
$this->filterInternalTransfers = true;
return $this;
}
/**
* @return Collection
*/
@ -157,14 +149,9 @@ class JournalCollector implements JournalCollectorInterface
$this->run = true;
/** @var Collection $set */
$set = $this->query->get(array_values($this->fields));
Log::debug(sprintf('Count of set is %d', $set->count()));
$set = $this->filterTransfers($set);
Log::debug(sprintf('Count of set after filterTransfers() is %d', $set->count()));
// possibly filter "internal" transfers:
$set = $this->filterInternalTransfers($set);
Log::debug(sprintf('Count of set after filterInternalTransfers() is %d', $set->count()));
// run all filters:
$set = $this->filter($set);
// loop for decryption.
$set->each(
@ -204,6 +191,22 @@ class JournalCollector implements JournalCollectorInterface
return $journals;
}
/**
* @param string $filter
*
* @return JournalCollectorInterface
*/
public function removeFilter(string $filter): JournalCollectorInterface
{
$key = array_search($filter, $this->filters, true);
if (!($key === false)) {
Log::debug('Removed filter %s', $filter);
unset($this->filters[$key]);
}
return $this;
}
/**
* @param Collection $accounts
*
@ -219,6 +222,7 @@ class JournalCollector implements JournalCollectorInterface
}
if ($accounts->count() > 1) {
$this->addFilter(TransferFilter::class);
$this->filterTransfers = true;
}
@ -242,6 +246,7 @@ class JournalCollector implements JournalCollectorInterface
}
if ($accounts->count() > 1) {
$this->addFilter(TransferFilter::class);
$this->filterTransfers = true;
}
@ -563,79 +568,21 @@ class JournalCollector implements JournalCollectorInterface
*
* @return Collection
*/
private function filterInternalTransfers(Collection $set): Collection
private function filter(Collection $set): Collection
{
if ($this->filterInternalTransfers === false) {
Log::debug('Did NO filtering for internal transfers on given set.');
return $set;
}
if ($this->joinedOpposing === false) {
Log::info('Cannot filter internal transfers because no opposing information is present.');
return $set;
}
$accountIds = $this->accountIds;
$set = $set->filter(
function (Transaction $transaction) use ($accountIds) {
// both id's in $accountids?
if (in_array($transaction->account_id, $accountIds) && in_array($transaction->opposing_account_id, $accountIds)) {
Log::debug(
sprintf(
'Transaction #%d has #%d and #%d in set, so removed',
$transaction->id, $transaction->account_id, $transaction->opposing_account_id
), $accountIds
);
return false;
}
return $transaction;
// create all possible filters:
$filters = [
InternalTransferFilter::class => new InternalTransferFilter($this->accountIds),
OpposingAccountFilter::class => new OpposingAccountFilter($this->accountIds),
TransferFilter::class => new TransferFilter,
];
Log::debug(sprintf('Will run %d filters on the set.', count($this->filters)));
foreach ($this->filters as $enabled) {
if (isset($filters[$enabled])) {
Log::debug(sprintf('Before filter %s: %d', $enabled, $set->count()));
$set = $filters[$enabled]->filter($set);
Log::debug(sprintf('After filter %s: %d', $enabled, $set->count()));
}
);
return $set;
}
/**
* If the set of accounts used by the collector includes more than one asset
* account, chances are the set include double entries: transfers get selected
* on both the source, and then again on the destination account.
*
* This method filters them out by removing transfers that have been selected twice.
*
* @param Collection $set
*
* @return Collection
*/
private function filterTransfers(Collection $set): Collection
{
if ($this->filterTransfers) {
$count = [];
$new = new Collection;
/** @var Transaction $transaction */
foreach ($set as $transaction) {
if ($transaction->transaction_type_type !== TransactionType::TRANSFER) {
$new->push($transaction);
continue;
}
// make property string:
$journalId = $transaction->transaction_journal_id;
$amount = Steam::positive($transaction->transaction_amount);
$accountIds = [intval($transaction->account_id), intval($transaction->opposing_account_id)];
sort($accountIds);
$key = $journalId . '-' . join(',', $accountIds) . '-' . $amount;
Log::debug(sprintf('Key is %s', $key));
if (!isset($count[$key])) {
// not yet counted? add to new set and count it:
$new->push($transaction);
$count[$key] = 1;
}
}
return $new;
}
return $set;

View File

@ -28,26 +28,18 @@ use Illuminate\Support\Collection;
*/
interface JournalCollectorInterface
{
/**
* @param string $filter
*
* @return JournalCollectorInterface
*/
public function addFilter(string $filter): JournalCollectorInterface;
/**
* @return int
*/
public function count(): int;
/**
* @return JournalCollectorInterface
*/
public function disableFilter(): JournalCollectorInterface;
/**
* @return JournalCollectorInterface
*/
public function disableInternalFilter(): JournalCollectorInterface;
/**
* @return JournalCollectorInterface
*/
public function enableInternalFilter(): JournalCollectorInterface;
/**
* @return Collection
*/
@ -58,6 +50,13 @@ interface JournalCollectorInterface
*/
public function getPaginatedJournals(): LengthAwarePaginator;
/**
* @param string $filter
*
* @return JournalCollectorInterface
*/
public function removeFilter(string $filter): JournalCollectorInterface;
/**
* @param Collection $accounts
*

View File

@ -25,19 +25,25 @@ use Log;
*/
class AmountFilter implements FilterInterface
{
/** @var int */
private $modifier = 0;
public function __construct(int $modifier)
{
$this->modifier = $modifier;
}
/**
* @param Collection $set
* @param null $parameters
*
* @return Collection
*/
public function filter(Collection $set, $parameters = null): Collection
public function filter(Collection $set): Collection
{
return $set->filter(
function (Transaction $transaction) use ($parameters) {
function (Transaction $transaction) {
// remove by amount
if (bccomp($transaction->transaction_amount, '0') === $parameters) {
if (bccomp($transaction->transaction_amount, '0') === $this->modifier) {
Log::debug(sprintf('Filtered #%d because amount is %f.', $transaction->id, $transaction->transaction_amount));
return null;

View File

@ -24,13 +24,11 @@ class EmptyFilter implements FilterInterface
/**
* @param Collection $set
* @param null $parameters
*
* @return Collection
*/
public function filter(Collection $set, $parameters = null): Collection
public function filter(Collection $set): Collection
{
// TODO: Implement filter() method.
throw new NotImplementedException;
return $set;
}
}

View File

@ -18,10 +18,9 @@ interface FilterInterface
{
/**
* @param Collection $set
* @param null $parameters
*
* @return Collection
*/
public function filter(Collection $set, $parameters = null): Collection;
public function filter(Collection $set): Collection;
}

View File

@ -26,27 +26,38 @@ use Log;
*/
class InternalTransferFilter implements FilterInterface
{
/** @var array */
private $accounts = [];
/**
* InternalTransferFilter constructor.
*
* @param array $accounts
*/
public function __construct(array $accounts)
{
$this->accounts = $accounts;
}
/**
* @param Collection $set
* @param null $parameters
*
* @return Collection
*/
public function filter(Collection $set, $parameters = null): Collection
public function filter(Collection $set): Collection
{
return $set->filter(
function (Transaction $transaction) use ($parameters) {
function (Transaction $transaction) {
if (is_null($transaction->opposing_account_id)) {
return $transaction;
}
// both id's in $parameters?
if (in_array($transaction->account_id, $parameters) && in_array($transaction->opposing_account_id, $parameters)) {
if (in_array($transaction->account_id, $this->accounts) && in_array($transaction->opposing_account_id, $this->accounts)) {
Log::debug(
sprintf(
'Transaction #%d has #%d and #%d in set, so removed',
$transaction->id, $transaction->account_id, $transaction->opposing_account_id
), $parameters
), $this->accounts
);
return false;

View File

@ -26,21 +26,32 @@ use Log;
*/
class OpposingAccountFilter implements FilterInterface
{
/** @var array */
private $accounts = [];
/**
* InternalTransferFilter constructor.
*
* @param array $accounts
*/
public function __construct(array $accounts)
{
$this->accounts = $accounts;
}
/**
* @param Collection $set
* @param null $parameters
*
* @return Collection
*/
public function filter(Collection $set, $parameters = null): Collection
public function filter(Collection $set): Collection
{
return $set->filter(
function (Transaction $transaction) use ($parameters) {
function (Transaction $transaction) {
$opposing = $transaction->opposing_account_id;
// remove internal transfer
if (in_array($opposing, $parameters)) {
Log::debug(sprintf('Filtered #%d because its opposite is in accounts.', $transaction->id), $parameters);
if (in_array($opposing, $this->accounts)) {
Log::debug(sprintf('Filtered #%d because its opposite is in accounts.', $transaction->id), $this->accounts);
return null;
}

View File

@ -27,11 +27,10 @@ class TransferFilter implements FilterInterface
{
/**
* @param Collection $set
* @param null $parameters
*
* @return Collection
*/
public function filter(Collection $set, $parameters = null): Collection
public function filter(Collection $set): Collection
{
$count = [];
$new = new Collection;