From 87c0f1d86e63c1e7cf56b1a4a62e7334afdcca12 Mon Sep 17 00:00:00 2001 From: James Cole Date: Sat, 23 Jul 2016 21:37:06 +0200 Subject: [PATCH] More CSV related updates. --- app/Crud/Account/AccountCrud.php | 28 ++ app/Crud/Account/AccountCrudInterface.php | 8 + app/Http/Controllers/ImportController.php | 2 +- app/Import/Converter/AssetAccountIban.php | 3 +- app/Import/Converter/AssetAccountId.php | 38 ++- app/Import/Converter/AssetAccountName.php | 45 ++- app/Import/Converter/AssetAccountNumber.php | 43 ++- app/Import/Converter/BillId.php | 36 ++- app/Import/Converter/BillName.php | 51 +++- app/Import/Converter/OpposingAccountIban.php | 35 +-- app/Import/Importer/CsvImporter.php | 56 +++- .../PreProcessorInterface.php | 28 ++ app/Import/MapperPreProcess/TagsComma.php | 31 ++ app/Import/MapperPreProcess/TagsSpace.php | 30 ++ app/Providers/AccountServiceProvider.php | 2 +- app/Providers/AttachmentServiceProvider.php | 2 +- app/Providers/BillServiceProvider.php | 2 +- app/Providers/BudgetServiceProvider.php | 2 +- app/Providers/CategoryServiceProvider.php | 2 +- app/Providers/CrudServiceProvider.php | 10 +- app/Providers/ExportJobServiceProvider.php | 4 +- app/Providers/JournalServiceProvider.php | 2 +- app/Providers/PiggyBankServiceProvider.php | 2 +- app/Providers/RuleGroupServiceProvider.php | 2 +- app/Providers/RuleServiceProvider.php | 2 +- app/Providers/TagServiceProvider.php | 2 +- app/Repositories/Bill/BillRepository.php | 117 ++++--- .../Bill/BillRepositoryInterface.php | 39 ++- config/app.php | 33 +- config/csv.php | 288 +++++++++++------- resources/views/import/csv/configure.twig | 2 +- 31 files changed, 684 insertions(+), 263 deletions(-) create mode 100644 app/Import/MapperPreProcess/PreProcessorInterface.php create mode 100644 app/Import/MapperPreProcess/TagsComma.php create mode 100644 app/Import/MapperPreProcess/TagsSpace.php diff --git a/app/Crud/Account/AccountCrud.php b/app/Crud/Account/AccountCrud.php index 11958fba4b..682b8bc162 100644 --- a/app/Crud/Account/AccountCrud.php +++ b/app/Crud/Account/AccountCrud.php @@ -74,6 +74,7 @@ class AccountCrud implements AccountCrudInterface */ public function find(int $accountId): Account { + Log::debug('Searching for user ', ['user' => $this->user->id]); $account = $this->user->accounts()->find($accountId); if (is_null($account)) { return new Account; @@ -82,6 +83,33 @@ class AccountCrud implements AccountCrudInterface return $account; } + /** + * @param string $number + * @param array $types + * + * @return Account + */ + public function findByAccountNumber(string $number, array $types): Account + { + $query = $this->user->accounts() + ->leftJoin('account_meta', 'account_meta.account_id', '=', 'accounts.id') + ->where('account_meta.name', 'accountNumber') + ->where('account_meta.data', json_encode($number)); + + if (count($types) > 0) { + $query->leftJoin('account_types', 'accounts.account_type_id', '=', 'account_types.id'); + $query->whereIn('account_types.type', $types); + } + + /** @var Collection $accounts */ + $accounts = $query->get(); + if ($accounts->count() > 0) { + return $accounts->first(); + } + + return new Account; + } + /** * @param string $iban * @param array $types diff --git a/app/Crud/Account/AccountCrudInterface.php b/app/Crud/Account/AccountCrudInterface.php index 1b11bdbbb0..41b6956cfa 100644 --- a/app/Crud/Account/AccountCrudInterface.php +++ b/app/Crud/Account/AccountCrudInterface.php @@ -53,6 +53,14 @@ interface AccountCrudInterface */ public function findByName(string $name, array $types): Account; + /** + * @param string $number + * @param array $types + * + * @return Account + */ + public function findByAccountNumber(string $number, array $types): Account; + /** * @param array $accountIds * diff --git a/app/Http/Controllers/ImportController.php b/app/Http/Controllers/ImportController.php index 589d7a1a5a..40a636deaf 100644 --- a/app/Http/Controllers/ImportController.php +++ b/app/Http/Controllers/ImportController.php @@ -117,7 +117,7 @@ class ImportController extends Controller /** * This is step 1. Upload a file. * - * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View + * @return View */ public function index() { diff --git a/app/Import/Converter/AssetAccountIban.php b/app/Import/Converter/AssetAccountIban.php index e903312a63..acc1389335 100644 --- a/app/Import/Converter/AssetAccountIban.php +++ b/app/Import/Converter/AssetAccountIban.php @@ -62,7 +62,8 @@ class AssetAccountIban extends BasicConverter implements ConverterInterface $account = $repository->store( - ['name' => $value, 'iban' => $value, 'user' => $this->user->id, 'accountType' => 'asset', 'virtualBalance' => 0, 'active' => true] + ['name' => 'Account with IBAN ' . $value, 'iban' => $value, 'user' => $this->user->id, 'accountType' => 'asset', 'virtualBalance' => 0, + 'active' => true] ); return $account; diff --git a/app/Import/Converter/AssetAccountId.php b/app/Import/Converter/AssetAccountId.php index b335e8e621..f055f819c7 100644 --- a/app/Import/Converter/AssetAccountId.php +++ b/app/Import/Converter/AssetAccountId.php @@ -11,7 +11,9 @@ declare(strict_types = 1); namespace FireflyIII\Import\Converter; -use FireflyIII\Exceptions\FireflyException; +use FireflyIII\Crud\Account\AccountCrudInterface; +use FireflyIII\Models\Account; +use Log; /** * Class AssetAccountId @@ -24,11 +26,41 @@ class AssetAccountId extends BasicConverter implements ConverterInterface /** * @param $value * - * @throws FireflyException + * @return Account */ public function convert($value) { - throw new FireflyException('Importer with name AssetAccountId has not yet been configured.'); + $value = intval(trim($value)); + Log::debug('Going to convert using AssetAccountId', ['value' => $value]); + + if ($value === 0) { + return new Account; + } + + /** @var AccountCrudInterface $repository */ + $repository = app(AccountCrudInterface::class, [$this->user]); + + + if (isset($this->mapping[$value])) { + Log::debug('Found account in mapping. Should exist.', ['value' => $value, 'map' => $this->mapping[$value]]); + $account = $repository->find(intval($this->mapping[$value])); + if (!is_null($account->id)) { + Log::debug('Found account by ID', ['id' => $account->id]); + + return $account; + } + } + + // not mapped? Still try to find it first: + $account = $repository->find($value); + if (!is_null($account->id)) { + Log::debug('Found account by ID ', ['id' => $account->id]); + + return $account; + } + + // should not really happen. If the ID does not match FF, what is FF supposed to do? + return new Account; } } \ No newline at end of file diff --git a/app/Import/Converter/AssetAccountName.php b/app/Import/Converter/AssetAccountName.php index ba5789cd31..e1b10b222a 100644 --- a/app/Import/Converter/AssetAccountName.php +++ b/app/Import/Converter/AssetAccountName.php @@ -11,7 +11,10 @@ declare(strict_types = 1); namespace FireflyIII\Import\Converter; -use FireflyIII\Exceptions\FireflyException; +use FireflyIII\Crud\Account\AccountCrudInterface; +use FireflyIII\Models\Account; +use FireflyIII\Models\AccountType; +use Log; /** * Class AssetAccountName @@ -24,11 +27,47 @@ class AssetAccountName extends BasicConverter implements ConverterInterface /** * @param $value * - * @throws FireflyException + * @return Account */ public function convert($value) { - throw new FireflyException('Importer with name AssetAccountName has not yet been configured.'); + $value = trim($value); + Log::debug('Going to convert using AssetAccountName', ['value' => $value]); + + if (strlen($value) === 0) { + return new Account; + } + + /** @var AccountCrudInterface $repository */ + $repository = app(AccountCrudInterface::class, [$this->user]); + + + if (isset($this->mapping[$value])) { + Log::debug('Found account in mapping. Should exist.', ['value' => $value, 'map' => $this->mapping[$value]]); + $account = $repository->find(intval($this->mapping[$value])); + if (!is_null($account->id)) { + Log::debug('Found account by ID', ['id' => $account->id]); + + return $account; + } + } + + // not mapped? Still try to find it first: + $account = $repository->findByName($value, [AccountType::ASSET]); + if (!is_null($account->id)) { + Log::debug('Found account by name', ['id' => $account->id]); + + return $account; + } + + + $account = $repository->store( + ['name' => $value, 'iban' => null, 'openingBalance' => 0, 'user' => $this->user->id, 'accountType' => 'asset', 'virtualBalance' => 0, + 'active' => true] + ); + + return $account; + } } \ No newline at end of file diff --git a/app/Import/Converter/AssetAccountNumber.php b/app/Import/Converter/AssetAccountNumber.php index d991c3ff14..d2373e23c5 100644 --- a/app/Import/Converter/AssetAccountNumber.php +++ b/app/Import/Converter/AssetAccountNumber.php @@ -11,7 +11,11 @@ declare(strict_types = 1); namespace FireflyIII\Import\Converter; +use FireflyIII\Crud\Account\AccountCrudInterface; use FireflyIII\Exceptions\FireflyException; +use FireflyIII\Models\Account; +use FireflyIII\Models\AccountType; +use Log; /** * Class AssetAccountNumber @@ -24,11 +28,46 @@ class AssetAccountNumber extends BasicConverter implements ConverterInterface /** * @param $value * - * @throws FireflyException + * @return Account */ public function convert($value) { - throw new FireflyException('Importer with name AssetAccountNumber has not yet been configured.'); + $value = trim($value); + Log::debug('Going to convert using AssetAccountName', ['value' => $value]); + + if (strlen($value) === 0) { + return new Account; + } + + /** @var AccountCrudInterface $repository */ + $repository = app(AccountCrudInterface::class, [$this->user]); + + + if (isset($this->mapping[$value])) { + Log::debug('Found account in mapping. Should exist.', ['value' => $value, 'map' => $this->mapping[$value]]); + $account = $repository->find(intval($this->mapping[$value])); + if (!is_null($account->id)) { + Log::debug('Found account by ID', ['id' => $account->id]); + + return $account; + } + } + + // not mapped? Still try to find it first: + $account = $repository->findByAccountNumber($value, [AccountType::ASSET]); + if (!is_null($account->id)) { + Log::debug('Found account by name', ['id' => $account->id]); + + return $account; + } + + + $account = $repository->store( + ['name' => 'Account with number ' . $value, 'openingBalance' => 0, 'iban' => null, 'user' => $this->user->id, 'accountType' => 'asset', + 'virtualBalance' => 0, 'active' => true] + ); + + return $account; } } \ No newline at end of file diff --git a/app/Import/Converter/BillId.php b/app/Import/Converter/BillId.php index 76b8c01fd2..00fa42d0ef 100644 --- a/app/Import/Converter/BillId.php +++ b/app/Import/Converter/BillId.php @@ -12,6 +12,9 @@ declare(strict_types = 1); namespace FireflyIII\Import\Converter; use FireflyIII\Exceptions\FireflyException; +use FireflyIII\Models\Bill; +use FireflyIII\Repositories\Bill\BillRepositoryInterface; +use Log; /** * Class BillId @@ -24,11 +27,40 @@ class BillId extends BasicConverter implements ConverterInterface /** * @param $value * - * @throws FireflyException + * @return Bill */ public function convert($value) { - throw new FireflyException('Importer with name BillId has not yet been configured.'); + $value = intval(trim($value)); + Log::debug('Going to convert using BillId', ['value' => $value]); + + if ($value === 0) { + return new Bill; + } + + /** @var BillRepositoryInterface $repository */ + $repository = app(BillRepositoryInterface::class, [$this->user]); + + if (isset($this->mapping[$value])) { + Log::debug('Found bill in mapping. Should exist.', ['value' => $value, 'map' => $this->mapping[$value]]); + $bill = $repository->find(intval($this->mapping[$value])); + if (!is_null($bill->id)) { + Log::debug('Found bill by ID', ['id' => $bill->id]); + + return $bill; + } + } + + // not mapped? Still try to find it first: + $bill = $repository->find($value); + if (!is_null($bill->id)) { + Log::debug('Found bill by ID ', ['id' => $bill->id]); + + return $bill; + } + + // should not really happen. If the ID does not match FF, what is FF supposed to do? + return new Bill; } } \ No newline at end of file diff --git a/app/Import/Converter/BillName.php b/app/Import/Converter/BillName.php index 888b6c4779..7dd8241e3c 100644 --- a/app/Import/Converter/BillName.php +++ b/app/Import/Converter/BillName.php @@ -12,6 +12,9 @@ declare(strict_types = 1); namespace FireflyIII\Import\Converter; use FireflyIII\Exceptions\FireflyException; +use FireflyIII\Models\Bill; +use FireflyIII\Repositories\Bill\BillRepositoryInterface; +use Log; /** * Class BillName @@ -28,7 +31,53 @@ class BillName extends BasicConverter implements ConverterInterface */ public function convert($value) { - throw new FireflyException('Importer with name BillName has not yet been configured.'); + $value = trim($value); + Log::debug('Going to convert using BillName', ['value' => $value]); + + if (strlen($value) === 0) { + return new Bill; + } + + /** @var BillRepositoryInterface $repository */ + $repository = app(BillRepositoryInterface::class, [$this->user]); + + if (isset($this->mapping[$value])) { + Log::debug('Found bill in mapping. Should exist.', ['value' => $value, 'map' => $this->mapping[$value]]); + $bill = $repository->find(intval($this->mapping[$value])); + if (!is_null($bill->id)) { + Log::debug('Found bill by ID', ['id' => $bill->id]); + + return $bill; + } + } + + // not mapped? Still try to find it first: + $bill = $repository->findByName($value); + if (!is_null($bill->id)) { + Log::debug('Found bill by name ', ['id' => $bill->id]); + + return $bill; + } + + // create new bill. Use a lot of made up values. + $bill = $repository->store( + [ + 'name' => $value, + 'match' => $value, + 'amount_min' => 1, + 'user_id' => $this->user->id, + 'amount_max' => 10, + 'date' => date('Ymd'), + 'repeat_freq' => 'monthly', + 'skip' => 0, + 'automatch' => 0, + 'active' => 1, + + ] + ); + + return $bill; + } } \ No newline at end of file diff --git a/app/Import/Converter/OpposingAccountIban.php b/app/Import/Converter/OpposingAccountIban.php index a364c597ef..c59f4ffb3c 100644 --- a/app/Import/Converter/OpposingAccountIban.php +++ b/app/Import/Converter/OpposingAccountIban.php @@ -65,40 +65,7 @@ class OpposingAccountIban extends BasicConverter implements ConverterInterface $account = $repository->store( ['name' => $value, 'iban' => $value, 'user' => $this->user->id, 'accountType' => 'import', 'virtualBalance' => 0, 'active' => true, - 'openingBalance' => 0 0] ); return $account; diff --git a/app/Import/Importer/CsvImporter.php b/app/Import/Importer/CsvImporter.php index db29c244cb..2779fb33cc 100644 --- a/app/Import/Importer/CsvImporter.php +++ b/app/Import/Importer/CsvImporter.php @@ -17,6 +17,7 @@ use FireflyIII\Crud\Account\AccountCrud; use FireflyIII\Import\Converter\ConverterInterface; use FireflyIII\Import\ImportEntry; use FireflyIII\Import\Mapper\MapperInterface; +use FireflyIII\Import\MapperPreProcess\PreProcessorInterface; use FireflyIII\Models\AccountType; use FireflyIII\Models\ImportJob; use Illuminate\Http\Request; @@ -180,16 +181,23 @@ class CsvImporter implements ImporterInterface public function saveImportConfiguration(array $data, FileBag $files): bool { /** @var AccountCrud $repository */ - $repository = app(AccountCrud::class); - $account = $repository->find(intval($data['csv_import_account'])); + $repository = app(AccountCrud::class, [auth()->user()]); + $account = $repository->find(intval($data['csv_import_account'])); + $hasHeaders = isset($data['has_headers']) && intval($data['has_headers']) === 1 ? true : false; $config = $this->job->configuration; $config['has-headers'] = $hasHeaders; $config['date-format'] = $data['date_format']; $config['delimiter'] = $data['csv_delimiter']; + Log::debug('Entered import account.', ['id' => $data['csv_import_account']]); + + if (!is_null($account->id)) { + Log::debug('Found account.', ['id' => $account->id, 'name' => $account->name]); $config['import-account'] = $account->id; + } else { + Log::error('Could not find anything for csv_import_account.', ['id' => $data['csv_import_account']]); } // loop specifics. if (isset($data['specifics']) && is_array($data['specifics'])) { @@ -335,21 +343,28 @@ class CsvImporter implements ImporterInterface foreach ($config['column-do-mapping'] as $index => $mustBeMapped) { if ($mustBeMapped) { - $column = $config['column-roles'][$index] ?? '_ignore'; - $canBeMapped = config('csv.import_roles.' . $column . '.mappable'); + $column = $config['column-roles'][$index] ?? '_ignore'; + $canBeMapped = config('csv.import_roles.' . $column . '.mappable'); + $preProcessMap = config('csv.import_roles.' . $column . '.pre-process-map'); if ($canBeMapped) { $mapperName = '\FireflyIII\Import\Mapper\\' . config('csv.import_roles.' . $column . '.mapper'); /** @var MapperInterface $mapper */ $mapper = new $mapperName; $indexes[] = $index; $data[$index] = [ - 'name' => $column, - 'mapper' => $mapperName, - 'index' => $index, - 'options' => $mapper->getMap(), - 'values' => [], + 'name' => $column, + 'mapper' => $mapperName, + 'index' => $index, + 'options' => $mapper->getMap(), + 'preProcessMap' => null, + 'values' => [], ]; + if ($preProcessMap) { + $data[$index]['preProcessMap'] = '\FireflyIII\Import\MapperPreProcess\\' . + config('csv.import_roles.' . $column . '.pre-process-mapper'); + } } + } } @@ -358,12 +373,29 @@ class CsvImporter implements ImporterInterface $reader = Reader::createFromString($content); $results = $reader->fetch(); - foreach ($results as $row) { + foreach ($results as $rowIndex => $row) { //do something here - foreach ($indexes as $index) { + foreach ($indexes as $index) { // this is simply 1, 2, 3, etc. $value = $row[$index]; if (strlen($value) > 0) { - $data[$index]['values'][] = $row[$index]; + + // we can do some preprocessing here, + // which is exclusively to fix the tags: + if (!is_null($data[$index]['preProcessMap'])) { + /** @var PreProcessorInterface $preProcessor */ + $preProcessor = app($data[$index]['preProcessMap']); + $result = $preProcessor->run($value); + $data[$index]['values'] = array_merge($data[$index]['values'], $result); + + Log::debug($rowIndex . ':' . $index . 'Value before preprocessor', ['value' => $value]); + Log::debug($rowIndex . ':' . $index . 'Value after preprocessor', ['value-new' => $result]); + Log::debug($rowIndex . ':' . $index . 'Value after joining', ['value-complete' => $data[$index]['values']]); + + + continue; + } + + $data[$index]['values'][] = $value; } } } diff --git a/app/Import/MapperPreProcess/PreProcessorInterface.php b/app/Import/MapperPreProcess/PreProcessorInterface.php new file mode 100644 index 0000000000..d577b90cc7 --- /dev/null +++ b/app/Import/MapperPreProcess/PreProcessorInterface.php @@ -0,0 +1,28 @@ +auth->check()) { - return app('FireflyIII\Repositories\Account\AccountRepository', [$app->auth->user()]); + return app('FireflyIII\Repositories\Account\AccountRepository', [auth()->user()]); } if (!isset($arguments[0]) && !$app->auth->check()) { throw new FireflyException('There is no user present.'); diff --git a/app/Providers/AttachmentServiceProvider.php b/app/Providers/AttachmentServiceProvider.php index bee83cf88c..0cd70ecc90 100644 --- a/app/Providers/AttachmentServiceProvider.php +++ b/app/Providers/AttachmentServiceProvider.php @@ -44,7 +44,7 @@ class AttachmentServiceProvider extends ServiceProvider 'FireflyIII\Repositories\Attachment\AttachmentRepositoryInterface', function (Application $app, array $arguments) { if (!isset($arguments[0]) && $app->auth->check()) { - return app('FireflyIII\Repositories\Attachment\AttachmentRepository', [$app->auth->user()]); + return app('FireflyIII\Repositories\Attachment\AttachmentRepository', [auth()->user()]); } if (!isset($arguments[0]) && !$app->auth->check()) { throw new FireflyException('There is no user present.'); diff --git a/app/Providers/BillServiceProvider.php b/app/Providers/BillServiceProvider.php index 289d712094..20bdd0f6bc 100644 --- a/app/Providers/BillServiceProvider.php +++ b/app/Providers/BillServiceProvider.php @@ -44,7 +44,7 @@ class BillServiceProvider extends ServiceProvider 'FireflyIII\Repositories\Bill\BillRepositoryInterface', function (Application $app, array $arguments) { if (!isset($arguments[0]) && $app->auth->check()) { - return app('FireflyIII\Repositories\Bill\BillRepository', [$app->auth->user()]); + return app('FireflyIII\Repositories\Bill\BillRepository', [auth()->user()]); } if (!isset($arguments[0]) && !$app->auth->check()) { throw new FireflyException('There is no user present.'); diff --git a/app/Providers/BudgetServiceProvider.php b/app/Providers/BudgetServiceProvider.php index afd73a846b..aa7f6687f3 100644 --- a/app/Providers/BudgetServiceProvider.php +++ b/app/Providers/BudgetServiceProvider.php @@ -44,7 +44,7 @@ class BudgetServiceProvider extends ServiceProvider 'FireflyIII\Repositories\Budget\BudgetRepositoryInterface', function (Application $app, array $arguments) { if (!isset($arguments[0]) && $app->auth->check()) { - return app('FireflyIII\Repositories\Budget\BudgetRepository', [$app->auth->user()]); + return app('FireflyIII\Repositories\Budget\BudgetRepository', [auth()->user()]); } if (!isset($arguments[0]) && !$app->auth->check()) { throw new FireflyException('There is no user present.'); diff --git a/app/Providers/CategoryServiceProvider.php b/app/Providers/CategoryServiceProvider.php index 5adab5c229..fbea960b60 100644 --- a/app/Providers/CategoryServiceProvider.php +++ b/app/Providers/CategoryServiceProvider.php @@ -44,7 +44,7 @@ class CategoryServiceProvider extends ServiceProvider 'FireflyIII\Repositories\Category\CategoryRepositoryInterface', function (Application $app, array $arguments) { if (!isset($arguments[0]) && $app->auth->check()) { - return app('FireflyIII\Repositories\Category\CategoryRepository', [$app->auth->user()]); + return app('FireflyIII\Repositories\Category\CategoryRepository', [auth()->user()]); } if (!isset($arguments[0]) && !$app->auth->check()) { throw new FireflyException('There is no user present.'); diff --git a/app/Providers/CrudServiceProvider.php b/app/Providers/CrudServiceProvider.php index 0117cf78a5..cfb30450e3 100644 --- a/app/Providers/CrudServiceProvider.php +++ b/app/Providers/CrudServiceProvider.php @@ -12,8 +12,10 @@ declare(strict_types = 1); namespace FireflyIII\Providers; use FireflyIII\Exceptions\FireflyException; +use Illuminate\Auth\AuthManager; use Illuminate\Foundation\Application; use Illuminate\Support\ServiceProvider; +use Log; /** * Class CrudServiceProvider @@ -49,12 +51,14 @@ class CrudServiceProvider extends ServiceProvider $this->app->bind( 'FireflyIII\Crud\Account\AccountCrudInterface', function (Application $app, array $arguments) { - if (!isset($arguments[0]) && $app->auth->check()) { - return app('FireflyIII\Crud\Account\AccountCrud', [$app->auth->user()]); + + if (!isset($arguments[0]) && auth()->check()) { + return app('FireflyIII\Crud\Account\AccountCrud', [auth()->user()]); } if (!isset($arguments[0]) && !$app->auth->check()) { throw new FireflyException('There is no user present.'); } + Log::debug('AccountCrud constructor, run with default arguments.', $arguments); return app('FireflyIII\Crud\Account\AccountCrud', $arguments); } @@ -67,7 +71,7 @@ class CrudServiceProvider extends ServiceProvider 'FireflyIII\Crud\Split\JournalInterface', function (Application $app, array $arguments) { if (!isset($arguments[0]) && $app->auth->check()) { - return app('FireflyIII\Crud\Split\Journal', [$app->auth->user()]); + return app('FireflyIII\Crud\Split\Journal', [auth()->user()]); } if (!isset($arguments[0]) && !$app->auth->check()) { throw new FireflyException('There is no user present.'); diff --git a/app/Providers/ExportJobServiceProvider.php b/app/Providers/ExportJobServiceProvider.php index f39e24cd1e..cd908bc969 100644 --- a/app/Providers/ExportJobServiceProvider.php +++ b/app/Providers/ExportJobServiceProvider.php @@ -56,7 +56,7 @@ class ExportJobServiceProvider extends ServiceProvider 'FireflyIII\Repositories\ExportJob\ExportJobRepositoryInterface', function (Application $app, array $arguments) { if (!isset($arguments[0]) && $app->auth->check()) { - return app('FireflyIII\Repositories\ExportJob\ExportJobRepository', [$app->auth->user()]); + return app('FireflyIII\Repositories\ExportJob\ExportJobRepository', [auth()->user()]); } if (!isset($arguments[0]) && !$app->auth->check()) { throw new FireflyException('There is no user present.'); @@ -73,7 +73,7 @@ class ExportJobServiceProvider extends ServiceProvider 'FireflyIII\Repositories\ImportJob\ImportJobRepositoryInterface', function (Application $app, array $arguments) { if (!isset($arguments[0]) && $app->auth->check()) { - return app('FireflyIII\Repositories\ImportJob\ImportJobRepository', [$app->auth->user()]); + return app('FireflyIII\Repositories\ImportJob\ImportJobRepository', [auth()->user()]); } if (!isset($arguments[0]) && !$app->auth->check()) { throw new FireflyException('There is no user present.'); diff --git a/app/Providers/JournalServiceProvider.php b/app/Providers/JournalServiceProvider.php index db50c23499..4e82de187e 100644 --- a/app/Providers/JournalServiceProvider.php +++ b/app/Providers/JournalServiceProvider.php @@ -44,7 +44,7 @@ class JournalServiceProvider extends ServiceProvider 'FireflyIII\Repositories\Journal\JournalRepositoryInterface', function (Application $app, array $arguments) { if (!isset($arguments[0]) && $app->auth->check()) { - return app('FireflyIII\Repositories\Journal\JournalRepository', [$app->auth->user()]); + return app('FireflyIII\Repositories\Journal\JournalRepository', [auth()->user()]); } if (!isset($arguments[0]) && !$app->auth->check()) { throw new FireflyException('There is no user present.'); diff --git a/app/Providers/PiggyBankServiceProvider.php b/app/Providers/PiggyBankServiceProvider.php index 14aa3353af..d662698511 100644 --- a/app/Providers/PiggyBankServiceProvider.php +++ b/app/Providers/PiggyBankServiceProvider.php @@ -45,7 +45,7 @@ class PiggyBankServiceProvider extends ServiceProvider 'FireflyIII\Repositories\PiggyBank\PiggyBankRepositoryInterface', function (Application $app, array $arguments) { if (!isset($arguments[0]) && $app->auth->check()) { - return app('FireflyIII\Repositories\PiggyBank\PiggyBankRepository', [$app->auth->user()]); + return app('FireflyIII\Repositories\PiggyBank\PiggyBankRepository', [auth()->user()]); } if (!isset($arguments[0]) && !$app->auth->check()) { throw new FireflyException('There is no user present.'); diff --git a/app/Providers/RuleGroupServiceProvider.php b/app/Providers/RuleGroupServiceProvider.php index 7536006145..4cff99454f 100644 --- a/app/Providers/RuleGroupServiceProvider.php +++ b/app/Providers/RuleGroupServiceProvider.php @@ -45,7 +45,7 @@ class RuleGroupServiceProvider extends ServiceProvider 'FireflyIII\Repositories\RuleGroup\RuleGroupRepositoryInterface', function (Application $app, array $arguments) { if (!isset($arguments[0]) && $app->auth->check()) { - return app('FireflyIII\Repositories\RuleGroup\RuleGroupRepository', [$app->auth->user()]); + return app('FireflyIII\Repositories\RuleGroup\RuleGroupRepository', [auth()->user()]); } if (!isset($arguments[0]) && !$app->auth->check()) { throw new FireflyException('There is no user present.'); diff --git a/app/Providers/RuleServiceProvider.php b/app/Providers/RuleServiceProvider.php index 2a416fcea0..14d3163a53 100644 --- a/app/Providers/RuleServiceProvider.php +++ b/app/Providers/RuleServiceProvider.php @@ -44,7 +44,7 @@ class RuleServiceProvider extends ServiceProvider 'FireflyIII\Repositories\Rule\RuleRepositoryInterface', function (Application $app, array $arguments) { if (!isset($arguments[0]) && $app->auth->check()) { - return app('FireflyIII\Repositories\Rule\RuleRepository', [$app->auth->user()]); + return app('FireflyIII\Repositories\Rule\RuleRepository', [auth()->user()]); } if (!isset($arguments[0]) && !$app->auth->check()) { throw new FireflyException('There is no user present.'); diff --git a/app/Providers/TagServiceProvider.php b/app/Providers/TagServiceProvider.php index 51e4a16e45..34ef48591a 100644 --- a/app/Providers/TagServiceProvider.php +++ b/app/Providers/TagServiceProvider.php @@ -44,7 +44,7 @@ class TagServiceProvider extends ServiceProvider 'FireflyIII\Repositories\Tag\TagRepositoryInterface', function (Application $app, array $arguments) { if (!isset($arguments[0]) && $app->auth->check()) { - return app('FireflyIII\Repositories\Tag\TagRepository', [$app->auth->user()]); + return app('FireflyIII\Repositories\Tag\TagRepository', [auth()->user()]); } if (!isset($arguments[0]) && !$app->auth->check()) { throw new FireflyException('There is no user present.'); diff --git a/app/Repositories/Bill/BillRepository.php b/app/Repositories/Bill/BillRepository.php index 43aabe96cf..6ea9f802af 100644 --- a/app/Repositories/Bill/BillRepository.php +++ b/app/Repositories/Bill/BillRepository.php @@ -72,6 +72,27 @@ class BillRepository implements BillRepositoryInterface return $bill; } + /** + * Find a bill by name. + * + * @param string $name + * + * @return Bill + */ + public function findByName(string $name) : Bill + { + $bills = $this->user->bills()->get(); + + /** @var Bill $bill */ + foreach ($bills as $bill) { + if ($bill->name === $name) { + return $bill; + } + } + + return new Bill; + } + /** * @return Collection */ @@ -293,6 +314,28 @@ class BillRepository implements BillRepositoryInterface return $bill->transactionjournals()->before($end)->after($start)->get(); } + /** + * @param $bill + * + * @return string + */ + public function getOverallAverage($bill): string + { + $journals = $bill->transactionjournals()->get(); + $sum = '0'; + $count = strval($journals->count()); + /** @var TransactionJournal $journal */ + foreach ($journals as $journal) { + $sum = bcadd($sum, TransactionJournal::amountPositive($journal)); + } + $avg = '0'; + if ($journals->count() > 0) { + $avg = bcdiv($sum, $count); + } + + return $avg; + } + /** * @param Bill $bill * @@ -358,6 +401,32 @@ class BillRepository implements BillRepositoryInterface return $validRanges; } + /** + * @param Bill $bill + * @param Carbon $date + * + * @return string + */ + public function getYearAverage(Bill $bill, Carbon $date): string + { + $journals = $bill->transactionjournals() + ->where('date', '>=', $date->year . '-01-01') + ->where('date', '<=', $date->year . '-12-31') + ->get(); + $sum = '0'; + $count = strval($journals->count()); + /** @var TransactionJournal $journal */ + foreach ($journals as $journal) { + $sum = bcadd($sum, TransactionJournal::amountPositive($journal)); + } + $avg = '0'; + if ($journals->count() > 0) { + $avg = bcdiv($sum, $count); + } + + return $avg; + } + /** * @param Bill $bill * @@ -557,52 +626,4 @@ class BillRepository implements BillRepositoryInterface return $wordMatch; } - - /** - * @param Bill $bill - * @param Carbon $date - * - * @return string - */ - public function getYearAverage(Bill $bill, Carbon $date): string - { - $journals = $bill->transactionjournals() - ->where('date', '>=', $date->year . '-01-01') - ->where('date', '<=', $date->year . '-12-31') - ->get(); - $sum = '0'; - $count = strval($journals->count()); - /** @var TransactionJournal $journal */ - foreach ($journals as $journal) { - $sum = bcadd($sum, TransactionJournal::amountPositive($journal)); - } - $avg = '0'; - if ($journals->count() > 0) { - $avg = bcdiv($sum, $count); - } - - return $avg; - } - - /** - * @param $bill - * - * @return string - */ - public function getOverallAverage($bill): string - { - $journals = $bill->transactionjournals()->get(); - $sum = '0'; - $count = strval($journals->count()); - /** @var TransactionJournal $journal */ - foreach ($journals as $journal) { - $sum = bcadd($sum, TransactionJournal::amountPositive($journal)); - } - $avg = '0'; - if ($journals->count() > 0) { - $avg = bcdiv($sum, $count); - } - - return $avg; - } } diff --git a/app/Repositories/Bill/BillRepositoryInterface.php b/app/Repositories/Bill/BillRepositoryInterface.php index 494b4d2d7f..ff28c7b521 100644 --- a/app/Repositories/Bill/BillRepositoryInterface.php +++ b/app/Repositories/Bill/BillRepositoryInterface.php @@ -32,21 +32,6 @@ interface BillRepositoryInterface */ public function destroy(Bill $bill): bool; - /** - * @param Bill $bill - * @param Carbon $date - * - * @return string - */ - public function getYearAverage(Bill $bill, Carbon $date): string; - - /** - * @param $bill - * - * @return string - */ - public function getOverallAverage($bill): string; - /** * Find a bill by ID. * @@ -56,6 +41,15 @@ interface BillRepositoryInterface */ public function find(int $billId) : Bill; + /** + * Find a bill by name. + * + * @param string $name + * + * @return Bill + */ + public function findByName(string $name) : Bill; + /** * @return Collection */ @@ -128,6 +122,13 @@ interface BillRepositoryInterface */ public function getJournalsInRange(Bill $bill, Carbon $start, Carbon $end): Collection; + /** + * @param $bill + * + * @return string + */ + public function getOverallAverage($bill): string; + /** * @param Bill $bill * @@ -148,6 +149,14 @@ interface BillRepositoryInterface */ public function getRanges(Bill $bill, Carbon $start, Carbon $end): array; + /** + * @param Bill $bill + * @param Carbon $date + * + * @return string + */ + public function getYearAverage(Bill $bill, Carbon $date): string; + /** * @param Bill $bill * diff --git a/config/app.php b/config/app.php index 79a9e67ed6..7e3766d118 100644 --- a/config/app.php +++ b/config/app.php @@ -152,21 +152,6 @@ return [ Collective\Html\HtmlServiceProvider::class, - /* - * More service providers. - */ - FireflyIII\Providers\CrudServiceProvider::class, - FireflyIII\Providers\AccountServiceProvider::class, - FireflyIII\Providers\AttachmentServiceProvider::class, - FireflyIII\Providers\BillServiceProvider::class, - FireflyIII\Providers\BudgetServiceProvider::class, - FireflyIII\Providers\CategoryServiceProvider::class, - FireflyIII\Providers\ExportJobServiceProvider::class, - FireflyIII\Providers\JournalServiceProvider::class, - FireflyIII\Providers\PiggyBankServiceProvider::class, - FireflyIII\Providers\RuleServiceProvider::class, - FireflyIII\Providers\RuleGroupServiceProvider::class, - FireflyIII\Providers\TagServiceProvider::class, /* @@ -186,6 +171,24 @@ return [ 'TwigBridge\ServiceProvider', 'PragmaRX\Google2FA\Vendor\Laravel\ServiceProvider', + + /* + * More service providers. + */ + FireflyIII\Providers\CrudServiceProvider::class, + FireflyIII\Providers\AccountServiceProvider::class, + FireflyIII\Providers\AttachmentServiceProvider::class, + FireflyIII\Providers\BillServiceProvider::class, + FireflyIII\Providers\BudgetServiceProvider::class, + FireflyIII\Providers\CategoryServiceProvider::class, + FireflyIII\Providers\ExportJobServiceProvider::class, + FireflyIII\Providers\JournalServiceProvider::class, + FireflyIII\Providers\PiggyBankServiceProvider::class, + FireflyIII\Providers\RuleServiceProvider::class, + FireflyIII\Providers\RuleGroupServiceProvider::class, + FireflyIII\Providers\TagServiceProvider::class, + + ], /* diff --git a/config/csv.php b/config/csv.php index 707a34b8c4..915b8f724b 100644 --- a/config/csv.php +++ b/config/csv.php @@ -14,179 +14,247 @@ return [ /* * Configuration for possible column roles. + * + * The key is the short name for the column role. There are five values, which mean this: + * + * 'mappable' + * Whether or not the value in the CSV column can be linked to an existing value in your + * Firefly database. For example: account names can be linked to existing account names you have already + * so double entries cannot occur. This process is called "mapping". You have to make each unique value in your + * CSV file to an existing entry in your database. For example, map all account names in your CSV file to existing + * accounts. If you have an entry that does not exist in your database, you can set Firefly to ignore it, and it will + * create it. + * + * 'pre-process-map' + * In the case of tags, there are multiple values in one csv column (for example: "expense groceries snack" in one column). + * This means the content of the column must be "pre processed" aka split in parts so the importer can work with the data. + * + * 'pre-process-mapper' + * This is the class that will actually do the pre-processing. + * + * 'field' + * I don't believe this value is used any more, but I am not sure. + * + * 'converter' + * The converter is a class in app/Import/Converter that converts the given value into an object Firefly understands. + * The CategoryName converter can convert a category name into an actual category. This converter will take a mapping + * into account: if you mapped "Groceries" to category "Groceries" the converter will simply return "Groceries" instead of + * trying to make a new category also named Groceries. + * + * 'mapper' + * When you map data (see "mappable") you need a list of stuff you can map to. If you say a certain column is mappable + * and the column contains "category names", the mapper will be "Category" and it will give you a list of possible categories. + * This way the importer always presents you with a valid list of things to map to. + * + * + * */ 'import_roles' => [ '_ignore' => [ - 'mappable' => false, - 'field' => 'ignored', - 'converter' => 'Ignore', + 'mappable' => false, + 'pre-process-map' => false, + 'field' => 'ignored', + 'converter' => 'Ignore', + 'mapper' => null, + ], 'bill-id' => [ - 'mappable' => false, - 'field' => 'bill', - 'converter' => 'BillId', - 'mapper' => 'Bills', + 'mappable' => false, + 'pre-process-map' => false, + 'field' => 'bill', + 'converter' => 'BillId', + 'mapper' => 'Bills', ], 'bill-name' => [ - 'mappable' => true, - 'field' => 'bill', - 'converter' => 'BillName', - 'mapper' => 'Bills', + 'mappable' => true, + 'pre-process-map' => false, + 'field' => 'bill', + 'converter' => 'BillName', + 'mapper' => 'Bills', ], 'currency-id' => [ - 'mappable' => true, - 'field' => 'currency', - 'converter' => 'CurrencyId', - 'mapper' => 'TransactionCurrencies', + 'mappable' => true, + 'pre-process-map' => false, + 'field' => 'currency', + 'converter' => 'CurrencyId', + 'mapper' => 'TransactionCurrencies', ], 'currency-name' => [ - 'mappable' => true, - 'converter' => 'CurrencyName', - 'field' => 'currency', - 'mapper' => 'TransactionCurrencies', + 'mappable' => true, + 'pre-process-map' => false, + 'converter' => 'CurrencyName', + 'field' => 'currency', + 'mapper' => 'TransactionCurrencies', ], 'currency-code' => [ - 'mappable' => true, - 'converter' => 'CurrencyCode', - 'field' => 'currency', - 'mapper' => 'TransactionCurrencies', + 'mappable' => true, + 'pre-process-map' => false, + 'converter' => 'CurrencyCode', + 'field' => 'currency', + 'mapper' => 'TransactionCurrencies', ], 'currency-symbol' => [ - 'mappable' => true, - 'converter' => 'CurrencySymbol', - 'field' => 'currency', - 'mapper' => 'TransactionCurrencies', + 'mappable' => true, + 'pre-process-map' => false, + 'converter' => 'CurrencySymbol', + 'field' => 'currency', + 'mapper' => 'TransactionCurrencies', ], 'description' => [ - 'mappable' => false, - 'converter' => 'Description', - 'field' => 'description', + 'mappable' => false, + 'pre-process-map' => false, + 'converter' => 'Description', + 'field' => 'description', ], 'date-transaction' => [ - 'mappable' => false, - 'converter' => 'Date', - 'field' => 'date', + 'mappable' => false, + 'pre-process-map' => false, + 'converter' => 'Date', + 'field' => 'date', ], 'date-rent' => [ - 'mappable' => false, - 'converter' => 'Date', - 'field' => 'date-rent', + 'mappable' => false, + 'pre-process-map' => false, + 'converter' => 'Date', + 'field' => 'date-rent', ], 'budget-id' => [ - 'mappable' => true, - 'converter' => 'BudgetId', - 'field' => 'budget', - 'mapper' => 'Budgets', + 'mappable' => true, + 'pre-process-map' => false, + 'converter' => 'BudgetId', + 'field' => 'budget', + 'mapper' => 'Budgets', ], 'budget-name' => [ - 'mappable' => true, - 'converter' => 'BudgetName', - 'field' => 'budget', - 'mapper' => 'Budgets', + 'mappable' => true, + 'pre-process-map' => false, + 'converter' => 'BudgetName', + 'field' => 'budget', + 'mapper' => 'Budgets', ], 'rabo-debet-credit' => [ - 'mappable' => false, - 'converter' => 'RabobankDebetCredit', - 'field' => 'amount-modifier', + 'mappable' => false, + 'pre-process-map' => false, + 'converter' => 'RabobankDebetCredit', + 'field' => 'amount-modifier', ], 'ing-debet-credit' => [ - 'mappable' => false, - 'converter' => 'INGDebetCredit', - 'field' => 'amount-modifier', + 'mappable' => false, + 'pre-process-map' => false, + 'converter' => 'INGDebetCredit', + 'field' => 'amount-modifier', ], 'category-id' => [ - 'mappable' => true, - 'converter' => 'CategoryId', - 'field' => 'category', - 'mapper' => 'Categories', + 'mappable' => true, + 'pre-process-map' => false, + 'converter' => 'CategoryId', + 'field' => 'category', + 'mapper' => 'Categories', ], 'category-name' => [ - 'mappable' => true, - 'converter' => 'CategoryName', - 'field' => 'category', - 'mapper' => 'Categories', + 'mappable' => true, + 'pre-process-map' => false, + 'converter' => 'CategoryName', + 'field' => 'category', + 'mapper' => 'Categories', ], 'tags-comma' => [ - 'mappable' => false, - 'field' => 'tags', - 'converter' => 'TagsComma', - 'mapper' => 'Tags', + 'mappable' => true, + 'pre-process-map' => true, + 'pre-process-mapper' => 'TagsComma', + 'field' => 'tags', + 'converter' => 'TagsComma', + 'mapper' => 'Tags', ], 'tags-space' => [ - 'mappable' => false, - 'field' => 'tags', - 'converter' => 'TagsSpace', - 'mapper' => 'Tags', + 'mappable' => true, + 'pre-process-map' => true, + 'pre-process-mapper' => 'TagsSpace', + 'field' => 'tags', + 'converter' => 'TagsSpace', + 'mapper' => 'Tags', ], 'account-id' => [ - 'mappable' => true, - 'field' => 'asset-account-id', - 'converter' => 'AssetAccountId', - 'mapper' => 'AssetAccounts', + 'mappable' => true, + 'pre-process-map' => false, + 'field' => 'asset-account-id', + 'converter' => 'AssetAccountId', + 'mapper' => 'AssetAccounts', ], 'account-name' => [ - 'mappable' => true, - 'field' => 'asset-account-name', - 'converter' => 'AssetAccountName', - 'mapper' => 'AssetAccounts', + 'mappable' => true, + 'pre-process-map' => false, + 'field' => 'asset-account-name', + 'converter' => 'AssetAccountName', + 'mapper' => 'AssetAccounts', ], 'account-iban' => [ - 'mappable' => true, - 'field' => 'asset-account-iban', - 'converter' => 'AssetAccountIban', - 'mapper' => 'AssetAccountIbans', + 'mappable' => true, + 'pre-process-map' => false, + 'field' => 'asset-account-iban', + 'converter' => 'AssetAccountIban', + 'mapper' => 'AssetAccountIbans', ], 'account-number' => [ - 'mappable' => true, - 'field' => 'asset-account-number', - 'converter' => 'AssetAccountNumber', - 'mapper' => 'AssetAccounts', + 'mappable' => true, + 'pre-process-map' => false, + 'field' => 'asset-account-number', + 'converter' => 'AssetAccountNumber', + 'mapper' => 'AssetAccounts', ], 'opposing-id' => [ - 'mappable' => true, - 'field' => 'opposing-account-id', - 'converter' => 'OpposingAccountId', - 'mapper' => 'OpposingAccounts', + 'mappable' => true, + 'pre-process-map' => false, + 'field' => 'opposing-account-id', + 'converter' => 'OpposingAccountId', + 'mapper' => 'OpposingAccounts', ], 'opposing-name' => [ - 'mappable' => true, - 'field' => 'opposing-account-name', - 'converter' => 'OpposingAccountName', - 'mapper' => 'OpposingAccounts', + 'mappable' => true, + 'pre-process-map' => false, + 'field' => 'opposing-account-name', + 'converter' => 'OpposingAccountName', + 'mapper' => 'OpposingAccounts', ], 'opposing-iban' => [ - 'mappable' => true, - 'field' => 'opposing-account-iban', - 'converter' => 'OpposingAccountIban', - 'mapper' => 'OpposingAccountIbans', + 'mappable' => true, + 'pre-process-map' => false, + 'field' => 'opposing-account-iban', + 'converter' => 'OpposingAccountIban', + 'mapper' => 'OpposingAccountIbans', ], 'opposing-number' => [ - 'mappable' => true, - 'field' => 'opposing-account-number', - 'converter' => 'OpposingAccountNumber', - 'mapper' => 'OpposingAccounts', + 'mappable' => true, + 'pre-process-map' => false, + 'field' => 'opposing-account-number', + 'converter' => 'OpposingAccountNumber', + 'mapper' => 'OpposingAccounts', ], 'amount' => [ - 'mappable' => false, - 'converter' => 'Amount', - 'field' => 'amount', + 'mappable' => false, + 'pre-process-map' => false, + 'converter' => 'Amount', + 'field' => 'amount', ], 'sepa-ct-id' => [ - 'mappable' => false, - 'converter' => 'Description', - 'field' => 'description', + 'mappable' => false, + 'pre-process-map' => false, + 'converter' => 'Description', + 'field' => 'description', ], 'sepa-ct-op' => [ - 'mappable' => false, - 'converter' => 'Description', - 'field' => 'description', + 'mappable' => false, + 'pre-process-map' => false, + 'converter' => 'Description', + 'field' => 'description', ], 'sepa-db' => [ - 'mappable' => false, - 'converter' => 'Description', - 'field' => 'description', + 'mappable' => false, + 'pre-process-map' => false, + 'converter' => 'Description', + 'field' => 'description', ], ], diff --git a/resources/views/import/csv/configure.twig b/resources/views/import/csv/configure.twig index fd3949e778..7dccd35ede 100644 --- a/resources/views/import/csv/configure.twig +++ b/resources/views/import/csv/configure.twig @@ -38,7 +38,7 @@ {{ ExpandedForm.checkbox('has_headers',1,job.configuration['has-headers'],{helpText: trans('csv.header_help')}) }} {{ ExpandedForm.text('date_format',job.configuration['date-format'],{helpText: trans('csv.date_help', {dateExample: phpdate('Ymd')}) }) }} {{ ExpandedForm.select('csv_delimiter', data.delimiters, job.configuration['delimiter'], {helpText: trans('csv.delimiter_help') } ) }} - {{ ExpandedForm.select('csv_import_account', data.accounts, 0, {helpText: trans('csv.import_account_help')} ) }} + {{ ExpandedForm.select('csv_import_account', data.accounts, job.configuration['import-account'], {helpText: trans('csv.import_account_help')} ) }} {% for type, specific in data.specifics %}