Allow more models to accept transactions #2828

This commit is contained in:
James Cole
2020-03-18 21:36:26 +01:00
parent c412ffc195
commit 3246b7eb9f
3 changed files with 214 additions and 98 deletions

View File

@@ -23,9 +23,6 @@ declare(strict_types=1);
namespace FireflyIII\Api\V1\Requests; namespace FireflyIII\Api\V1\Requests;
use FireflyIII\Models\Bill;
use FireflyIII\Models\ImportJob;
use FireflyIII\Models\TransactionJournal;
use FireflyIII\Rules\IsValidAttachmentModel; use FireflyIII\Rules\IsValidAttachmentModel;
/** /**
@@ -69,14 +66,14 @@ class AttachmentStoreRequest extends Request
*/ */
public function rules(): array public function rules(): array
{ {
$models = implode( $models = config('firefly.valid_attachment_models');
',', $models = array_map(
[
str_replace('FireflyIII\\Models\\', '', Bill::class), static function (string $className) {
str_replace('FireflyIII\\Models\\', '', ImportJob::class), return str_replace('FireflyIII\\Models\\', '', $className);
str_replace('FireflyIII\\Models\\', '', TransactionJournal::class), }, $models
]
); );
$models = implode(',', $models);
$model = $this->string('attachable_type'); $model = $this->string('attachable_type');
return [ return [

View File

@@ -24,15 +24,24 @@ declare(strict_types=1);
namespace FireflyIII\Rules; namespace FireflyIII\Rules;
use FireflyIII\Models\Account;
use FireflyIII\Models\Bill; use FireflyIII\Models\Bill;
use FireflyIII\Models\Budget;
use FireflyIII\Models\Category;
use FireflyIII\Models\ImportJob; use FireflyIII\Models\ImportJob;
use FireflyIII\Models\PiggyBank;
use FireflyIII\Models\Tag;
use FireflyIII\Models\Transaction; use FireflyIII\Models\Transaction;
use FireflyIII\Models\TransactionJournal; use FireflyIII\Models\TransactionJournal;
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use FireflyIII\Repositories\Bill\BillRepositoryInterface; use FireflyIII\Repositories\Bill\BillRepositoryInterface;
use FireflyIII\Repositories\Budget\BudgetRepositoryInterface;
use FireflyIII\Repositories\Category\CategoryRepositoryInterface;
use FireflyIII\Repositories\ImportJob\ImportJobRepositoryInterface; use FireflyIII\Repositories\ImportJob\ImportJobRepositoryInterface;
use FireflyIII\Repositories\Journal\JournalAPIRepositoryInterface; use FireflyIII\Repositories\Journal\JournalAPIRepositoryInterface;
use FireflyIII\Repositories\Journal\JournalRepositoryInterface; use FireflyIII\Repositories\Journal\JournalRepositoryInterface;
use FireflyIII\User; use FireflyIII\Repositories\PiggyBank\PiggyBankRepositoryInterface;
use FireflyIII\Repositories\Tag\TagRepositoryInterface;
use Illuminate\Contracts\Validation\Rule; use Illuminate\Contracts\Validation\Rule;
use Log; use Log;
@@ -80,54 +89,151 @@ class IsValidAttachmentModel implements Rule
if (!auth()->check()) { if (!auth()->check()) {
return false; return false;
} }
$methods = [
Account::class => 'validateAccount',
if (Bill::class === $this->model) { Bill::class => 'validateBill',
/** @var BillRepositoryInterface $repository */ Budget::class => 'validateBudget',
$repository = app(BillRepositoryInterface::class); Category::class => 'validateCategory',
/** @var User $user */ ImportJob::class => 'validateImportJob',
$user = auth()->user(); PiggyBank::class => 'validatePiggyBank',
$repository->setUser($user); Tag::class => 'validateTag',
$bill = $repository->find((int)$value); Transaction::class => 'validateTransaction',
TransactionJournal::class => 'validateJournal',
return null !== $bill; ];
} if (!isset($methods[$this->model])) {
Log::error(sprintf('Cannot validate model "%s" in %s.', $this->model, __METHOD__));
if (ImportJob::class === $this->model) {
/** @var ImportJobRepositoryInterface $repository */
$repository = app(ImportJobRepositoryInterface::class);
/** @var User $user */
$user = auth()->user();
$repository->setUser($user);
$importJob = $repository->find((int)$value);
return null !== $importJob;
}
if (Transaction::class === $this->model) {
/** @var JournalAPIRepositoryInterface $repository */
$repository = app(JournalAPIRepositoryInterface::class);
/** @var User $user */
$user = auth()->user();
$repository->setUser($user);
$transaction = $repository->findTransaction((int)$value);
return null !== $transaction;
}
if (TransactionJournal::class === $this->model) {
$repository = app(JournalRepositoryInterface::class);
$user = auth()->user();
$repository->setUser($user);
$result = $repository->findNull((int)$value);
return null !== $result;
}
Log::error(sprintf('No model was recognized from string "%s"', $this->model));
return false; return false;
} }
$method = $methods[$this->model];
return $this->$method((int) $value);
}
/**
* @param int $value
*
* @return bool
*/
private function validateTag(int $value): bool
{
/** @var TagRepositoryInterface $repository */
$repository = app(TagRepositoryInterface::class);
$repository->setUser(auth()->user());
return null !== $repository->findNull($value);
}
/**
* @param int $value
*
* @return bool
*/
private function validatePiggyBank(int $value): bool
{
/** @var PiggyBankRepositoryInterface $repository */
$repository = app(PiggyBankRepositoryInterface::class);
$repository->setUser(auth()->user());
return null !== $repository->findNull($value);
}
/**
* @param int $value
*
* @return bool
*/
private function validateBudget(int $value): bool
{
/** @var BudgetRepositoryInterface $repository */
$repository = app(BudgetRepositoryInterface::class);
$repository->setUser(auth()->user());
return null !== $repository->findNull($value);
}
/**
* @param int $value
*
* @return bool
*/
private function validateCategory(int $value): bool
{
/** @var CategoryRepositoryInterface $repository */
$repository = app(CategoryRepositoryInterface::class);
$repository->setUser(auth()->user());
return null !== $repository->findNull($value);
}
/**
* @param int $value
*
* @return bool
*/
private function validateAccount(int $value): bool
{
/** @var AccountRepositoryInterface $repository */
$repository = app(AccountRepositoryInterface::class);
$repository->setUser(auth()->user());
return null !== $repository->findNull($value);
}
/**
* @param int $value
*
* @return bool
*/
private function validateJournal(int $value): bool
{
$repository = app(JournalRepositoryInterface::class);
$repository->setUser(auth()->user());
return null !== $repository->findNull($value);
}
/**
* @param int $value
*
* @return bool
*/
private function validateTransaction(int $value): bool
{
/** @var JournalAPIRepositoryInterface $repository */
$repository = app(JournalAPIRepositoryInterface::class);
$repository->setUser(auth()->user());
return null !== $repository->findTransaction((int) $value);
}
/**
* @param int $value
*
* @return bool
*/
private function validateImportJob(int $value): bool
{
/** @var ImportJobRepositoryInterface $repository */
$repository = app(ImportJobRepositoryInterface::class);
$repository->setUser(auth()->user());
return null !== $repository->find($value);
}
/**
* @param int $value
*
* @return bool
*/
private function validateBill(int $value): bool
{
/** @var BillRepositoryInterface $repository */
$repository = app(BillRepositoryInterface::class);
$repository->setUser(auth()->user());
return null !== $repository->find($value);
}
/** /**
* @param string $model * @param string $model
@@ -141,6 +247,7 @@ class IsValidAttachmentModel implements Rule
$model = str_replace($search, $replace, $model); $model = str_replace($search, $replace, $model);
$model = sprintf('FireflyIII\Models\%s', $model); $model = sprintf('FireflyIII\Models\%s', $model);
return $model; return $model;
} }
} }

View File

@@ -38,6 +38,7 @@ use FireflyIII\Models\Recurrence;
use FireflyIII\Models\Rule; use FireflyIII\Models\Rule;
use FireflyIII\Models\RuleGroup; use FireflyIII\Models\RuleGroup;
use FireflyIII\Models\Tag; use FireflyIII\Models\Tag;
use FireflyIII\Models\Transaction;
use FireflyIII\Models\TransactionCurrency; use FireflyIII\Models\TransactionCurrency;
use FireflyIII\Models\TransactionGroup; use FireflyIII\Models\TransactionGroup;
use FireflyIII\Models\TransactionJournal; use FireflyIII\Models\TransactionJournal;
@@ -167,6 +168,17 @@ return [
'latitude' => env('MAP_DEFAULT_LAT', '51.983333'), 'latitude' => env('MAP_DEFAULT_LAT', '51.983333'),
'zoom_level' => env('MAP_DEFAULT_ZOOM', '6'), 'zoom_level' => env('MAP_DEFAULT_ZOOM', '6'),
], ],
'valid_attachment_models' => [
Account::class,
Bill::class,
Budget::class,
Category::class,
ImportJob::class,
PiggyBank::class,
Tag::class,
Transaction::class,
TransactionJournal::class,
],
'allowedMimes' => [ 'allowedMimes' => [
/* plain files */ /* plain files */
'text/plain', 'text/plain',
@@ -546,7 +558,7 @@ return [
'default_language' => envNonEmpty('DEFAULT_LANGUAGE', 'en_US'), 'default_language' => envNonEmpty('DEFAULT_LANGUAGE', 'en_US'),
'search_modifiers' => ['amount_is', 'amount', 'amount_max', 'amount_min', 'amount_less', 'amount_more', 'source', 'destination', 'category', 'search_modifiers' => ['amount_is', 'amount', 'amount_max', 'amount_min', 'amount_less', 'amount_more', 'source', 'destination', 'category',
'budget', 'bill', 'type', 'date', 'date_before', 'date_after', 'on', 'before', 'after', 'from', 'to', 'tag', 'created_on', 'budget', 'bill', 'type', 'date', 'date_before', 'date_after', 'on', 'before', 'after', 'from', 'to', 'tag', 'created_on',
'updated_on', ], 'updated_on',],
// TODO notes has_attachments // TODO notes has_attachments
'cer_providers' => [ 'cer_providers' => [
@@ -559,10 +571,10 @@ return [
'source' => [ 'source' => [
TransactionTypeModel::WITHDRAWAL => [AccountType::ASSET, AccountType::LOAN, AccountType::DEBT, AccountType::MORTGAGE], TransactionTypeModel::WITHDRAWAL => [AccountType::ASSET, AccountType::LOAN, AccountType::DEBT, AccountType::MORTGAGE],
TransactionTypeModel::DEPOSIT => [AccountType::REVENUE, AccountType::CASH, AccountType::LOAN, AccountType::DEBT, AccountType::MORTGAGE, TransactionTypeModel::DEPOSIT => [AccountType::REVENUE, AccountType::CASH, AccountType::LOAN, AccountType::DEBT, AccountType::MORTGAGE,
AccountType::INITIAL_BALANCE, AccountType::RECONCILIATION, ], AccountType::INITIAL_BALANCE, AccountType::RECONCILIATION,],
TransactionTypeModel::TRANSFER => [AccountType::ASSET, AccountType::LOAN, AccountType::DEBT, AccountType::MORTGAGE], TransactionTypeModel::TRANSFER => [AccountType::ASSET, AccountType::LOAN, AccountType::DEBT, AccountType::MORTGAGE],
TransactionTypeModel::OPENING_BALANCE => [AccountType::INITIAL_BALANCE, AccountType::ASSET, AccountType::LOAN, AccountType::DEBT, TransactionTypeModel::OPENING_BALANCE => [AccountType::INITIAL_BALANCE, AccountType::ASSET, AccountType::LOAN, AccountType::DEBT,
AccountType::MORTGAGE, ], AccountType::MORTGAGE,],
TransactionTypeModel::RECONCILIATION => [AccountType::RECONCILIATION, AccountType::ASSET], TransactionTypeModel::RECONCILIATION => [AccountType::RECONCILIATION, AccountType::ASSET],
// in case no transaction type is known yet, it could be anything. // in case no transaction type is known yet, it could be anything.
'none' => [ 'none' => [
@@ -576,43 +588,43 @@ return [
], ],
'destination' => [ 'destination' => [
TransactionTypeModel::WITHDRAWAL => [AccountType::EXPENSE, AccountType::CASH, AccountType::LOAN, AccountType::DEBT, TransactionTypeModel::WITHDRAWAL => [AccountType::EXPENSE, AccountType::CASH, AccountType::LOAN, AccountType::DEBT,
AccountType::MORTGAGE, ], AccountType::MORTGAGE,],
TransactionTypeModel::DEPOSIT => [AccountType::ASSET, AccountType::LOAN, AccountType::DEBT, AccountType::MORTGAGE], TransactionTypeModel::DEPOSIT => [AccountType::ASSET, AccountType::LOAN, AccountType::DEBT, AccountType::MORTGAGE],
TransactionTypeModel::TRANSFER => [AccountType::ASSET, AccountType::LOAN, AccountType::DEBT, AccountType::MORTGAGE], TransactionTypeModel::TRANSFER => [AccountType::ASSET, AccountType::LOAN, AccountType::DEBT, AccountType::MORTGAGE],
TransactionTypeModel::OPENING_BALANCE => [AccountType::INITIAL_BALANCE, AccountType::ASSET, AccountType::LOAN, AccountType::DEBT, TransactionTypeModel::OPENING_BALANCE => [AccountType::INITIAL_BALANCE, AccountType::ASSET, AccountType::LOAN, AccountType::DEBT,
AccountType::MORTGAGE, ], AccountType::MORTGAGE,],
TransactionTypeModel::RECONCILIATION => [AccountType::RECONCILIATION, AccountType::ASSET], TransactionTypeModel::RECONCILIATION => [AccountType::RECONCILIATION, AccountType::ASSET],
], ],
], ],
'allowed_opposing_types' => [ 'allowed_opposing_types' => [
'source' => [ 'source' => [
AccountType::ASSET => [AccountType::ASSET, AccountType::CASH, AccountType::DEBT, AccountType::EXPENSE, AccountType::INITIAL_BALANCE, AccountType::ASSET => [AccountType::ASSET, AccountType::CASH, AccountType::DEBT, AccountType::EXPENSE, AccountType::INITIAL_BALANCE,
AccountType::LOAN, AccountType::RECONCILIATION, ], AccountType::LOAN, AccountType::RECONCILIATION,],
AccountType::CASH => [AccountType::ASSET], AccountType::CASH => [AccountType::ASSET],
AccountType::DEBT => [AccountType::ASSET, AccountType::DEBT, AccountType::EXPENSE, AccountType::INITIAL_BALANCE, AccountType::LOAN, AccountType::DEBT => [AccountType::ASSET, AccountType::DEBT, AccountType::EXPENSE, AccountType::INITIAL_BALANCE, AccountType::LOAN,
AccountType::MORTGAGE, ], AccountType::MORTGAGE,],
AccountType::EXPENSE => [], // is not allowed as a source. AccountType::EXPENSE => [], // is not allowed as a source.
AccountType::INITIAL_BALANCE => [AccountType::ASSET, AccountType::DEBT, AccountType::LOAN, AccountType::MORTGAGE], AccountType::INITIAL_BALANCE => [AccountType::ASSET, AccountType::DEBT, AccountType::LOAN, AccountType::MORTGAGE],
AccountType::LOAN => [AccountType::ASSET, AccountType::DEBT, AccountType::EXPENSE, AccountType::INITIAL_BALANCE, AccountType::LOAN, AccountType::LOAN => [AccountType::ASSET, AccountType::DEBT, AccountType::EXPENSE, AccountType::INITIAL_BALANCE, AccountType::LOAN,
AccountType::MORTGAGE, ], AccountType::MORTGAGE,],
AccountType::MORTGAGE => [AccountType::ASSET, AccountType::DEBT, AccountType::EXPENSE, AccountType::INITIAL_BALANCE, AccountType::LOAN, AccountType::MORTGAGE => [AccountType::ASSET, AccountType::DEBT, AccountType::EXPENSE, AccountType::INITIAL_BALANCE, AccountType::LOAN,
AccountType::MORTGAGE, ], AccountType::MORTGAGE,],
AccountType::RECONCILIATION => [AccountType::ASSET], AccountType::RECONCILIATION => [AccountType::ASSET],
AccountType::REVENUE => [AccountType::ASSET, AccountType::DEBT, AccountType::LOAN, AccountType::MORTGAGE], AccountType::REVENUE => [AccountType::ASSET, AccountType::DEBT, AccountType::LOAN, AccountType::MORTGAGE],
], ],
'destination' => [ 'destination' => [
AccountType::ASSET => [AccountType::ASSET, AccountType::CASH, AccountType::DEBT, AccountType::INITIAL_BALANCE, AccountType::LOAN, AccountType::ASSET => [AccountType::ASSET, AccountType::CASH, AccountType::DEBT, AccountType::INITIAL_BALANCE, AccountType::LOAN,
AccountType::MORTGAGE, AccountType::RECONCILIATION, AccountType::REVENUE, ], AccountType::MORTGAGE, AccountType::RECONCILIATION, AccountType::REVENUE,],
AccountType::CASH => [AccountType::ASSET], AccountType::CASH => [AccountType::ASSET],
AccountType::DEBT => [AccountType::ASSET, AccountType::DEBT, AccountType::INITIAL_BALANCE, AccountType::LOAN, AccountType::MORTGAGE, AccountType::DEBT => [AccountType::ASSET, AccountType::DEBT, AccountType::INITIAL_BALANCE, AccountType::LOAN, AccountType::MORTGAGE,
AccountType::REVENUE, ], AccountType::REVENUE,],
AccountType::EXPENSE => [AccountType::ASSET, AccountType::DEBT, AccountType::LOAN, AccountType::MORTGAGE], AccountType::EXPENSE => [AccountType::ASSET, AccountType::DEBT, AccountType::LOAN, AccountType::MORTGAGE],
AccountType::INITIAL_BALANCE => [AccountType::ASSET, AccountType::DEBT, AccountType::LOAN, AccountType::MORTGAGE], AccountType::INITIAL_BALANCE => [AccountType::ASSET, AccountType::DEBT, AccountType::LOAN, AccountType::MORTGAGE],
AccountType::LOAN => [AccountType::ASSET, AccountType::DEBT, AccountType::INITIAL_BALANCE, AccountType::LOAN, AccountType::MORTGAGE, AccountType::LOAN => [AccountType::ASSET, AccountType::DEBT, AccountType::INITIAL_BALANCE, AccountType::LOAN, AccountType::MORTGAGE,
AccountType::REVENUE, ], AccountType::REVENUE,],
AccountType::MORTGAGE => [AccountType::ASSET, AccountType::DEBT, AccountType::INITIAL_BALANCE, AccountType::LOAN, AccountType::MORTGAGE, AccountType::MORTGAGE => [AccountType::ASSET, AccountType::DEBT, AccountType::INITIAL_BALANCE, AccountType::LOAN, AccountType::MORTGAGE,
AccountType::REVENUE, ], AccountType::REVENUE,],
AccountType::RECONCILIATION => [AccountType::ASSET], AccountType::RECONCILIATION => [AccountType::ASSET],
AccountType::REVENUE => [], // is not allowed as a destination AccountType::REVENUE => [], // is not allowed as a destination
], ],
@@ -621,29 +633,29 @@ return [
'allowed_transaction_types' => [ 'allowed_transaction_types' => [
'source' => [ 'source' => [
AccountType::ASSET => [TransactionTypeModel::WITHDRAWAL, TransactionTypeModel::TRANSFER, TransactionTypeModel::OPENING_BALANCE, AccountType::ASSET => [TransactionTypeModel::WITHDRAWAL, TransactionTypeModel::TRANSFER, TransactionTypeModel::OPENING_BALANCE,
TransactionTypeModel::RECONCILIATION, ], TransactionTypeModel::RECONCILIATION,],
AccountType::EXPENSE => [], // is not allowed as a source. AccountType::EXPENSE => [], // is not allowed as a source.
AccountType::REVENUE => [TransactionTypeModel::DEPOSIT], AccountType::REVENUE => [TransactionTypeModel::DEPOSIT],
AccountType::LOAN => [TransactionTypeModel::WITHDRAWAL, TransactionTypeModel::DEPOSIT, TransactionTypeModel::TRANSFER, AccountType::LOAN => [TransactionTypeModel::WITHDRAWAL, TransactionTypeModel::DEPOSIT, TransactionTypeModel::TRANSFER,
TransactionTypeModel::OPENING_BALANCE, ], TransactionTypeModel::OPENING_BALANCE,],
AccountType::DEBT => [TransactionTypeModel::WITHDRAWAL, TransactionTypeModel::DEPOSIT, TransactionTypeModel::TRANSFER, AccountType::DEBT => [TransactionTypeModel::WITHDRAWAL, TransactionTypeModel::DEPOSIT, TransactionTypeModel::TRANSFER,
TransactionTypeModel::OPENING_BALANCE, ], TransactionTypeModel::OPENING_BALANCE,],
AccountType::MORTGAGE => [TransactionTypeModel::WITHDRAWAL, TransactionTypeModel::DEPOSIT, TransactionTypeModel::TRANSFER, AccountType::MORTGAGE => [TransactionTypeModel::WITHDRAWAL, TransactionTypeModel::DEPOSIT, TransactionTypeModel::TRANSFER,
TransactionTypeModel::OPENING_BALANCE, ], TransactionTypeModel::OPENING_BALANCE,],
AccountType::INITIAL_BALANCE => [], // todo fill me in. AccountType::INITIAL_BALANCE => [], // todo fill me in.
AccountType::RECONCILIATION => [], // todo fill me in. AccountType::RECONCILIATION => [], // todo fill me in.
], ],
'destination' => [ 'destination' => [
AccountType::ASSET => [TransactionTypeModel::DEPOSIT, TransactionTypeModel::TRANSFER, TransactionTypeModel::OPENING_BALANCE, AccountType::ASSET => [TransactionTypeModel::DEPOSIT, TransactionTypeModel::TRANSFER, TransactionTypeModel::OPENING_BALANCE,
TransactionTypeModel::RECONCILIATION, ], TransactionTypeModel::RECONCILIATION,],
AccountType::EXPENSE => [TransactionTypeModel::WITHDRAWAL], AccountType::EXPENSE => [TransactionTypeModel::WITHDRAWAL],
AccountType::REVENUE => [], // is not allowed as destination. AccountType::REVENUE => [], // is not allowed as destination.
AccountType::LOAN => [TransactionTypeModel::WITHDRAWAL, TransactionTypeModel::DEPOSIT, TransactionTypeModel::TRANSFER, AccountType::LOAN => [TransactionTypeModel::WITHDRAWAL, TransactionTypeModel::DEPOSIT, TransactionTypeModel::TRANSFER,
TransactionTypeModel::OPENING_BALANCE, ], TransactionTypeModel::OPENING_BALANCE,],
AccountType::DEBT => [TransactionTypeModel::WITHDRAWAL, TransactionTypeModel::DEPOSIT, TransactionTypeModel::TRANSFER, AccountType::DEBT => [TransactionTypeModel::WITHDRAWAL, TransactionTypeModel::DEPOSIT, TransactionTypeModel::TRANSFER,
TransactionTypeModel::OPENING_BALANCE, ], TransactionTypeModel::OPENING_BALANCE,],
AccountType::MORTGAGE => [TransactionTypeModel::WITHDRAWAL, TransactionTypeModel::DEPOSIT, TransactionTypeModel::TRANSFER, AccountType::MORTGAGE => [TransactionTypeModel::WITHDRAWAL, TransactionTypeModel::DEPOSIT, TransactionTypeModel::TRANSFER,
TransactionTypeModel::OPENING_BALANCE, ], TransactionTypeModel::OPENING_BALANCE,],
AccountType::INITIAL_BALANCE => [], // todo fill me in. AccountType::INITIAL_BALANCE => [], // todo fill me in.
AccountType::RECONCILIATION => [], // todo fill me in. AccountType::RECONCILIATION => [], // todo fill me in.
], ],