Extend rule set for import.

This commit is contained in:
James Cole
2016-08-11 18:44:11 +02:00
parent 186b704509
commit 0aaf9a6fda
32 changed files with 349 additions and 72 deletions

1
.gitignore vendored
View File

@@ -5,3 +5,4 @@ _development
.env.local .env.local
result.html result.html
test-import.sh test-import.sh
test-import-report.txt

View File

@@ -19,6 +19,7 @@ use FireflyIII\Import\Logging\CommandHandler;
use FireflyIII\Models\ImportJob; use FireflyIII\Models\ImportJob;
use Illuminate\Console\Command; use Illuminate\Console\Command;
use Log; use Log;
use Monolog\Handler\StreamHandler;
/** /**
* Class Import * Class Import
@@ -80,6 +81,7 @@ class Import extends Command
// intercept logging by importer. // intercept logging by importer.
$monolog = Log::getMonolog(); $monolog = Log::getMonolog();
$handler = new CommandHandler($this); $handler = new CommandHandler($this);
$monolog->pushHandler($handler); $monolog->pushHandler($handler);
// create import entries // create import entries

View File

@@ -158,10 +158,12 @@ class AccountCrud implements AccountCrudInterface
/** @var Account $account */ /** @var Account $account */
foreach ($accounts as $account) { foreach ($accounts as $account) {
if ($account->name === $name) { 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; return new Account;
} }
@@ -233,7 +235,7 @@ class AccountCrud implements AccountCrudInterface
public function store(array $data): Account public function store(array $data): Account
{ {
$newAccount = $this->storeAccount($data); $newAccount = $this->storeAccount($data);
if (!is_null($newAccount)) { if (!is_null($newAccount->id)) {
$this->storeMetadata($newAccount, $data); $this->storeMetadata($newAccount, $data);
} }
@@ -327,8 +329,8 @@ class AccountCrud implements AccountCrudInterface
]; ];
$existingAccount = Account::firstOrNullEncrypted($searchData); $existingAccount = Account::firstOrNullEncrypted($searchData);
if (!$existingAccount) { if (!$existingAccount) {
Log::error('Account create error: ' . $newAccount->getErrors()->toJson()); Log::error('Account create error', $newAccount->getErrors()->toArray());
abort(500); return new Account;
} }
$newAccount = $existingAccount; $newAccount = $existingAccount;

View File

@@ -66,9 +66,17 @@ class AssetAccountIban extends BasicConverter implements ConverterInterface
$account = $repository->store( $account = $repository->store(
['name' => 'Account with IBAN ' . $value, 'iban' => $value, 'user' => $this->user->id, 'accountType' => 'asset', 'virtualBalance' => 0, ['name' => 'Asset account with IBAN ' . $value, 'iban' => $value, 'user' => $this->user->id, 'accountType' => 'asset', 'virtualBalance' => 0,
'active' => true] '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); $this->setCertainty(100);
return $account; return $account;

View File

@@ -68,6 +68,14 @@ class AssetAccountName extends BasicConverter implements ConverterInterface
['name' => $value, 'iban' => null, 'openingBalance' => 0, 'user' => $this->user->id, 'accountType' => 'asset', 'virtualBalance' => 0, ['name' => $value, 'iban' => null, 'openingBalance' => 0, 'user' => $this->user->id, 'accountType' => 'asset', 'virtualBalance' => 0,
'active' => true] '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); $this->setCertainty(100);
Log::debug('Created new asset account ', ['name' => $account->name, 'id' => $account->id]); Log::debug('Created new asset account ', ['name' => $account->name, 'id' => $account->id]);

View File

@@ -32,7 +32,7 @@ class AssetAccountNumber extends BasicConverter implements ConverterInterface
public function convert($value) public function convert($value)
{ {
$value = trim($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) { if (strlen($value) === 0) {
return new Account; return new Account;
@@ -77,6 +77,14 @@ class AssetAccountNumber extends BasicConverter implements ConverterInterface
'accountType' => 'asset', 'accountType' => 'asset',
'virtualBalance' => 0, 'accountNumber' => $value, 'active' => true] '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); $this->setCertainty(100);
return $account; return $account;

View File

@@ -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? // 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); $this->setCertainty(0);

View File

@@ -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); $this->setCertainty(100);
return $bill; return $bill;

View File

@@ -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? // should not really happen. If the ID does not match FF, what is FF supposed to do?
$this->setCertainty(0); $this->setCertainty(0);
Log::info(sprintf('Could not find budget with ID %d. Will return NULL', $value));
return new Budget; return new Budget;
} }

View File

@@ -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? // should not really happen. If the ID does not match FF, what is FF supposed to do?
$this->setCertainty(0); $this->setCertainty(0);
Log::info(sprintf('Could not find category with ID %d. Will return NULL', $value));
return new Category; return new Category;
} }

View File

@@ -61,6 +61,9 @@ class CurrencyId extends BasicConverter implements ConverterInterface
} }
$this->setCertainty(0); $this->setCertainty(0);
// should not really happen. If the ID does not match FF, what is FF supposed to do? // 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; return new TransactionCurrency;
} }

View File

@@ -37,9 +37,10 @@ class Date extends BasicConverter implements ConverterInterface
try { try {
$date = Carbon::createFromFormat($this->config['date-format'], $value); $date = Carbon::createFromFormat($this->config['date-format'], $value);
} catch (InvalidArgumentException $e) { } catch (InvalidArgumentException $e) {
Log::critical($e->getMessage()); Log::notice($e->getMessage());
Log::critical('Cannot convert this string using the given format.', ['value' => $value, 'format' => $this->config['date-format']]); Log::notice('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'])); $this->setCertainty(0);
return new Carbon;
} }
Log::debug('Converted date', ['converted' => $date->toAtomString()]); Log::debug('Converted date', ['converted' => $date->toAtomString()]);
$this->setCertainty(100); $this->setCertainty(100);

View File

@@ -56,7 +56,7 @@ class OpposingAccountIban extends BasicConverter implements ConverterInterface
$account = $repository->findByIban($value, []); $account = $repository->findByIban($value, []);
if (!is_null($account->id)) { if (!is_null($account->id)) {
Log::debug('Found account by IBAN', ['id' => $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.', 'The match between IBAN and account is uncertain because the type of transactions may not have been determined.',
['id' => $account->id, 'iban' => $value] ['id' => $account->id, 'iban' => $value]
); );

View File

@@ -47,6 +47,7 @@ class OpposingAccountName extends BasicConverter implements ConverterInterface
if (!is_null($account->id)) { if (!is_null($account->id)) {
Log::debug('Found account by ID', ['id' => $account->id]); Log::debug('Found account by ID', ['id' => $account->id]);
$this->setCertainty(100); $this->setCertainty(100);
return $account; return $account;
} }
} }
@@ -55,11 +56,12 @@ class OpposingAccountName extends BasicConverter implements ConverterInterface
$account = $repository->findByName($value, []); $account = $repository->findByName($value, []);
if (!is_null($account->id)) { if (!is_null($account->id)) {
Log::debug('Found opposing account by name', ['id' => $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.', 'The match between name and account is uncertain because the type of transactions may not have been determined.',
['id' => $account->id, 'name' => $value] ['id' => $account->id, 'name' => $value]
); );
$this->setCertainty(50); $this->setCertainty(50);
return $account; return $account;
} }
@@ -68,6 +70,11 @@ class OpposingAccountName extends BasicConverter implements ConverterInterface
'openingBalance' => 0, 'openingBalance' => 0,
] ]
); );
if (is_null($account->id)) {
$this->setCertainty(0);
return new Account;
}
$this->setCertainty(100); $this->setCertainty(100);
Log::debug('Created new opposing account ', ['name' => $account->name, 'id' => $account->id]); Log::debug('Created new opposing account ', ['name' => $account->name, 'id' => $account->id]);

View File

@@ -221,7 +221,7 @@ class ImportEntry
return; 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; 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; 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]));
} }
} }

View File

@@ -57,9 +57,9 @@ class ImportStorage
*/ */
public function store() public function store()
{ {
foreach ($this->entries as $entry) { foreach ($this->entries as $index => $entry) {
Log::debug('--- import store start ---'); Log::debug(sprintf('--- import store start for row %d ---', $index));
$this->storeSingle($entry); $this->storeSingle($index, $entry);
} }
} }
@@ -80,19 +80,20 @@ class ImportStorage
} }
/** /**
* @param int $index
* @param ImportEntry $entry * @param ImportEntry $entry
* *
* @throws FireflyException * @throws FireflyException
*/ */
private function storeSingle(ImportEntry $entry) private function storeSingle(int $index, ImportEntry $entry)
{ {
if ($entry->valid === false) { if ($entry->valid === false) {
Log::error('Cannot import entry, because valid=false'); Log::error(sprintf('Cannot import row %d, because valid=false', $index));
return; 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; $billId = is_null($entry->fields['bill']) ? null : $entry->fields['bill']->id;
$journalData = [ $journalData = [
'user_id' => $entry->user->id, 'user_id' => $entry->user->id,
@@ -108,7 +109,12 @@ class ImportStorage
]; ];
/** @var TransactionJournal $journal */ /** @var TransactionJournal $journal */
$journal = TransactionJournal::create($journalData); $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]); Log::debug('Created journal', ['id' => $journal->id]);
@@ -154,13 +160,30 @@ class ImportStorage
$one = Transaction::create($sourceData); $one = Transaction::create($sourceData);
$two = Transaction::create($destinationData); $two = Transaction::create($destinationData);
Log::debug('Created transaction 1', ['id' => $one->id, 'account' => $one->account_id,'account_name' => $source->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]); Log::debug('Created transaction 2', ['id' => $two->id, 'account' => $two->account_id, 'account_name' => $destination->name]);
$journal->completed = 1; $journal->completed = 1;
$journal->save(); $journal->save();
// now attach budget and so on. // 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();
}
} }

View File

@@ -52,8 +52,8 @@ class ImportValidator
{ {
$newCollection = new Collection; $newCollection = new Collection;
/** @var ImportEntry $entry */ /** @var ImportEntry $entry */
foreach ($this->entries as $entry) { foreach ($this->entries as $index => $entry) {
Log::debug('--- import validator start ---'); Log::debug(sprintf('--- import validator start for row %d ---', $index));
/* /*
* X Adds the date (today) if no date is present. * X Adds the date (today) if no date is present.
* X Determins the types of accounts involved (asset, expense, revenue). * X Determins the types of accounts involved (asset, expense, revenue).
@@ -64,14 +64,12 @@ class ImportValidator
$entry = $this->checkAmount($entry); $entry = $this->checkAmount($entry);
$entry = $this->setDate($entry); $entry = $this->setDate($entry);
$entry = $this->setAssetAccount($entry); $entry = $this->setAssetAccount($entry);
Log::debug(sprintf('Opposing account is of type %s', $entry->fields['opposing-account']->accountType->type));
$entry = $this->setOpposingAccount($entry); $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->cleanDescription($entry);
$entry = $this->setTransactionType($entry); $entry = $this->setTransactionType($entry);
$entry = $this->setTransactionCurrency($entry); $entry = $this->setTransactionCurrency($entry);
$newCollection->push($entry); $newCollection->put($index, $entry);
} }
return $newCollection; return $newCollection;
@@ -118,6 +116,7 @@ class ImportValidator
*/ */
private function cleanDescription(ImportEntry $entry): ImportEntry private function cleanDescription(ImportEntry $entry): ImportEntry
{ {
if (!isset($entry->fields['description'])) { if (!isset($entry->fields['description'])) {
Log::debug('Set empty transaction description because field was not set.'); Log::debug('Set empty transaction description because field was not set.');
$entry->fields['description'] = '(empty transaction description)'; $entry->fields['description'] = '(empty transaction description)';
@@ -130,6 +129,7 @@ class ImportValidator
return $entry; return $entry;
} }
$entry->fields['description'] = trim($entry->fields['description']);
if (strlen($entry->fields['description']) == 0) { if (strlen($entry->fields['description']) == 0) {
Log::debug('Set empty transaction description because field was empty.'); Log::debug('Set empty transaction description because field was empty.');
@@ -137,8 +137,7 @@ class ImportValidator
return $entry; return $entry;
} }
Log::debug('Transaction description is OK.'); Log::debug('Transaction description is OK.', ['description' => $entry->fields['description']]);
$entry->fields['description'] = trim($entry->fields['description']);
return $entry; return $entry;
} }
@@ -246,7 +245,7 @@ class ImportValidator
*/ */
private function setDate(ImportEntry $entry): ImportEntry 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. // empty date field? find alternative.
$alternatives = ['date-book', 'date-interest', 'date-process']; $alternatives = ['date-book', 'date-interest', 'date-process'];
foreach ($alternatives as $alternative) { foreach ($alternatives as $alternative) {
@@ -263,6 +262,9 @@ class ImportValidator
return $entry; return $entry;
} }
// confidence is zero?
Log::debug('Date-transaction is OK'); Log::debug('Date-transaction is OK');
return $entry; return $entry;

View File

@@ -51,11 +51,10 @@ class CsvImporter implements ImporterInterface
Log::debug('----- import entry build start --'); Log::debug('----- import entry build start --');
Log::debug(sprintf('Now going to import row %d.', $index)); Log::debug(sprintf('Now going to import row %d.', $index));
$importEntry = $this->importSingleRow($index, $row); $importEntry = $this->importSingleRow($index, $row);
$collection->push($importEntry); $collection->put($index, $importEntry);
} }
} }
Log::debug(sprintf('Collection contains %d entries', $collection->count())); Log::debug(sprintf('Import collection contains %d entries', $collection->count()));
Log::debug('This call should be intercepted somehow.');
return $collection; return $collection;
} }

View File

@@ -13,6 +13,7 @@ namespace FireflyIII\Import\Logging;
use Illuminate\Console\Command; use Illuminate\Console\Command;
use Monolog\Handler\AbstractProcessingHandler; use Monolog\Handler\AbstractProcessingHandler;
use Monolog\Logger;
/** /**
* Class CommandHandler * Class CommandHandler
@@ -32,7 +33,9 @@ class CommandHandler extends AbstractProcessingHandler
*/ */
public function __construct(Command $command) public function __construct(Command $command)
{ {
parent::__construct();
$this->command = $command; $this->command = $command;
$this->changeLevel(env('LOG_LEVEL', 'debug'));
} }
/** /**
@@ -44,6 +47,39 @@ class CommandHandler extends AbstractProcessingHandler
*/ */
protected function write(array $record) 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;
}
} }
} }

View File

@@ -79,8 +79,9 @@ class Account extends Model
= [ = [
'user_id' => 'required|exists:users,id', 'user_id' => 'required|exists:users,id',
'account_type_id' => 'required|exists:account_types,id', 'account_type_id' => 'required|exists:account_types,id',
'name' => 'required', 'name' => 'required|between:1,200',
'active' => 'required|boolean', 'active' => 'required|boolean',
'iban' => 'between:1,50|iban',
]; ];
/** @var bool */ /** @var bool */
private $joinedAccountTypes; private $joinedAccountTypes;

View File

@@ -17,6 +17,7 @@ use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\HasMany; use Illuminate\Database\Eloquent\Relations\HasMany;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Watson\Validating\ValidatingTrait;
/** /**
* FireflyIII\Models\Bill * 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 whereNameEncrypted($value)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\Bill whereMatchEncrypted($value) * @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\Bill whereMatchEncrypted($value)
* @mixin \Eloquent * @mixin \Eloquent
* @property string $deleted_at * @property string $deleted_at
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\Bill whereDeletedAt($value) * @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\Bill whereDeletedAt($value)
*/ */
class Bill extends Model class Bill extends Model
{ {
use ValidatingTrait;
protected $dates = ['created_at', 'updated_at', 'date']; protected $dates = ['created_at', 'updated_at', 'date'];
protected $fillable protected $fillable
= ['name', 'match', 'amount_min', 'match_encrypted', 'name_encrypted', 'user_id', 'amount_max', 'date', 'repeat_freq', 'skip', = ['name', 'match', 'amount_min', 'match_encrypted', 'name_encrypted', 'user_id', 'amount_max', 'date', 'repeat_freq', 'skip',
'automatch', 'active',]; 'automatch', 'active',];
protected $hidden = ['amount_min_encrypted', 'amount_max_encrypted', 'name_encrypted', 'match_encrypted']; protected $hidden = ['amount_min_encrypted', 'amount_max_encrypted', 'name_encrypted', 'match_encrypted'];
protected $rules = ['name' => 'required|between:1,200',];
/** /**
* @param Bill $value * @param Bill $value

View File

@@ -17,6 +17,7 @@ use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\SoftDeletes; use Illuminate\Database\Eloquent\SoftDeletes;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Watson\Validating\ValidatingTrait;
/** /**
* FireflyIII\Models\Budget * FireflyIII\Models\Budget
@@ -51,11 +52,12 @@ use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
class Budget extends Model class Budget extends Model
{ {
use SoftDeletes; use SoftDeletes, ValidatingTrait;
protected $dates = ['created_at', 'updated_at', 'deleted_at', 'startdate', 'enddate']; protected $dates = ['created_at', 'updated_at', 'deleted_at', 'startdate', 'enddate'];
protected $fillable = ['user_id', 'name', 'active']; protected $fillable = ['user_id', 'name', 'active'];
protected $hidden = ['encrypted']; protected $hidden = ['encrypted'];
protected $rules = ['name' => 'required|between:1,200',];
/** /**
* @param array $fields * @param array $fields

View File

@@ -17,6 +17,7 @@ use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\SoftDeletes; use Illuminate\Database\Eloquent\SoftDeletes;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Watson\Validating\ValidatingTrait;
/** /**
* FireflyIII\Models\Category * FireflyIII\Models\Category
@@ -46,11 +47,12 @@ use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
*/ */
class Category extends Model class Category extends Model
{ {
use SoftDeletes; use SoftDeletes, ValidatingTrait;
protected $dates = ['created_at', 'updated_at', 'deleted_at']; protected $dates = ['created_at', 'updated_at', 'deleted_at'];
protected $fillable = ['user_id', 'name']; protected $fillable = ['user_id', 'name'];
protected $hidden = ['encrypted']; protected $hidden = ['encrypted'];
protected $rules = ['name' => 'required|between:1,200',];
/** /**
* @param array $fields * @param array $fields

View File

@@ -15,6 +15,7 @@ use Auth;
use Crypt; use Crypt;
use FireflyIII\Support\Models\TagSupport; use FireflyIII\Support\Models\TagSupport;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Watson\Validating\ValidatingTrait;
/** /**
* FireflyIII\Models\Tag * FireflyIII\Models\Tag
@@ -52,6 +53,9 @@ class Tag extends TagSupport
{ {
protected $dates = ['created_at', 'updated_at', 'date']; protected $dates = ['created_at', 'updated_at', 'date'];
protected $fillable = ['user_id', 'tag', 'date', 'description', 'longitude', 'latitude', 'zoomLevel', 'tagMode']; protected $fillable = ['user_id', 'tag', 'date', 'description', 'longitude', 'latitude', 'zoomLevel', 'tagMode'];
protected $rules = ['tag' => 'required|between:1,200',];
use ValidatingTrait;
/** /**
* @param array $fields * @param array $fields

View File

@@ -15,6 +15,7 @@ use Auth;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes; use Illuminate\Database\Eloquent\SoftDeletes;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Watson\Validating\ValidatingTrait;
/** /**
* FireflyIII\Models\TransactionCurrency * FireflyIII\Models\TransactionCurrency
@@ -38,19 +39,12 @@ use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
*/ */
class TransactionCurrency extends Model class TransactionCurrency extends Model
{ {
use SoftDeletes; use SoftDeletes, ValidatingTrait;
protected $fillable = ['name', 'code', 'symbol'];
protected $dates = ['created_at', 'updated_at', 'deleted_at']; protected $dates = ['created_at', 'updated_at', 'deleted_at'];
protected $fillable = ['name', 'code', 'symbol'];
/** protected $rules = ['name' => 'required|between:1,200', 'code' => 'required|between:3,3', 'symbol' => 'required|between:1,12'];
* @return \Illuminate\Database\Eloquent\Relations\HasMany
*/
public function transactionJournals()
{
return $this->hasMany('FireflyIII\Models\TransactionJournal');
}
/** /**
* @param TransactionCurrency $currency * @param TransactionCurrency $currency
@@ -64,4 +58,12 @@ class TransactionCurrency extends Model
} }
throw new NotFoundHttpException; throw new NotFoundHttpException;
} }
/**
* @return \Illuminate\Database\Eloquent\Relations\HasMany
*/
public function transactionJournals()
{
return $this->hasMany('FireflyIII\Models\TransactionJournal');
}
} }

View File

@@ -444,6 +444,12 @@ class CategoryRepository implements CategoryRepositoryInterface
*/ */
public function store(array $data): Category public function store(array $data): Category
{ {
// TODO use validation, not this.
if (strlen($data['name']) > 200 || strlen($data['name']) === 0) {
}
$newCategory = Category::firstOrCreateEncrypted( $newCategory = Category::firstOrCreateEncrypted(
[ [
'user_id' => $data['user'], 'user_id' => $data['user'],

View File

@@ -72,9 +72,9 @@ class TestData
'updated_at' => $this->time, 'updated_at' => $this->time,
'user_id' => $account['user_id'], 'user_id' => $account['user_id'],
'account_type_id' => $account['account_type_id'], 'account_type_id' => $account['account_type_id'],
'name' => Crypt::encrypt($account['name']), 'name' => $account['name'],
'active' => 1, 'active' => 1,
'encrypted' => 1, 'encrypted' => 0,
'virtual_balance' => 0, 'virtual_balance' => 0,
'iban' => isset($account['iban']) ? Crypt::encrypt($account['iban']) : null, 'iban' => isset($account['iban']) ? Crypt::encrypt($account['iban']) : null,
]; ];
@@ -244,6 +244,25 @@ class TestData
DB::table('categories')->insert($insert); 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->createMultiDeposits();
$this->createMultiTransfers(); $this->createMultiTransfers();
$this->createImportJobs(); $this->createImportJobs();
$this->createCurrencies();
} }
} }

View File

@@ -38,10 +38,15 @@ class TestDataSeeder extends Seeder
if ($disk->exists($fileName)) { if ($disk->exists($fileName)) {
Log::debug('Now seeding ' . $fileName); Log::debug('Now seeding ' . $fileName);
$file = json_decode($disk->get($fileName), true); $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; return;
} }
Log::info('No seed file (' . $fileName . ') for environment ' . $env); Log::info('No seed file (' . $fileName . ') for environment ' . $env);
} }

View File

@@ -11,20 +11,78 @@
"role": 1 "role": 1
} }
], ],
"accounts": [], "accounts": [
"account-meta": [], {
"bills": [], "user_id": 1,
"budgets": [], "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": [], "budget-limits": [],
"monthly-limits": [], "monthly-limits": [],
"categories": [], "categories": [
{
"name": "ExistingCategory",
"user_id": 1
}
],
"piggy-banks": [], "piggy-banks": [],
"piggy-events": [], "piggy-events": [],
"rule-groups": [], "rule-groups": [],
"rules": [], "rules": [],
"rule-triggers": [], "rule-triggers": [],
"rule-actions": [], "rule-actions": [],
"tags": [], "tags": [
{
"user_id": 1,
"tag": "ExistingTag",
"tagMode": "nothing"
},
{
"user_id": 1,
"tag": "AnotherExistingTag",
"tagMode": "nothing"
}
],
"monthly-deposits": [], "monthly-deposits": [],
"monthly-transfers": [], "monthly-transfers": [],
"monthly-withdrawals": [], "monthly-withdrawals": [],
@@ -43,18 +101,67 @@
"date-format": "Ymd", "date-format": "Ymd",
"delimiter": ",", "delimiter": ",",
"import-account": 0, "import-account": 0,
"specifics": [], "specifics": {
"column-count": 7, "RabobankDescription": 1,
"AbnAmroDescription": 1
},
"column-count": 30,
"column-roles": [ "column-roles": [
"account-name",
"opposing-name",
"amount", "amount",
"date-transaction", "account-id",
"category-name", "account-iban",
"account-name",
"opposing-number",
"bill-id",
"bill-name",
"budget-id",
"budget-name", "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": [ "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, false,
false, false,
@@ -64,9 +171,16 @@
false false
], ],
"column-roles-complete": false, "column-roles-complete": false,
"column-mapping-config": [], "column-mapping-config": {},
"column-mapping-complete": false "column-mapping-complete": false
} }
} }
],
"currencies": [
{
"name": "ExistingCurrency",
"symbol": "#",
"code": "EXI"
}
] ]
} }

View File

@@ -1007,5 +1007,6 @@
] ]
} }
], ],
"import-jobs": [] "import-jobs": [],
"currencies": []
} }

View File

@@ -298,5 +298,6 @@
] ]
} }
], ],
"import-jobs": [] "import-jobs": [],
"currencies": []
} }

View File

@@ -1007,5 +1007,6 @@
] ]
} }
], ],
"import-jobs": [] "import-jobs": [],
"currencies": []
} }