diff --git a/app/Import/Importer/CsvImporter.php b/app/Import/Importer/CsvImporter.php index 7a592442a4..3b1f2fc704 100644 --- a/app/Import/Importer/CsvImporter.php +++ b/app/Import/Importer/CsvImporter.php @@ -14,6 +14,7 @@ namespace FireflyIII\Import\Importer; use ExpandedForm; use FireflyIII\Crud\Account\AccountCrud; +use FireflyIII\Import\Mapper\MapperInterface; use FireflyIII\Models\AccountType; use FireflyIII\Models\ImportJob; use Illuminate\Http\Request; @@ -111,54 +112,18 @@ class CsvImporter implements ImporterInterface */ public function getDataForSettings(): array { - $config = $this->job->configuration; - $data = [ - 'columns' => [], - 'columnCount' => 0, - ]; if ($this->doColumnRoles()) { - - // show user column role configuration. - $content = $this->job->uploadFileContents(); - - // create CSV reader. - $reader = Reader::createFromString($content); - $start = $config['has-headers'] ? 1 : 0; - $end = $start + self::EXAMPLE_ROWS; // first X rows - - // collect example data in $data['columns'] - while ($start < $end) { - $row = $reader->fetchOne($start); - foreach ($row as $index => $value) { - $value = trim($value); - if (strlen($value) > 0) { - $data['columns'][$index][] = $value; - } - } - $start++; - $data['columnCount'] = count($row); - } - - // make unique example data - foreach ($data['columns'] as $index => $values) { - $data['columns'][$index] = array_unique($values); - } - - $data['set_roles'] = []; - // collect possible column roles: - $data['available_roles'] = []; - foreach (array_keys(config('csv.import_roles')) as $role) { - $data['available_roles'][$role] = trans('csv.column_' . $role); - } - - $config['column-count'] = $data['columnCount']; - $this->job->configuration = $config; - $this->job->save(); + $data = $this->getDataForColumnRoles(); + + return $data; + } + + if ($this->doColumnMapping()) { + $data = $this->getDataForColumnMapping(); return $data; } - echo 'no settings to do.'; exit; @@ -176,6 +141,11 @@ class CsvImporter implements ImporterInterface if ($this->doColumnRoles()) { return 'import.csv.roles'; } + + if ($this->doColumnMapping()) { + return 'import.csv.map'; + } + echo 'no view for settings'; exit; } @@ -269,6 +239,14 @@ class CsvImporter implements ImporterInterface } } + /** + * @return bool + */ + private function doColumnMapping(): bool + { + return $this->job->configuration['column-mapping-complete'] === false; + } + /** * @return bool */ @@ -276,4 +254,94 @@ class CsvImporter implements ImporterInterface { return $this->job->configuration['column-roles-complete'] === false; } + + /** + * @return array + */ + private function getDataForColumnMapping(): array + { + $config = $this->job->configuration; + $data = []; + + foreach ($config['column-do-mapping'] as $index => $mustBeMapped) { + if ($mustBeMapped) { + $column = $config['column-roles'][$index] ?? '_ignore'; + $canBeMapped = config('csv.import_roles.' . $column . '.mappable'); + if ($canBeMapped) { + $mapperName = '\FireflyIII\Import\Mapper\\' . config('csv.import_roles.' . $column . '.mapper'); + /** @var MapperInterface $mapper */ + $mapper = new $mapperName; + $data[$index] = [ + 'name' => $column, + 'mapper' => $mapperName, + 'options' => $mapper->getMap(), + 'values' => [], + ]; + } + } + } + + + echo '
';
+ var_dump($data);
+ var_dump($config);
+
+
+ exit;
+
+
+ }
+
+ /**
+ * @return array
+ */
+ private function getDataForColumnRoles():array
+ {
+ $config = $this->job->configuration;
+ $data = [
+ 'columns' => [],
+ 'columnCount' => 0,
+ ];
+
+ // show user column role configuration.
+ $content = $this->job->uploadFileContents();
+
+ // create CSV reader.
+ $reader = Reader::createFromString($content);
+ $start = $config['has-headers'] ? 1 : 0;
+ $end = $start + self::EXAMPLE_ROWS; // first X rows
+
+ // collect example data in $data['columns']
+ while ($start < $end) {
+ $row = $reader->fetchOne($start);
+ foreach ($row as $index => $value) {
+ $value = trim($value);
+ if (strlen($value) > 0) {
+ $data['columns'][$index][] = $value;
+ }
+ }
+ $start++;
+ $data['columnCount'] = count($row);
+ }
+
+ // make unique example data
+ foreach ($data['columns'] as $index => $values) {
+ $data['columns'][$index] = array_unique($values);
+ }
+
+ $data['set_roles'] = [];
+ // collect possible column roles:
+ $data['available_roles'] = [];
+ foreach (array_keys(config('csv.import_roles')) as $role) {
+ $data['available_roles'][$role] = trans('csv.column_' . $role);
+ }
+
+ $config['column-count'] = $data['columnCount'];
+ $this->job->configuration = $config;
+ $this->job->save();
+
+ return $data;
+
+
+ }
}
\ No newline at end of file
diff --git a/app/Import/Mapper/AssetAccounts.php b/app/Import/Mapper/AssetAccounts.php
new file mode 100644
index 0000000000..fdf0a64daa
--- /dev/null
+++ b/app/Import/Mapper/AssetAccounts.php
@@ -0,0 +1,53 @@
+getAccountsByType([AccountType::DEFAULT, AccountType::ASSET]);
+ $list = [];
+
+ /** @var Account $account */
+ foreach ($set as $account) {
+ $name = $account->name;
+ $iban = $account->iban ?? '';
+ if (strlen($iban) > 0) {
+ $name .= ' (' . $account->iban . ')';
+ }
+ $list[$account->id] = $name;
+ }
+
+ asort($list);
+
+ $list = [0 => trans('csv.do_not_map')] + $list;
+
+ return $list;
+
+ }
+}
\ No newline at end of file
diff --git a/app/Import/Mapper/MapperInterface.php b/app/Import/Mapper/MapperInterface.php
new file mode 100644
index 0000000000..c285c9b31f
--- /dev/null
+++ b/app/Import/Mapper/MapperInterface.php
@@ -0,0 +1,26 @@
+getAccountsByType(
+ [
+ AccountType::DEFAULT, AccountType::ASSET,
+ AccountType::EXPENSE, AccountType::BENEFICIARY,
+ AccountType::REVENUE
+ ]);
+ $list = [];
+
+ /** @var Account $account */
+ foreach ($set as $account) {
+ $name = $account->name;
+ $iban = $account->iban ?? '';
+ if (strlen($iban) > 0) {
+ $name .= ' (' . $account->iban . ')';
+ }
+ $list[$account->id] = $name;
+ }
+
+ asort($list);
+
+ $list = [0 => trans('csv.do_not_map')] + $list;
+
+ return $list;
+ }
+}
\ No newline at end of file
diff --git a/app/Import/Mapper/TransactionCurrencies.php b/app/Import/Mapper/TransactionCurrencies.php
new file mode 100644
index 0000000000..6f21ebb355
--- /dev/null
+++ b/app/Import/Mapper/TransactionCurrencies.php
@@ -0,0 +1,42 @@
+id] = $currency->name . ' (' . $currency->code . ')';
+ }
+
+ asort($list);
+
+ $list = [0 => trans('csv.do_not_map')] + $list;
+
+ return $list;
+
+ }
+}
\ No newline at end of file
diff --git a/app/Models/Account.php b/app/Models/Account.php
index 9070be24e4..fdb7b3c2e9 100644
--- a/app/Models/Account.php
+++ b/app/Models/Account.php
@@ -13,6 +13,8 @@ namespace FireflyIII\Models;
use Auth;
use Crypt;
+use FireflyIII\Exceptions\FireflyException;
+use Illuminate\Contracts\Encryption\DecryptException;
use Illuminate\Database\Eloquent\Builder as EloquentBuilder;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
@@ -183,10 +185,14 @@ class Account extends Model
*/
public function getIbanAttribute($value): string
{
- if (is_null($value)) {
+ if (is_null($value) || strlen(strval($value)) === 0) {
return '';
}
- $result = Crypt::decrypt($value);
+ try {
+ $result = Crypt::decrypt($value);
+ } catch (DecryptException $e) {
+ throw new FireflyException('Cannot decrypt value "' . $value . '" for account #' . $this->id);
+ }
if (is_null($result)) {
return '';
}
diff --git a/config/csv.php b/config/csv.php
index e235133f32..6e0a7edd6f 100644
--- a/config/csv.php
+++ b/config/csv.php
@@ -25,37 +25,37 @@ return [
'mappable' => false,
'field' => 'bill',
'converter' => 'BillId',
- 'mapper' => 'Bill',
+ 'mapper' => 'Bills',
],
'bill-name' => [
'mappable' => true,
'converter' => 'BillName',
'field' => 'bill',
- 'mapper' => 'Bill',
+ 'mapper' => 'Bills',
],
'currency-id' => [
'mappable' => true,
'converter' => 'CurrencyId',
'field' => 'currency',
- 'mapper' => 'TransactionCurrency'
+ 'mapper' => 'TransactionCurrencies'
],
'currency-name' => [
'mappable' => true,
'converter' => 'CurrencyName',
'field' => 'currency',
- 'mapper' => 'TransactionCurrency'
+ 'mapper' => 'TransactionCurrencies'
],
'currency-code' => [
'mappable' => true,
'converter' => 'CurrencyCode',
'field' => 'currency',
- 'mapper' => 'TransactionCurrency'
+ 'mapper' => 'TransactionCurrencies'
],
'currency-symbol' => [
'mappable' => true,
'converter' => 'CurrencySymbol',
'field' => 'currency',
- 'mapper' => 'TransactionCurrency'
+ 'mapper' => 'TransactionCurrencies'
],
'description' => [
'mappable' => false,
@@ -76,13 +76,13 @@ return [
'mappable' => true,
'converter' => 'BudgetId',
'field' => 'budget',
- 'mapper' => 'Budget',
+ 'mapper' => 'Budgets',
],
'budget-name' => [
'mappable' => true,
'converter' => 'BudgetName',
'field' => 'budget',
- 'mapper' => 'Budget',
+ 'mapper' => 'Budgets',
],
'rabo-debet-credit' => [
'mappable' => false,
@@ -98,73 +98,73 @@ return [
'mappable' => true,
'converter' => 'CategoryId',
'field' => 'category',
- 'mapper' => 'Category',
+ 'mapper' => 'Categories',
],
'category-name' => [
'mappable' => true,
'converter' => 'CategoryName',
'field' => 'category',
- 'mapper' => 'Category',
+ 'mapper' => 'Categories',
],
'tags-comma' => [
'mappable' => true,
'field' => 'tags',
'converter' => 'TagsComma',
- 'mapper' => 'Tag',
+ 'mapper' => 'Tags',
],
'tags-space' => [
'mappable' => true,
'field' => 'tags',
'converter' => 'TagsSpace',
- 'mapper' => 'Tag',
+ 'mapper' => 'Tags',
],
'account-id' => [
'mappable' => true,
- 'mapper' => 'AssetAccount',
+ 'mapper' => 'AssetAccountId',
'field' => 'asset-account-id',
- 'converter' => 'AccountId'
+ 'converter' => 'AssetAccounts'
],
'account-name' => [
'mappable' => true,
- 'mapper' => 'AssetAccount',
+ 'mapper' => 'AssetAccountName',
'field' => 'asset-account-name',
- 'converter' => 'AssetAccountName'
+ 'converter' => 'AssetAccounts'
],
'account-iban' => [
'mappable' => true,
'converter' => 'AssetAccountIban',
'field' => 'asset-account-iban',
- 'mapper' => 'AssetAccount'
+ 'mapper' => 'AssetAccounts'
],
'account-number' => [
'mappable' => true,
'converter' => 'AssetAccountNumber',
'field' => 'asset-account-number',
- 'mapper' => 'AssetAccount'
+ 'mapper' => 'AssetAccounts'
],
'opposing-id' => [
'mappable' => true,
'field' => 'opposing-account-id',
'converter' => 'OpposingAccountId',
- 'mapper' => 'AnyAccount',
+ 'mapper' => 'OpposingAccounts',
],
'opposing-name' => [
'mappable' => true,
'field' => 'opposing-account-name',
'converter' => 'OpposingAccountName',
- 'mapper' => 'AnyAccount',
+ 'mapper' => 'OpposingAccounts',
],
'opposing-iban' => [
'mappable' => true,
'field' => 'opposing-account-iban',
'converter' => 'OpposingAccountIban',
- 'mapper' => 'AnyAccount',
+ 'mapper' => 'OpposingAccounts',
],
'opposing-number' => [
'mappable' => true,
'field' => 'opposing-account-number',
'converter' => 'OpposingAccountNumber',
- 'mapper' => 'AnyAccount',
+ 'mapper' => 'OpposingAccounts',
],
'amount' => [
'mappable' => false,
diff --git a/resources/lang/en_US/csv.php b/resources/lang/en_US/csv.php
index c27e945dce..3f2003ff22 100644
--- a/resources/lang/en_US/csv.php
+++ b/resources/lang/en_US/csv.php
@@ -32,6 +32,7 @@ return [
'column' => 'Column',
'no_example_data' => 'No example data available',
'store_column_roles' => 'Continue import',
+ 'do_not_map' => '(do not map)',
'column__ignore' => '(ignore this column)',
'column_account-iban' => 'Asset account (IBAN)',
diff --git a/resources/views/import/csv/map.twig b/resources/views/import/csv/map.twig
new file mode 100644
index 0000000000..bc6a5cea31
--- /dev/null
+++ b/resources/views/import/csv/map.twig
@@ -0,0 +1,84 @@
+{% extends "./layout/default.twig" %}
+
+{% block breadcrumbs %}
+ {{ Breadcrumbs.renderIfExists(Route.getCurrentRoute.getName) }}
+{% endblock %}
+
+{% block content %}
+
+
+
+
+
+
+ {{ trans('csv.map_title') }}
+
+
+
+ {{ trans('csv.map_text') }}
+
+
+
+
+
+
+
+
+
+{% endblock %}