From 162c762973c1814ddab91c0b18d93fb1cb677129 Mon Sep 17 00:00:00 2001 From: James Cole Date: Sat, 2 Jul 2016 20:40:23 +0200 Subject: [PATCH] First set of data mappers. --- app/Import/Importer/CsvImporter.php | 154 ++++++++++++++------ app/Import/Mapper/AssetAccounts.php | 53 +++++++ app/Import/Mapper/MapperInterface.php | 26 ++++ app/Import/Mapper/OpposingAccounts.php | 57 ++++++++ app/Import/Mapper/TransactionCurrencies.php | 42 ++++++ app/Models/Account.php | 10 +- config/csv.php | 44 +++--- resources/lang/en_US/csv.php | 1 + resources/views/import/csv/map.twig | 84 +++++++++++ 9 files changed, 404 insertions(+), 67 deletions(-) create mode 100644 app/Import/Mapper/AssetAccounts.php create mode 100644 app/Import/Mapper/MapperInterface.php create mode 100644 app/Import/Mapper/OpposingAccounts.php create mode 100644 app/Import/Mapper/TransactionCurrencies.php create mode 100644 resources/views/import/csv/map.twig 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') }} +

+
+
+ +
+
+
+ + + {# + + {% for index,columnName in map %} + +
+
+
+
+

{{ Config.get('csv.roles.'~columnName~'.name') }}

+
+
+ + + + + + + + + {% for value in values[index] %} + + + + + {% endfor %} + + + +
{{ 'csv_field_value'|_ }}{{ 'csv_field_mapped_to'|_ }}
{{ value }} + {{ Form.select('mapping['~index~']['~value~']',options[index], mapped[index][value], {class: 'form-control'}) }} +
+ + +
+
+
+
+ {% endfor %} + #} + + +
+
+
+
+ +
+
+
+
+ +
+ + +{% endblock %}