diff --git a/.gitignore b/.gitignore index 3285ef1ed2..485afe93a2 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,4 @@ _development .env.local result.html test-import.sh +test-import-report.txt diff --git a/app/Console/Commands/Import.php b/app/Console/Commands/Import.php index bd02d71384..7f92e063ab 100644 --- a/app/Console/Commands/Import.php +++ b/app/Console/Commands/Import.php @@ -19,6 +19,7 @@ use FireflyIII\Import\Logging\CommandHandler; use FireflyIII\Models\ImportJob; use Illuminate\Console\Command; use Log; +use Monolog\Handler\StreamHandler; /** * Class Import @@ -80,6 +81,7 @@ class Import extends Command // intercept logging by importer. $monolog = Log::getMonolog(); $handler = new CommandHandler($this); + $monolog->pushHandler($handler); // create import entries diff --git a/app/Crud/Account/AccountCrud.php b/app/Crud/Account/AccountCrud.php index 787ced7bbf..552d7e0f5f 100644 --- a/app/Crud/Account/AccountCrud.php +++ b/app/Crud/Account/AccountCrud.php @@ -158,10 +158,12 @@ class AccountCrud implements AccountCrudInterface /** @var Account $account */ foreach ($accounts as $account) { if ($account->name === $name) { - Log::debug('Account name is an exact match. ', ['db' => $account->name, 'source' => $name,'id' => $account->id]); + Log::debug('Account name is an exact match. ', ['db' => $account->name, 'source' => $name, 'id' => $account->id]); + + return $account; } } - Log::warning('Found nothing in findByName()', ['name' => $name, 'types' => $types]); + Log::debug('Found nothing in findByName()', ['name' => $name, 'types' => $types]); return new Account; } @@ -233,7 +235,7 @@ class AccountCrud implements AccountCrudInterface public function store(array $data): Account { $newAccount = $this->storeAccount($data); - if (!is_null($newAccount)) { + if (!is_null($newAccount->id)) { $this->storeMetadata($newAccount, $data); } @@ -327,8 +329,8 @@ class AccountCrud implements AccountCrudInterface ]; $existingAccount = Account::firstOrNullEncrypted($searchData); if (!$existingAccount) { - Log::error('Account create error: ' . $newAccount->getErrors()->toJson()); - abort(500); + Log::error('Account create error', $newAccount->getErrors()->toArray()); + return new Account; } $newAccount = $existingAccount; diff --git a/app/Import/Converter/AssetAccountIban.php b/app/Import/Converter/AssetAccountIban.php index 3cbe47bc91..a22022db3b 100644 --- a/app/Import/Converter/AssetAccountIban.php +++ b/app/Import/Converter/AssetAccountIban.php @@ -66,9 +66,17 @@ class AssetAccountIban extends BasicConverter implements ConverterInterface $account = $repository->store( - ['name' => 'Account with IBAN ' . $value, 'iban' => $value, 'user' => $this->user->id, 'accountType' => 'asset', 'virtualBalance' => 0, - 'active' => true] + ['name' => 'Asset account with IBAN ' . $value, 'iban' => $value, 'user' => $this->user->id, 'accountType' => 'asset', 'virtualBalance' => 0, + 'active' => true, 'openingBalance' => 0] ); + + if (is_null($account->id)) { + $this->setCertainty(0); + Log::info('Could not store new asset account by IBAN', $account->getErrors()->toArray()); + + return new Account; + } + $this->setCertainty(100); return $account; diff --git a/app/Import/Converter/AssetAccountName.php b/app/Import/Converter/AssetAccountName.php index af293656be..a8e7ef27a6 100644 --- a/app/Import/Converter/AssetAccountName.php +++ b/app/Import/Converter/AssetAccountName.php @@ -68,6 +68,14 @@ class AssetAccountName extends BasicConverter implements ConverterInterface ['name' => $value, 'iban' => null, 'openingBalance' => 0, 'user' => $this->user->id, 'accountType' => 'asset', 'virtualBalance' => 0, 'active' => true] ); + + if (is_null($account->id)) { + $this->setCertainty(0); + Log::info('Could not store new asset account by name', $account->getErrors()->toArray()); + + return new Account; + } + $this->setCertainty(100); Log::debug('Created new asset account ', ['name' => $account->name, 'id' => $account->id]); diff --git a/app/Import/Converter/AssetAccountNumber.php b/app/Import/Converter/AssetAccountNumber.php index cc478ca94a..241ebf0a3a 100644 --- a/app/Import/Converter/AssetAccountNumber.php +++ b/app/Import/Converter/AssetAccountNumber.php @@ -32,7 +32,7 @@ class AssetAccountNumber extends BasicConverter implements ConverterInterface public function convert($value) { $value = trim($value); - Log::debug('Going to convert using AssetAccountName', ['value' => $value]); + Log::debug('Going to convert using AssetAccountNumber', ['value' => $value]); if (strlen($value) === 0) { return new Account; @@ -77,6 +77,14 @@ class AssetAccountNumber extends BasicConverter implements ConverterInterface 'accountType' => 'asset', 'virtualBalance' => 0, 'accountNumber' => $value, 'active' => true] ); + + if (is_null($account->id)) { + $this->setCertainty(0); + Log::notice('Could not store new asset account by account number', $account->getErrors()->toArray()); + + return new Account; + } + $this->setCertainty(100); return $account; diff --git a/app/Import/Converter/BillId.php b/app/Import/Converter/BillId.php index 3d6a4cc67e..74ccedc513 100644 --- a/app/Import/Converter/BillId.php +++ b/app/Import/Converter/BillId.php @@ -63,6 +63,7 @@ class BillId extends BasicConverter implements ConverterInterface } // should not really happen. If the ID does not match FF, what is FF supposed to do? + Log::info(sprintf('Could not find bill with ID %d. Will return NULL', $value)); $this->setCertainty(0); diff --git a/app/Import/Converter/BillName.php b/app/Import/Converter/BillName.php index 9d06e13105..a159ab4a3a 100644 --- a/app/Import/Converter/BillName.php +++ b/app/Import/Converter/BillName.php @@ -76,6 +76,13 @@ class BillName extends BasicConverter implements ConverterInterface ] ); + if (is_null($bill->id)) { + $this->setCertainty(0); + Log::info('Could not store new bill by name', $bill->getErrors()->toArray()); + + return new Bill; + } + $this->setCertainty(100); return $bill; diff --git a/app/Import/Converter/BudgetId.php b/app/Import/Converter/BudgetId.php index 6e50fb0e20..7d18d58de4 100644 --- a/app/Import/Converter/BudgetId.php +++ b/app/Import/Converter/BudgetId.php @@ -63,6 +63,9 @@ class BudgetId extends BasicConverter implements ConverterInterface // should not really happen. If the ID does not match FF, what is FF supposed to do? $this->setCertainty(0); + + Log::info(sprintf('Could not find budget with ID %d. Will return NULL', $value)); + return new Budget; } diff --git a/app/Import/Converter/CategoryId.php b/app/Import/Converter/CategoryId.php index 03fefa2cd5..1a2d3fc45c 100644 --- a/app/Import/Converter/CategoryId.php +++ b/app/Import/Converter/CategoryId.php @@ -62,6 +62,9 @@ class CategoryId extends BasicConverter implements ConverterInterface // should not really happen. If the ID does not match FF, what is FF supposed to do? $this->setCertainty(0); + + Log::info(sprintf('Could not find category with ID %d. Will return NULL', $value)); + return new Category; } diff --git a/app/Import/Converter/CurrencyId.php b/app/Import/Converter/CurrencyId.php index 08b8b43775..2dd402dafe 100644 --- a/app/Import/Converter/CurrencyId.php +++ b/app/Import/Converter/CurrencyId.php @@ -61,6 +61,9 @@ class CurrencyId extends BasicConverter implements ConverterInterface } $this->setCertainty(0); // should not really happen. If the ID does not match FF, what is FF supposed to do? + + Log::info(sprintf('Could not find category with ID %d. Will return NULL', $value)); + return new TransactionCurrency; } diff --git a/app/Import/Converter/Date.php b/app/Import/Converter/Date.php index d9619631a2..134d141e10 100644 --- a/app/Import/Converter/Date.php +++ b/app/Import/Converter/Date.php @@ -37,9 +37,10 @@ class Date extends BasicConverter implements ConverterInterface try { $date = Carbon::createFromFormat($this->config['date-format'], $value); } catch (InvalidArgumentException $e) { - Log::critical($e->getMessage()); - Log::critical('Cannot convert this string using the given format.', ['value' => $value, 'format' => $this->config['date-format']]); - throw new FireflyException(sprintf('Cannot convert "%s" to a valid date using format "%s".', $value, $this->config['date-format'])); + Log::notice($e->getMessage()); + Log::notice('Cannot convert this string using the given format.', ['value' => $value, 'format' => $this->config['date-format']]); + $this->setCertainty(0); + return new Carbon; } Log::debug('Converted date', ['converted' => $date->toAtomString()]); $this->setCertainty(100); diff --git a/app/Import/Converter/OpposingAccountIban.php b/app/Import/Converter/OpposingAccountIban.php index 674134c43b..27487b4542 100644 --- a/app/Import/Converter/OpposingAccountIban.php +++ b/app/Import/Converter/OpposingAccountIban.php @@ -56,7 +56,7 @@ class OpposingAccountIban extends BasicConverter implements ConverterInterface $account = $repository->findByIban($value, []); if (!is_null($account->id)) { Log::debug('Found account by IBAN', ['id' => $account->id]); - Log::warning( + Log::notice( 'The match between IBAN and account is uncertain because the type of transactions may not have been determined.', ['id' => $account->id, 'iban' => $value] ); diff --git a/app/Import/Converter/OpposingAccountName.php b/app/Import/Converter/OpposingAccountName.php index b45a28cdb5..bf872bec82 100644 --- a/app/Import/Converter/OpposingAccountName.php +++ b/app/Import/Converter/OpposingAccountName.php @@ -47,6 +47,7 @@ class OpposingAccountName extends BasicConverter implements ConverterInterface if (!is_null($account->id)) { Log::debug('Found account by ID', ['id' => $account->id]); $this->setCertainty(100); + return $account; } } @@ -55,11 +56,12 @@ class OpposingAccountName extends BasicConverter implements ConverterInterface $account = $repository->findByName($value, []); if (!is_null($account->id)) { Log::debug('Found opposing account by name', ['id' => $account->id]); - Log::warning( + Log::info( 'The match between name and account is uncertain because the type of transactions may not have been determined.', ['id' => $account->id, 'name' => $value] ); $this->setCertainty(50); + return $account; } @@ -68,6 +70,11 @@ class OpposingAccountName extends BasicConverter implements ConverterInterface 'openingBalance' => 0, ] ); + if (is_null($account->id)) { + $this->setCertainty(0); + + return new Account; + } $this->setCertainty(100); Log::debug('Created new opposing account ', ['name' => $account->name, 'id' => $account->id]); diff --git a/app/Import/ImportEntry.php b/app/Import/ImportEntry.php index 5d30621124..29a49effae 100644 --- a/app/Import/ImportEntry.php +++ b/app/Import/ImportEntry.php @@ -221,7 +221,7 @@ class ImportEntry return; } - Log::error(sprintf('Will not set %s based on certainty %d (current certainty is %d) or NULL id.', $field, $certainty, $this->certain[$field])); + Log::info(sprintf('Will not set %s based on certainty %d (current certainty is %d) or NULL id.', $field, $certainty, $this->certain[$field])); } @@ -239,7 +239,7 @@ class ImportEntry return; } - Log::error(sprintf('Will not set %s based on certainty %d (current certainty is %d).', $field, $certainty, $this->certain[$field])); + Log::info(sprintf('Will not set %s based on certainty %d (current certainty is %d).', $field, $certainty, $this->certain[$field])); } /** @@ -256,7 +256,7 @@ class ImportEntry return; } - Log::error(sprintf('Will not set %s based on certainty %d (current certainty is %d) or NULL id.', $field, $certainty, $this->certain[$field])); + Log::info(sprintf('Will not set %s based on certainty %d (current certainty is %d) or NULL id.', $field, $certainty, $this->certain[$field])); } } diff --git a/app/Import/ImportStorage.php b/app/Import/ImportStorage.php index a5c72a2ffe..0f2b45414b 100644 --- a/app/Import/ImportStorage.php +++ b/app/Import/ImportStorage.php @@ -57,9 +57,9 @@ class ImportStorage */ public function store() { - foreach ($this->entries as $entry) { - Log::debug('--- import store start ---'); - $this->storeSingle($entry); + foreach ($this->entries as $index => $entry) { + Log::debug(sprintf('--- import store start for row %d ---', $index)); + $this->storeSingle($index, $entry); } } @@ -80,19 +80,20 @@ class ImportStorage } /** + * @param int $index * @param ImportEntry $entry * * @throws FireflyException */ - private function storeSingle(ImportEntry $entry) + private function storeSingle(int $index, ImportEntry $entry) { if ($entry->valid === false) { - Log::error('Cannot import entry, because valid=false'); + Log::error(sprintf('Cannot import row %d, because valid=false', $index)); return; } - Log::debug('Going to store entry!'); + Log::debug(sprintf('Going to store row %d', $index)); $billId = is_null($entry->fields['bill']) ? null : $entry->fields['bill']->id; $journalData = [ 'user_id' => $entry->user->id, @@ -108,7 +109,12 @@ class ImportStorage ]; /** @var TransactionJournal $journal */ $journal = TransactionJournal::create($journalData); - $amount = $this->makePositive($entry->fields['amount']); + + foreach ($journal->getErrors()->all() as $err) { + Log::error($err); + } + + $amount = $this->makePositive($entry->fields['amount']); Log::debug('Created journal', ['id' => $journal->id]); @@ -154,13 +160,30 @@ class ImportStorage $one = Transaction::create($sourceData); $two = Transaction::create($destinationData); - Log::debug('Created transaction 1', ['id' => $one->id, 'account' => $one->account_id,'account_name' => $source->name]); - Log::debug('Created transaction 2', ['id' => $two->id, 'account' => $two->account_id,'account_name' => $destination->name]); + Log::debug('Created transaction 1', ['id' => $one->id, 'account' => $one->account_id, 'account_name' => $source->name]); + Log::debug('Created transaction 2', ['id' => $two->id, 'account' => $two->account_id, 'account_name' => $destination->name]); $journal->completed = 1; $journal->save(); // now attach budget and so on. + if (!is_null($entry->fields['budget']) && !is_null($entry->fields['budget']->id)) { + $journal->budgets()->save($entry->fields['budget']); + Log::debug('Attached budget', ['id' => $entry->fields['budget']->id, 'name' => $entry->fields['budget']->name]); + $journal->save(); + } + + if (!is_null($entry->fields['category']) && !is_null($entry->fields['category']->id)) { + $journal->categories()->save($entry->fields['category']); + Log::debug('Attached category', ['id' => $entry->fields['category']->id, 'name' => $entry->fields['category']->name]); + $journal->save(); + } + + if (!is_null($entry->fields['bill']) && !is_null($entry->fields['bill']->id)) { + $journal->bill()->associate($entry->fields['bill']); + Log::debug('Attached bill', ['id' => $entry->fields['bill']->id, 'name' => $entry->fields['bill']->name]); + $journal->save(); + } } diff --git a/app/Import/ImportValidator.php b/app/Import/ImportValidator.php index 527f407a8a..596252a10c 100644 --- a/app/Import/ImportValidator.php +++ b/app/Import/ImportValidator.php @@ -52,8 +52,8 @@ class ImportValidator { $newCollection = new Collection; /** @var ImportEntry $entry */ - foreach ($this->entries as $entry) { - Log::debug('--- import validator start ---'); + foreach ($this->entries as $index => $entry) { + Log::debug(sprintf('--- import validator start for row %d ---', $index)); /* * X Adds the date (today) if no date is present. * X Determins the types of accounts involved (asset, expense, revenue). @@ -64,14 +64,12 @@ class ImportValidator $entry = $this->checkAmount($entry); $entry = $this->setDate($entry); $entry = $this->setAssetAccount($entry); - Log::debug(sprintf('Opposing account is of type %s', $entry->fields['opposing-account']->accountType->type)); $entry = $this->setOpposingAccount($entry); - Log::debug(sprintf('Opposing account is of type %s', $entry->fields['opposing-account']->accountType->type)); $entry = $this->cleanDescription($entry); $entry = $this->setTransactionType($entry); $entry = $this->setTransactionCurrency($entry); - $newCollection->push($entry); + $newCollection->put($index, $entry); } return $newCollection; @@ -118,6 +116,7 @@ class ImportValidator */ private function cleanDescription(ImportEntry $entry): ImportEntry { + if (!isset($entry->fields['description'])) { Log::debug('Set empty transaction description because field was not set.'); $entry->fields['description'] = '(empty transaction description)'; @@ -130,6 +129,7 @@ class ImportValidator return $entry; } + $entry->fields['description'] = trim($entry->fields['description']); if (strlen($entry->fields['description']) == 0) { Log::debug('Set empty transaction description because field was empty.'); @@ -137,8 +137,7 @@ class ImportValidator return $entry; } - Log::debug('Transaction description is OK.'); - $entry->fields['description'] = trim($entry->fields['description']); + Log::debug('Transaction description is OK.', ['description' => $entry->fields['description']]); return $entry; } @@ -246,7 +245,7 @@ class ImportValidator */ private function setDate(ImportEntry $entry): ImportEntry { - if (is_null($entry->fields['date-transaction'])) { + if (is_null($entry->fields['date-transaction']) || $entry->certain['date-transaction'] == 0) { // empty date field? find alternative. $alternatives = ['date-book', 'date-interest', 'date-process']; foreach ($alternatives as $alternative) { @@ -263,6 +262,9 @@ class ImportValidator return $entry; } + + // confidence is zero? + Log::debug('Date-transaction is OK'); return $entry; diff --git a/app/Import/Importer/CsvImporter.php b/app/Import/Importer/CsvImporter.php index f2e630d5c7..38ec2d272c 100644 --- a/app/Import/Importer/CsvImporter.php +++ b/app/Import/Importer/CsvImporter.php @@ -51,11 +51,10 @@ class CsvImporter implements ImporterInterface Log::debug('----- import entry build start --'); Log::debug(sprintf('Now going to import row %d.', $index)); $importEntry = $this->importSingleRow($index, $row); - $collection->push($importEntry); + $collection->put($index, $importEntry); } } - Log::debug(sprintf('Collection contains %d entries', $collection->count())); - Log::debug('This call should be intercepted somehow.'); + Log::debug(sprintf('Import collection contains %d entries', $collection->count())); return $collection; } diff --git a/app/Import/Logging/CommandHandler.php b/app/Import/Logging/CommandHandler.php index d4f2021948..eeab715e22 100644 --- a/app/Import/Logging/CommandHandler.php +++ b/app/Import/Logging/CommandHandler.php @@ -13,6 +13,7 @@ namespace FireflyIII\Import\Logging; use Illuminate\Console\Command; use Monolog\Handler\AbstractProcessingHandler; +use Monolog\Logger; /** * Class CommandHandler @@ -32,7 +33,9 @@ class CommandHandler extends AbstractProcessingHandler */ public function __construct(Command $command) { + parent::__construct(); $this->command = $command; + $this->changeLevel(env('LOG_LEVEL', 'debug')); } /** @@ -44,6 +47,39 @@ class CommandHandler extends AbstractProcessingHandler */ protected function write(array $record) { - $this->command->line((string) trim($record['formatted'])); + $this->command->line((string)trim($record['formatted'])); + } + + /** + * @param string $level + */ + private function changeLevel(string $level) + { + switch ($level) { + case 'debug': + $this->setLevel(Logger::DEBUG); + break; + case 'info': + $this->setLevel(Logger::INFO); + break; + case 'notice': + $this->setLevel(Logger::NOTICE); + break; + case 'warning': + $this->setLevel(Logger::WARNING); + break; + case 'error': + $this->setLevel(Logger::ERROR); + break; + case 'critical': + $this->setLevel(Logger::CRITICAL); + break; + case 'alert': + $this->setLevel(Logger::ALERT); + break; + case 'emergency': + $this->setLevel(Logger::EMERGENCY); + break; + } } } \ No newline at end of file diff --git a/app/Models/Account.php b/app/Models/Account.php index 2c8313c0b2..c06e5f3d51 100644 --- a/app/Models/Account.php +++ b/app/Models/Account.php @@ -79,8 +79,9 @@ class Account extends Model = [ 'user_id' => 'required|exists:users,id', 'account_type_id' => 'required|exists:account_types,id', - 'name' => 'required', + 'name' => 'required|between:1,200', 'active' => 'required|boolean', + 'iban' => 'between:1,50|iban', ]; /** @var bool */ private $joinedAccountTypes; diff --git a/app/Models/Bill.php b/app/Models/Bill.php index c3bec163d7..a833cd7c3f 100644 --- a/app/Models/Bill.php +++ b/app/Models/Bill.php @@ -17,6 +17,7 @@ use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Database\Eloquent\Relations\HasMany; use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; +use Watson\Validating\ValidatingTrait; /** * FireflyIII\Models\Bill @@ -58,17 +59,20 @@ use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; * @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\Bill whereNameEncrypted($value) * @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\Bill whereMatchEncrypted($value) * @mixin \Eloquent - * @property string $deleted_at + * @property string $deleted_at * @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\Bill whereDeletedAt($value) */ class Bill extends Model { + use ValidatingTrait; + protected $dates = ['created_at', 'updated_at', 'date']; protected $fillable = ['name', 'match', 'amount_min', 'match_encrypted', 'name_encrypted', 'user_id', 'amount_max', 'date', 'repeat_freq', 'skip', 'automatch', 'active',]; protected $hidden = ['amount_min_encrypted', 'amount_max_encrypted', 'name_encrypted', 'match_encrypted']; + protected $rules = ['name' => 'required|between:1,200',]; /** * @param Bill $value diff --git a/app/Models/Budget.php b/app/Models/Budget.php index d9ca98a14b..d33cdad51f 100644 --- a/app/Models/Budget.php +++ b/app/Models/Budget.php @@ -17,6 +17,7 @@ use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Database\Eloquent\SoftDeletes; use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; +use Watson\Validating\ValidatingTrait; /** * FireflyIII\Models\Budget @@ -51,11 +52,12 @@ use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; class Budget extends Model { - use SoftDeletes; + use SoftDeletes, ValidatingTrait; protected $dates = ['created_at', 'updated_at', 'deleted_at', 'startdate', 'enddate']; protected $fillable = ['user_id', 'name', 'active']; protected $hidden = ['encrypted']; + protected $rules = ['name' => 'required|between:1,200',]; /** * @param array $fields diff --git a/app/Models/Category.php b/app/Models/Category.php index db3a8172f4..d88d627ecb 100644 --- a/app/Models/Category.php +++ b/app/Models/Category.php @@ -17,6 +17,7 @@ use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Database\Eloquent\SoftDeletes; use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; +use Watson\Validating\ValidatingTrait; /** * FireflyIII\Models\Category @@ -46,11 +47,12 @@ use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; */ class Category extends Model { - use SoftDeletes; + use SoftDeletes, ValidatingTrait; protected $dates = ['created_at', 'updated_at', 'deleted_at']; protected $fillable = ['user_id', 'name']; protected $hidden = ['encrypted']; + protected $rules = ['name' => 'required|between:1,200',]; /** * @param array $fields diff --git a/app/Models/Tag.php b/app/Models/Tag.php index bfa9e17dee..2c5ddab13c 100644 --- a/app/Models/Tag.php +++ b/app/Models/Tag.php @@ -15,6 +15,7 @@ use Auth; use Crypt; use FireflyIII\Support\Models\TagSupport; use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; +use Watson\Validating\ValidatingTrait; /** * FireflyIII\Models\Tag @@ -52,6 +53,9 @@ class Tag extends TagSupport { protected $dates = ['created_at', 'updated_at', 'date']; protected $fillable = ['user_id', 'tag', 'date', 'description', 'longitude', 'latitude', 'zoomLevel', 'tagMode']; + protected $rules = ['tag' => 'required|between:1,200',]; + + use ValidatingTrait; /** * @param array $fields diff --git a/app/Models/TransactionCurrency.php b/app/Models/TransactionCurrency.php index 69d33955b6..84208e2a22 100644 --- a/app/Models/TransactionCurrency.php +++ b/app/Models/TransactionCurrency.php @@ -15,6 +15,7 @@ use Auth; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\SoftDeletes; use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; +use Watson\Validating\ValidatingTrait; /** * FireflyIII\Models\TransactionCurrency @@ -38,19 +39,12 @@ use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; */ class TransactionCurrency extends Model { - use SoftDeletes; + use SoftDeletes, ValidatingTrait; - protected $fillable = ['name', 'code', 'symbol']; protected $dates = ['created_at', 'updated_at', 'deleted_at']; - - /** - * @return \Illuminate\Database\Eloquent\Relations\HasMany - */ - public function transactionJournals() - { - return $this->hasMany('FireflyIII\Models\TransactionJournal'); - } + protected $fillable = ['name', 'code', 'symbol']; + protected $rules = ['name' => 'required|between:1,200', 'code' => 'required|between:3,3', 'symbol' => 'required|between:1,12']; /** * @param TransactionCurrency $currency @@ -64,4 +58,12 @@ class TransactionCurrency extends Model } throw new NotFoundHttpException; } + + /** + * @return \Illuminate\Database\Eloquent\Relations\HasMany + */ + public function transactionJournals() + { + return $this->hasMany('FireflyIII\Models\TransactionJournal'); + } } diff --git a/app/Repositories/Category/CategoryRepository.php b/app/Repositories/Category/CategoryRepository.php index e0a662b355..380578e174 100644 --- a/app/Repositories/Category/CategoryRepository.php +++ b/app/Repositories/Category/CategoryRepository.php @@ -444,6 +444,12 @@ class CategoryRepository implements CategoryRepositoryInterface */ public function store(array $data): Category { + // TODO use validation, not this. + if (strlen($data['name']) > 200 || strlen($data['name']) === 0) { + + } + + $newCategory = Category::firstOrCreateEncrypted( [ 'user_id' => $data['user'], diff --git a/app/Support/Migration/TestData.php b/app/Support/Migration/TestData.php index d3e59f9cdd..5c87f63003 100644 --- a/app/Support/Migration/TestData.php +++ b/app/Support/Migration/TestData.php @@ -72,9 +72,9 @@ class TestData 'updated_at' => $this->time, 'user_id' => $account['user_id'], 'account_type_id' => $account['account_type_id'], - 'name' => Crypt::encrypt($account['name']), + 'name' => $account['name'], 'active' => 1, - 'encrypted' => 1, + 'encrypted' => 0, 'virtual_balance' => 0, 'iban' => isset($account['iban']) ? Crypt::encrypt($account['iban']) : null, ]; @@ -244,6 +244,25 @@ class TestData DB::table('categories')->insert($insert); } + /** + * + */ + private function createCurrencies() + { + $insert = []; + foreach ($this->data['currencies'] as $job) { + $insert[] = [ + 'created_at' => $this->time, + 'updated_at' => $this->time, + 'deleted_at' => null, + 'code' => $job['code'], + 'name' => $job['name'], + 'symbol' => $job['symbol'], + ]; + } + DB::table('transaction_currencies')->insert($insert); + } + /** * */ @@ -829,6 +848,7 @@ class TestData $this->createMultiDeposits(); $this->createMultiTransfers(); $this->createImportJobs(); + $this->createCurrencies(); } } diff --git a/database/seeds/TestDataSeeder.php b/database/seeds/TestDataSeeder.php index d4faa0e4f3..a0ccd5eee9 100644 --- a/database/seeds/TestDataSeeder.php +++ b/database/seeds/TestDataSeeder.php @@ -38,10 +38,15 @@ class TestDataSeeder extends Seeder if ($disk->exists($fileName)) { Log::debug('Now seeding ' . $fileName); $file = json_decode($disk->get($fileName), true); - // run the file: - TestData::run($file); + if (is_array($file)) { + // run the file: + TestData::run($file); + return; + } + Log::error('No valid data found (' . $fileName . ') for environment ' . $env); return; + } Log::info('No seed file (' . $fileName . ') for environment ' . $env); } diff --git a/storage/database/seed.import-test.json b/storage/database/seed.import-test.json index 47cde9a977..bbdd6fe38c 100644 --- a/storage/database/seed.import-test.json +++ b/storage/database/seed.import-test.json @@ -11,20 +11,78 @@ "role": 1 } ], - "accounts": [], - "account-meta": [], - "bills": [], - "budgets": [], + "accounts": [ + { + "user_id": 1, + "account_type_id": 3, + "name": "ExistingAssetAccount", + "iban": "NL62EXFK3945306779" + }, + { + "user_id": 1, + "account_type_id": 4, + "name": "ExistingOpposingAccount", + "iban": "NL79BGWN6303364632" + } + ], + "account-meta": [ + { + "account_id": 1, + "name": "accountNumber", + "data": "\"3945306779\"" + }, + { + "account_id": 2, + "name": "accountNumber", + "data": "\"6303364632\"" + } + ], + "bills": [ + { + "name": "ExistingBill", + "match": "ExistingBill", + "amount_min": 100, + "amount_max": 200, + "user_id": 1, + "date": "2015-01-01", + "active": 1, + "automatch": 1, + "repeat_freq": "monthly", + "skip": 0 + } + ], + "budgets": [ + { + "name": "ExistingBudget", + "user_id": 1 + } + ], "budget-limits": [], "monthly-limits": [], - "categories": [], + "categories": [ + { + "name": "ExistingCategory", + "user_id": 1 + } + ], "piggy-banks": [], "piggy-events": [], "rule-groups": [], "rules": [], "rule-triggers": [], "rule-actions": [], - "tags": [], + "tags": [ + { + "user_id": 1, + "tag": "ExistingTag", + "tagMode": "nothing" + }, + { + "user_id": 1, + "tag": "AnotherExistingTag", + "tagMode": "nothing" + } + ], "monthly-deposits": [], "monthly-transfers": [], "monthly-withdrawals": [], @@ -43,18 +101,67 @@ "date-format": "Ymd", "delimiter": ",", "import-account": 0, - "specifics": [], - "column-count": 7, + "specifics": { + "RabobankDescription": 1, + "AbnAmroDescription": 1 + }, + "column-count": 30, "column-roles": [ - "account-name", - "opposing-name", "amount", - "date-transaction", - "category-name", + "account-id", + "account-iban", + "account-name", + "opposing-number", + "bill-id", + "bill-name", + "budget-id", "budget-name", - "description" + "category-id", + "category-name", + "currency-code", + "currency-id", + "currency-symbol", + "currency-name", + "date-transaction", + "description", + "_ignore", + "ing-debet-credit", + "opposing-iban", + "opposing-id", + "opposing-name", + "opposing-number", + "rabo-debet-credit", + "tags-comma", + "tags-space", + "date-interest", + "date-book", + "date-process", + "external-id" ], "column-do-mapping": [ + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, false, false, false, @@ -64,9 +171,16 @@ false ], "column-roles-complete": false, - "column-mapping-config": [], + "column-mapping-config": {}, "column-mapping-complete": false } } + ], + "currencies": [ + { + "name": "ExistingCurrency", + "symbol": "#", + "code": "EXI" + } ] } \ No newline at end of file diff --git a/storage/database/seed.local.json b/storage/database/seed.local.json index 463b1119ff..bd1d17d784 100644 --- a/storage/database/seed.local.json +++ b/storage/database/seed.local.json @@ -1007,5 +1007,6 @@ ] } ], - "import-jobs": [] + "import-jobs": [], + "currencies": [] } \ No newline at end of file diff --git a/storage/database/seed.split.json b/storage/database/seed.split.json index 2a60692705..38fa070988 100644 --- a/storage/database/seed.split.json +++ b/storage/database/seed.split.json @@ -298,5 +298,6 @@ ] } ], - "import-jobs": [] + "import-jobs": [], + "currencies": [] } \ No newline at end of file diff --git a/storage/database/seed.testing.json b/storage/database/seed.testing.json index 5dbaaaf5e9..847832ee07 100644 --- a/storage/database/seed.testing.json +++ b/storage/database/seed.testing.json @@ -1007,5 +1007,6 @@ ] } ], - "import-jobs": [] + "import-jobs": [], + "currencies": [] } \ No newline at end of file