Expanded CSV configuration.

This commit is contained in:
James Cole 2015-07-05 14:37:36 +02:00
parent 9e7b730002
commit d7329a5915
21 changed files with 363 additions and 135 deletions

View File

@ -1,10 +1,4 @@
<?php
/**
* Created by PhpStorm.
* User: sander
* Date: 27/06/15
* Time: 17:21
*/
namespace FireflyIII\Generator\Chart\Bill;

View File

@ -1,51 +0,0 @@
<?php
/**
* Created by PhpStorm.
* User: sander
* Date: 05/07/15
* Time: 05:49
*/
namespace FireflyIII\Helpers\Csv\Converter;
use Auth;
use FireflyIII\Models\Account;
use FireflyIII\Models\AccountType;
use Log;
/**
* Class AccountIban
*
* @package FireflyIII\Helpers\Csv\Converter
*/
class AccountIban extends BasicConverter implements ConverterInterface
{
/**
* @return Account|null
*/
public function convert()
{
// is mapped? Then it's easy!
if (isset($this->mapped[$this->index][$this->value])) {
$account = Auth::user()->accounts()->find($this->mapped[$this->index][$this->value]);
} else {
// find or create new account:
$accountType = AccountType::where('type', 'Asset account')->first();
$account = Account::firstOrCreateEncrypted(
[
'name' => $this->value,
//'iban' => $this->value,
'user_id' => Auth::user()->id,
'account_type_id' => $accountType->id,
'active' => true,
]
);
if ($account->getErrors()->count() > 0) {
Log::error('Create or find asset account: ' . json_encode($account->getErrors()->all()));
}
}
return $account;
}
}

View File

@ -0,0 +1,29 @@
<?php
namespace FireflyIII\Helpers\Csv\Converter;
use Auth;
use FireflyIII\Models\Account;
/**
* Class AccountId
*
* @package FireflyIII\Helpers\Csv\Converter
*/
class AccountId extends BasicConverter implements ConverterInterface
{
/**
* @return Account
*/
public function convert()
{
// is mapped? Then it's easy!
if (isset($this->mapped[$this->index][$this->value])) {
$account = Auth::user()->accounts()->find($this->mapped[$this->index][$this->value]);
} else {
$account = Auth::user()->accounts()->find($this->value);
}
return $account;
}
}

View File

@ -1,10 +1,4 @@
<?php
/**
* Created by PhpStorm.
* User: sander
* Date: 05/07/15
* Time: 05:49
*/
namespace FireflyIII\Helpers\Csv\Converter;

View File

@ -0,0 +1,51 @@
<?php
namespace FireflyIII\Helpers\Csv\Converter;
use Auth;
use FireflyIII\Models\Account;
use FireflyIII\Models\AccountType;
/**
* Class AssetAccountIban
*
* @package FireflyIII\Helpers\Csv\Converter
*/
class AssetAccountIban extends BasicConverter implements ConverterInterface
{
/**
* @return Account|null
*/
public function convert()
{
// is mapped? Then it's easy!
if (isset($this->mapped[$this->index][$this->value])) {
$account = Auth::user()->accounts()->find($this->mapped[$this->index][$this->value]);
return $account;
}
// find or create new account:
$accountType = AccountType::where('type', 'Asset account')->first();
$set = Auth::user()->accounts()->where('account_type_id', $accountType->id)->get();
/** @var Account $entry */
foreach ($set as $entry) {
if ($entry->iban == $this->value) {
return $entry;
}
}
// create it if doesnt exist.
$account = Account::firstOrCreateEncrypted(
[
'name' => $this->value,
'iban' => $this->value,
'user_id' => Auth::user()->id,
'account_type_id' => $accountType->id,
'active' => 1,
]
);
return $account;
}
}

View File

@ -0,0 +1,50 @@
<?php
namespace FireflyIII\Helpers\Csv\Converter;
use Auth;
use FireflyIII\Models\Account;
use FireflyIII\Models\AccountType;
/**
* Class AssetAccountName
*
* @package FireflyIII\Helpers\Csv\Converter
*/
class AssetAccountName extends BasicConverter implements ConverterInterface
{
/**
* @return Account|null
*/
public function convert()
{
// is mapped? Then it's easy!
if (isset($this->mapped[$this->index][$this->value])) {
$account = Auth::user()->accounts()->find($this->mapped[$this->index][$this->value]);
return $account;
}
// find or create new account:
$accountType = AccountType::where('type', 'Asset account')->first();
$set = Auth::user()->accounts()->where('account_type_id', $accountType->id)->get();
/** @var Account $entry */
foreach ($set as $entry) {
if ($entry->name == $this->value) {
return $entry;
}
}
// create it if doesnt exist.
$account = Account::firstOrCreateEncrypted(
[
'name' => $this->value,
'iban' => '',
'user_id' => Auth::user()->id,
'account_type_id' => $accountType->id,
'active' => 1,
]
);
return $account;
}
}

View File

@ -0,0 +1,30 @@
<?php
namespace FireflyIII\Helpers\Csv\Converter;
use Auth;
use FireflyIII\Models\Bill;
/**
* Class BillId
*
* @package FireflyIII\Helpers\Csv\Converter
*/
class BillId extends BasicConverter implements ConverterInterface
{
/**
* @return Bill
*/
public function convert()
{
// is mapped? Then it's easy!
if (isset($this->mapped[$this->index][$this->value])) {
$bill = Auth::user()->bills()->find($this->mapped[$this->index][$this->value]);
} else {
$bill = Auth::user()->bills()->find($this->value);
}
return $bill;
}
}

View File

@ -0,0 +1,38 @@
<?php
namespace FireflyIII\Helpers\Csv\Converter;
use Auth;
use FireflyIII\Models\Bill;
/**
* Class BillName
*
* @package FireflyIII\Helpers\Csv\Converter
*/
class BillName extends BasicConverter implements ConverterInterface
{
/**
* @return Bill
*/
public function convert()
{
$bill = null;
// is mapped? Then it's easy!
if (isset($this->mapped[$this->index][$this->value])) {
$bill = Auth::user()->bills()->find($this->mapped[$this->index][$this->value]);
} else {
$bills = Auth::user()->bills()->get();
/** @var Bill $bill */
foreach ($bills as $bill) {
if ($bill->name == $this->value) {
return $bill;
}
}
}
return $bill;
}
}

View File

@ -1,10 +1,4 @@
<?php
/**
* Created by PhpStorm.
* User: sander
* Date: 05/07/15
* Time: 05:42
*/
namespace FireflyIII\Helpers\Csv\Converter;

View File

@ -1,10 +1,4 @@
<?php
/**
* Created by PhpStorm.
* User: sander
* Date: 05/07/15
* Time: 05:49
*/
namespace FireflyIII\Helpers\Csv\Converter;

View File

@ -1,10 +1,4 @@
<?php
/**
* Created by PhpStorm.
* User: sander
* Date: 05/07/15
* Time: 06:12
*/
namespace FireflyIII\Helpers\Csv\Converter;

View File

@ -4,17 +4,19 @@ namespace FireflyIII\Helpers\Csv;
use App;
use Auth;
use Carbon\Carbon;
use Config;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Helpers\Csv\Converter\ConverterInterface;
use FireflyIII\Models\Account;
use FireflyIII\Models\AccountType;
use FireflyIII\Models\Transaction;
use FireflyIII\Models\TransactionCurrency;
use FireflyIII\Models\TransactionJournal;
use FireflyIII\Models\TransactionType;
use Illuminate\Support\MessageBag;
use Log;
use Preferences;
use ReflectionException;
set_time_limit(0);
@ -30,15 +32,43 @@ class Importer
protected $data;
/** @var array */
protected $errors;
/** @var int */
protected $imported;
/** @var array */
protected $map;
/** @var array */
protected $mapped;
/** @var array */
protected $roles;
/** @var int */
protected $rows = 0;
/**
*
* @return array
*/
public function getErrors()
{
return $this->errors;
}
/**
* @return int
*/
public function getImported()
{
return $this->imported;
}
/**
* @return int
*/
public function getRows()
{
return $this->rows;
}
/**
* @throws FireflyException
*/
public function run()
{
@ -46,15 +76,18 @@ class Importer
$this->roles = $this->data->getRoles();
$this->mapped = $this->data->getMapped();
foreach ($this->data->getReader() as $index => $row) {
Log::debug('Now at row ' . $index);
$result = $this->importRow($row);
if (!($result === true)) {
Log::error('Caught error at row #' . $index . ': ' . $result);
$this->errors[$index] = $result;
if (($this->data->getHasHeaders() && $index > 1) || !$this->data->getHasHeaders()) {
$this->rows++;
Log::debug('Now at row ' . $index);
$result = $this->importRow($row);
if (!($result === true)) {
Log::error('Caught error at row #' . $index . ': ' . $result);
$this->errors[$index] = $result;
} else {
$this->imported++;
}
}
}
return count($this->errors);
}
/**
@ -80,8 +113,12 @@ class Importer
if (is_null($field)) {
throw new FireflyException('No place to store value of type "' . $role . '".');
}
/** @var ConverterInterface $converter */
$converter = App::make('FireflyIII\Helpers\Csv\Converter\\' . $class);
try {
/** @var ConverterInterface $converter */
$converter = App::make('FireflyIII\Helpers\Csv\Converter\\' . $class);
} catch (ReflectionException $e) {
throw new FireflyException('Cannot continue with column of type "' . $role . '" because class "' . $class . '" cannot be found.');
}
$converter->setData($data); // the complete array so far.
$converter->setField($field);
$converter->setIndex($index);
@ -122,6 +159,8 @@ class Importer
'amount-modifier' => 1,
'ignored' => null,
'date-rent' => null,
'bill' => null,
'bill-id' => null,
];
}
@ -147,19 +186,27 @@ class Importer
$accountType = AccountType::where('type', 'Revenue account')->first();
}
if(strlen($data['description']) == 0) {
if (strlen($data['description']) == 0) {
$data['description'] = trans('firefly.csv_empty_description');
}
// fix currency
if (is_null($data['currency'])) {
$currencyPreference = Preferences::get('currencyPreference', 'EUR');
$data['currency'] = TransactionCurrency::whereCode($currencyPreference->data)->first();
}
if (!is_null($data['bill'])) {
$data['bill-id'] = $data['bill']->id;
}
// do bank specific fixes:
$specifix = new Specifix();
$specifix->setData($data);
$specifix->setRow($row);
$specifix->fix($data, $row);
//$specifix->fix($data, $row); // TODO
// get data back:
$data = $specifix->getData();
//$data = $specifix->getData(); // TODO
$data['opposing-account-object'] = Account::firstOrCreateEncrypted(
[
@ -215,11 +262,11 @@ class Importer
[
'user_id' => Auth::user()->id,
'transaction_type_id' => $transactionType->id,
'bill_id' => null,
'transaction_currency_id' => $data['currency']->id,
'description' => $data['description'],
'completed' => 0,
'date' => $date,
'bill_id' => $data['bill-id'],
]
);
$errors = $journal->getErrors()->merge($errors);
@ -261,14 +308,5 @@ class Importer
$this->data = $data;
}
/**
* @param $value
*
* @return Carbon
*/
protected function parseDate($value)
{
return Carbon::createFromFormat($this->data->getDateFormat(), $value);
}
}

View File

@ -1,10 +1,4 @@
<?php
/**
* Created by PhpStorm.
* User: sander
* Date: 05/07/15
* Time: 08:35
*/
namespace FireflyIII\Helpers\Csv\Mapper;

View File

@ -1,10 +1,4 @@
<?php
/**
* Created by PhpStorm.
* User: sander
* Date: 03/07/15
* Time: 10:37
*/
namespace FireflyIII\Http\Controllers;
@ -17,6 +11,7 @@ use FireflyIII\Helpers\Csv\WizardInterface;
use Illuminate\Http\Request;
use Input;
use Log;
use Preferences;
use Redirect;
use Session;
use View;
@ -74,7 +69,7 @@ class CsvController extends Controller
$firstRow = $this->data->getReader()->fetchOne();
$count = count($firstRow);
$headers = [];
$example = $this->data->getReader()->fetchOne();
$example = $this->data->getReader()->fetchOne(1);
$availableRoles = [];
$roles = $this->data->getRoles();
$map = $this->data->getMap();
@ -166,6 +161,9 @@ class CsvController extends Controller
if ($role['mappable'] === true && !isset($role['mapper'])) {
$unsupported[] = trans('firefly.csv_unsupported_map', ['columnRole' => $role['name']]);
}
if (!isset($role['field'])) {
$unsupported[] = trans('firefly.csv_cannot_store_value', ['columnRole' => $role['name']]);
}
}
sort($unsupported);
@ -309,8 +307,13 @@ class CsvController extends Controller
}
Log::debug('Done importing!');
echo 'display result';
exit;
$rows = $importer->getRows();
$errors = $importer->getErrors();
$imported = $importer->getImported();
Preferences::mark();
return view('csv.process', compact('rows', 'errors', 'imported'));
}

View File

@ -40,6 +40,9 @@ class HomeController extends Controller
*/
public function flush()
{
Preferences::mark();
// get all tags.
// update all counts:
$tags = Tag::get();
@ -54,6 +57,7 @@ class HomeController extends Controller
}
Session::clear();
return Redirect::route('index');

View File

@ -76,7 +76,7 @@ class Account extends Model
// everything but the name:
$query = Account::orderBy('id');
foreach ($fields as $name => $value) {
if ($name != 'name') {
if ($name != 'name' && $name != 'iban') {
$query->where($name, $value);
}
}
@ -87,6 +87,11 @@ class Account extends Model
return $account;
}
}
// account must have a name. If not set, use IBAN.
if (!isset($fields['name'])) {
$fields['name'] = $fields['iban'];
}
// create it!
$account = Account::create($fields);

View File

@ -8,12 +8,16 @@ return [
'field' => 'ignored',
],
'bill-id' => [
'name' => 'Bill ID (matching Firefly)',
'mappable' => true,
'name' => 'Bill ID (matching Firefly)',
'mappable' => false,
'field' => 'bill',
'converter' => 'BillId'
],
'bill-name' => [
'name' => 'Bill name',
'mappable' => true,
'name' => 'Bill name',
'mappable' => true,
'converter' => 'BillName',
'field' => 'bill',
],
'currency-id' => [
'name' => 'Currency ID (matching Firefly)',
@ -83,32 +87,38 @@ return [
'mappable' => true,
],
'account-id' => [
'name' => 'Asset account ID (matching Firefly)',
'mappable' => true,
'name' => 'Asset account ID (matching Firefly)',
'mappable' => true,
'mapper' => 'AssetAccount',
'field' => 'asset-account',
'converter' => 'AccountId'
],
'account-name' => [
'name' => 'Asset account name',
'mappable' => true,
'name' => 'Asset account name',
'mappable' => true,
'mapper' => 'AssetAccount',
'field' => 'asset-account',
'converter' => 'AssetAccountName'
],
'account-iban' => [
'name' => 'Asset account IBAN',
'mappable' => true,
'converter' => 'AccountIban',
'converter' => 'AssetAccountIban',
'field' => 'asset-account',
'mapper' => 'AssetAccount'
],
'opposing-id' => [
'name' => 'Expense or revenue account ID (matching Firefly)',
'name' => 'Opposing account account ID (matching Firefly)',
'mappable' => true,
],
'opposing-name' => [
'name' => 'Expense or revenue account name',
'name' => 'Opposing account name',
'mappable' => true,
'converter' => 'OpposingName',
'field' => 'opposing-account'
],
'opposing-iban' => [
'name' => 'Expense or revenue account IBAN',
'name' => 'Opposing account IBAN',
'mappable' => true,
],
'amount' => [

View File

@ -62,6 +62,14 @@ return [
'csv_index_unsupported_warning' => 'The CSV importer is yet incapable of doing the following:',
'csv_unsupported_map' => 'The importer cannot map the column ":columnRole" to existing values in the database.',
'csv_unsupported_value' => 'The importer does not know how to handle values in columns marked as ":columnRole".',
'csv_cannot_store_value' => 'The importer has not reserved space for columns marked ":columnRole" and will be incapable of processing them.',
'csv_process_title' => 'CVS import finished',
'csv_process_text' => 'The CVS importer has finished and has imported :rows rows',
'csv_row' => 'Row',
'csv_import_with_errors' => 'There was one error.|There were :errors errors.',
'csv_error_see_logs' => 'Check the log files to see details.',
'csv_start_over' => 'Import again',
'csv_to_index' => 'Back home',
// 'csv_index_text' => 'Here be explanation.',
// 'csv_upload_form' => 'Upload form',
// 'upload_csv_file' => 'Upload CSV file',

View File

@ -40,7 +40,7 @@
<div class="col-lg-12">
<div class="box">
<div class="box-body">
<a href="{{ route('csv.index') }}" class="btn btn-danger"><i class="fa fa-arrow-left"></i> {{ 'csv_go_back'|_ }}</a>
<a href="{{ route('csv.column-roles') }}" class="btn btn-danger"><i class="fa fa-arrow-left"></i> {{ 'csv_go_back'|_ }}</a>
<a href="{{ route('csv.process') }}" class="btn btn-success pull-right">{{ 'csv_continue'|_ }} <i class="fa fa-arrow-right"></i></a>
</div>
</div>

View File

@ -54,7 +54,7 @@
<div class="box-body">
{{ ExpandedForm.checkbox('has_headers',false,null,{helpText: 'csv_header_help'|_}) }}
{{ ExpandedForm.checkbox('has_headers',1,null,{helpText: 'csv_header_help'|_}) }}
{{ ExpandedForm.text('date_format','Ymd',{helpText: 'csv_date_help'|_}) }}
{{ ExpandedForm.file('csv',{helpText: 'csv_csv_file_help'|_}) }}

View File

@ -0,0 +1,49 @@
{% extends "./layout/default.twig" %}
{% block breadcrumbs %}
{{ Breadcrumbs.renderIfExists(Route.getCurrentRoute.getName) }}
{% endblock %}
{% block content %}
<div class="row">
<div class="col-lg-12">
<div class="box">
<div class="box-header with-border">
<h3 class="box-title">{{ 'csv_process_title'|_ }}</h3>
<!-- ACTIONS MENU -->
<div class="box-tools pull-right">
<button class="btn btn-box-tool" data-widget="collapse"><i class="fa fa-minus"></i></button>
</div>
</div>
<div class="box-body">
<p>
{{ trans('firefly.csv_process_text',{rows: rows}) }}
</p>
{% if errors|length > 0 %}
<p class="text-danger">{{ Lang.choice('firefly.csv_import_with_errors',errors|length,{errors: errors|length}) }}</p>
<ul>
{% for index,err in errors %}
<li>{{ 'csv_row'|_ }} #{{ index }}: {{ err }}</li>
{% endfor %}
</ul>
<p>
{{ trans('firefly.csv_error_see_logs') }}
</p>
{% endif %}
<p>
<a href="{{ route('csv.index') }}" class="btn btn-warning">{{ 'csv_start_over'|_ }}</a>
<a href="{{ route('index') }}" class="btn btn-success">{{ 'csv_to_index'|_ }}</a>
</p>
</div>
</div>
</div>
</div>
{% endblock %}