Compare commits

...

111 Commits
3.9.0 ... 3.10

Author SHA1 Message Date
James Cole
9cac7d46c0 Merge branch 'release/3.10' 2016-08-12 16:03:30 +02:00
James Cole
99b3e24836 Code optimalization 2016-08-12 15:50:52 +02:00
James Cole
ffb699cb06 Clean up code. 2016-08-12 15:34:15 +02:00
James Cole
2947ec0002 Small optimisations. 2016-08-12 15:27:44 +02:00
James Cole
5c4d010bde Code cleanup. 2016-08-12 15:10:03 +02:00
James Cole
955306d877 Remove travis file and fix NULL error in sqlite. 2016-08-12 14:50:25 +02:00
James Cole
015935ed55 Implemented ABN Amro specific import code. 2016-08-12 12:55:52 +02:00
James Cole
48f4cceb19 Mention new version. 2016-08-12 10:47:09 +02:00
James Cole
9850220aac Add new languages. 2016-08-12 10:46:22 +02:00
James Cole
c4ac1460f0 Expanded translations 2016-08-12 10:44:27 +02:00
James Cole
b9e1e01337 New translations. 2016-08-12 10:34:45 +02:00
James Cole
76649cb7de Extended views and language. 2016-08-12 10:07:53 +02:00
James Cole
5e310776b4 New change log 2016-08-12 09:50:54 +02:00
James Cole
4d7fa11172 Upgrade instructions for 3.10 2016-08-12 09:35:09 +02:00
James Cole
28962007c1 More code for new importer 2016-08-12 09:27:09 +02:00
James Cole
2111873bcf Fixed a bug in tag creation. 2016-08-11 19:01:23 +02:00
James Cole
0aaf9a6fda Extend rule set for import. 2016-08-11 18:44:11 +02:00
James Cole
186b704509 Lots of new code to test the import routine.
Signed-off-by: James Cole <thegrumpydictator@gmail.com>
2016-08-11 10:21:32 +02:00
James Cole
efe9933721 Import storage routine is creating the first transaction journals.
Signed-off-by: James Cole <thegrumpydictator@gmail.com>
2016-08-11 08:00:02 +02:00
James Cole
200366f5be Extended the validator and created more code to handle exceptions.
Signed-off-by: James Cole <thegrumpydictator@gmail.com>
2016-08-10 18:49:16 +02:00
James Cole
c9bd72337d Some notes on the import process. 2016-08-06 09:31:32 +02:00
James Cole
d4510440b8 Split the importer and the setup routine. 2016-08-06 06:28:21 +02:00
James Cole
5a9cf698f7 Configuration for import routine. 2016-08-06 06:21:46 +02:00
James Cole
5826fec519 Some new import stuff. 2016-08-06 06:21:25 +02:00
James Cole
7035600984 Add some logging for #283 2016-08-05 21:50:49 +02:00
James Cole
b1dfb5811f Merge pull request #286 from niekvanderkooy/develop
Generalise Steam::phpBytes
2016-08-05 21:42:40 +02:00
Niek van der Kooy
51570a5d08 Allow phpBytes to work with configs where gigabyte file sizes are allowed 2016-08-05 20:54:59 +02:00
Niek van der Kooy
f065f3a0b8 Make phpBytes case insensitive, since php.ini can contain both capitals and small letters 2016-08-05 20:53:09 +02:00
James Cole
47376f1f35 Fix a problem mentioned in issue #283
Signed-off-by: James Cole <thegrumpydictator@gmail.com>
2016-08-05 19:29:44 +02:00
James Cole
bcfe2c6410 Fixes #284
Signed-off-by: James Cole <thegrumpydictator@gmail.com>
2016-08-05 18:52:16 +02:00
James Cole
09d63b584d Save old data; bread crumbs 2016-08-04 06:14:08 +02:00
James Cole
5f5469a7d4 Moved some files around. 2016-08-04 06:10:30 +02:00
James Cole
38800d61b0 New user related code. 2016-08-04 06:07:53 +02:00
James Cole
1186e95c51 Admin view will show some IP addresses.
Signed-off-by: James Cole <thegrumpydictator@gmail.com>
2016-08-03 20:57:01 +02:00
James Cole
d870e0f42e Fix split query. 2016-08-02 19:42:41 +02:00
James Cole
0db9852769 This should fix a bug in split expenses. 2016-08-02 19:12:18 +02:00
James Cole
7e3f9048fe Fixed some fields in split thing. 2016-08-01 20:14:23 +02:00
James Cole
1ba88f182b Various CSV bugs and a config bug fixed. 2016-07-31 17:17:45 +02:00
James Cole
c8f5a6b7ad Ignore deleted columns. 2016-07-30 20:04:24 +02:00
James Cole
d26bbf3cdc Handling import values. This is a dead end but it seemed a good idea. 2016-07-30 19:09:58 +02:00
James Cole
0de72b6914 Ignore result.html 2016-07-30 16:29:49 +02:00
James Cole
e41c89bd59 Does not belong. 2016-07-30 16:29:17 +02:00
James Cole
541d9ebdd9 Optimised some code. 2016-07-30 16:29:04 +02:00
James Cole
1e724712e0 Bug fix in converter 2016-07-29 21:42:12 +02:00
James Cole
3682467ae3 Each CSV converter can set the certainty of their conversion. 2016-07-29 21:40:58 +02:00
James Cole
7707c81b2d Each CSV converter can set the certainty of their conversion. 2016-07-29 21:29:46 +02:00
James Cole
e434de72a3 Expand fields. 2016-07-26 20:40:46 +02:00
James Cole
ce191fa6d3 Fix split deposit. 2016-07-26 20:26:46 +02:00
James Cole
90865a5284 Fix recursive. 2016-07-24 19:24:02 +02:00
James Cole
684f6e0b5c Don't need these. 2016-07-24 19:07:47 +02:00
James Cole
c287bc139c Check new list. 2016-07-24 18:51:39 +02:00
James Cole
1392275b81 Lots of new code for importer and some preferences. 2016-07-24 18:47:55 +02:00
James Cole
87c0f1d86e More CSV related updates. 2016-07-23 21:37:06 +02:00
James Cole
a4a723cfc6 Fixed import error. 2016-07-20 15:57:42 +02:00
James Cole
921e2c06f4 Beta warning for import thing. 2016-07-20 15:47:30 +02:00
James Cole
cb9433f4b9 This should fix #280 2016-07-17 08:50:22 +02:00
James Cole
1be6af820e No map for tags. 2016-07-17 08:35:04 +02:00
James Cole
3b686b6d1c New but empty converters. 2016-07-16 08:25:39 +02:00
James Cole
697566fe42 New importers. 2016-07-16 07:58:25 +02:00
James Cole
5130ba7ea4 Working IBAN account import thing. 2016-07-15 22:37:47 +02:00
James Cole
c9e46a4dd1 Lots of import related code. 2016-07-15 22:26:08 +02:00
James Cole
f5b3dc36e3 Fix view. 2016-07-05 09:02:01 +02:00
James Cole
f1e8d1cf1e Show bill average. 2016-07-05 08:57:45 +02:00
James Cole
e8e7ab01d2 Merge branch 'develop' of github.com:JC5/firefly-iii into develop 2016-07-04 12:38:22 +02:00
James Cole
9244994233 Fix bug that would report wrong file size to browser. 2016-07-04 12:37:33 +02:00
James Cole
ae768a8525 Works up until actual import. 2016-07-02 23:08:47 +02:00
James Cole
162c762973 First set of data mappers. 2016-07-02 20:40:23 +02:00
James Cole
57b5981904 Fix #266 for period-chart. 2016-07-02 17:42:27 +02:00
James Cole
275d19e71d Fix #266 for all-chart. 2016-07-02 17:39:58 +02:00
James Cole
189b11befa Extra page number check for issue #276 2016-07-02 17:36:46 +02:00
James Cole
a56a5fc228 New code for import routine. 2016-07-02 17:33:57 +02:00
James Cole
cbe3fb73a8 Catch decrypt exceptions. 2016-06-27 16:36:28 +02:00
James Cole
3d58fbebec Should not have committed this. 2016-06-27 16:25:17 +02:00
James Cole
b947ff50ed Fix chart thing. 2016-06-27 16:11:49 +02:00
James Cole
18d2741814 More code for the new CSV import 2016-06-27 15:15:46 +02:00
James Cole
93a54780ab Fixes a bug in the 2FA activation thing. 2016-06-24 21:58:57 +02:00
James Cole
3d201db6fc More code for import. 2016-06-24 14:24:34 +02:00
James Cole
9ffc0936ee Merge branch 'feature/new-csv-import' into develop
# Conflicts:
#	app/Helpers/Csv/Importer.php
2016-06-23 12:15:19 +02:00
James Cole
fbf9e00208 Change preferences info. 2016-06-23 12:08:14 +02:00
James Cole
2c826451d1 Fix delete routine and some NULLs 2016-06-23 12:07:31 +02:00
James Cole
617a5c0606 Fix date range. 2016-06-23 08:01:15 +02:00
James Cole
8331a7e34a Rename stuff. 2016-06-18 07:37:12 +02:00
James Cole
8ee1676f0a New migrations. 2016-06-18 07:36:15 +02:00
James Cole
5dc8620c43 More new migrations. 2016-06-17 14:06:38 +02:00
James Cole
d2733a4df0 First attempt at rewriting all migrations. 2016-06-17 06:03:42 +02:00
James Cole
ae649223d8 Mobile add money to piggy routine 2016-06-16 20:52:59 +02:00
James Cole
6267930938 Work on new chart for year report. 2016-06-16 20:52:30 +02:00
James Cole
bdee8cde77 This fixes #273 2016-06-16 08:04:22 +02:00
James Cole
e63f216905 Fix small bug in reorder routine. 2016-06-15 09:58:33 +02:00
James Cole
ec18165698 Fixed #267 2016-06-11 07:38:30 +02:00
James Cole
307e6a2337 Renamed fields #267 2016-06-11 06:36:46 +02:00
James Cole
b80d8cf774 Move date picker stuff to new method. 2016-06-11 06:33:51 +02:00
James Cole
7a5ef6013a Fix #271 2016-06-11 06:31:56 +02:00
James Cole
13b92c47d9 Translations and fixes. 2016-06-11 06:31:40 +02:00
James Cole
5a79bc0a99 Initial code base for new CSV import. 2016-06-10 21:00:00 +02:00
James Cole
beda6ec3a9 Removed old CSV stuff. 2016-06-10 15:25:24 +02:00
James Cole
c619b8730b Implemented #264 2016-06-07 12:22:46 +02:00
James Cole
c14ec8b006 New change log. 2016-06-07 12:22:30 +02:00
James Cole
10c7786248 Merge branch 'release/3.9.1' 2016-06-06 20:25:55 +02:00
James Cole
08ff08685c Small updates for 3.9.1 2016-06-06 20:25:01 +02:00
James Cole
8091dbfdfa Restore views (#262) 2016-06-06 09:28:35 +02:00
James Cole
8dc106b79a Restore config (#262) 2016-06-06 09:28:25 +02:00
James Cole
7527433738 Restore provider (#262) 2016-06-06 09:25:29 +02:00
James Cole
1502e08a7a Restore routes (#262) 2016-06-06 09:24:51 +02:00
James Cole
c9679f1d4f Restore bread crumbs (#262) 2016-06-06 09:23:55 +02:00
James Cole
6b976dd6b9 Restore controller (#262) 2016-06-06 09:22:28 +02:00
James Cole
8da4abf655 Restore helpers (#262) 2016-06-06 09:22:20 +02:00
James Cole
2e26193333 This should fix #266 2016-05-24 16:08:43 +02:00
James Cole
ada43bc0dd Fix #265 2016-05-24 11:28:24 +02:00
James Cole
a447c886c4 Basic for for #262
Signed-off-by: James Cole <thegrumpydictator@gmail.com>
2016-05-22 21:11:30 +02:00
James Cole
288e713f94 Remove all code related to the CSV importer in preparation of #262
Signed-off-by: James Cole <thegrumpydictator@gmail.com>
2016-05-22 20:18:16 +02:00
331 changed files with 15120 additions and 9305 deletions

View File

@@ -42,5 +42,3 @@ SHOW_DEMO_WARNING=false
ANALYTICS_ID=
RUNCLEANUP=true
SITE_OWNER=mail@example.com
BLOCKED_DOMAINS=

3
.gitignore vendored
View File

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

View File

@@ -1,22 +0,0 @@
language: php
sudo: false
php:
- 7
install:
- phpenv config-rm xdebug.ini
- composer selfupdate
- rm composer.lock
- composer update --no-scripts
- php artisan clear-compiled
- php artisan optimize
- php artisan env
- mv -v .env.testing .env
- php artisan env
- touch storage/upload/at-1.data
- touch storage/upload/at-2.data
- touch storage/database/testing.db
- php artisan migrate --seed
script:
- phpunit

View File

@@ -5,6 +5,48 @@ This project adheres to [Semantic Versioning](http://semver.org/).
## [Unreleased]
- No unreleased changes yet.
## [3.10] - 2015-05-25
### Added
- New charts in year report
- Can add / remove money from piggy bank on mobile device.
- Bill overview shows some useful things.
- Firefly will track registration / activation IP addresses.
### Changed
- Rewrote the import routine.
- The date picker now supports more ranges and periods.
- Rewrote all migrations. #272
### Deprecated
- Initial release.
### Removed
- Initial release.
### Fixed
- Issue #264
- Issue #265
- Fixed amount calculation problems, #266, thanks @xzaz
- Issue #271
- Issue #278, #273, thanks @StevenReitsma and @rubella
- Bug in attachment download routine would report the wrong size to the user's browser.
- Various NULL errors fixed.
- Various strict typing errors fixed.
- Fixed pagination problems, #276, thanks @xzaz
- Fixed a bug where an expense would be assigned to a piggy bank if you created a transfer first.
- Bulk update problems, #280, thanks @stickgrinder
- Fixed various problems with amount reporting of split transactions.
### Security
- Initial release.
[3.9.1]
### Fixed
- Fixed a bug where removing money from a piggy bank would not work. See issue #265 and #269
[3.9.0]
### Added
- @zjean has added code that allows you to force "https://"-URL's.

View File

@@ -0,0 +1,69 @@
<?php
/**
* EncryptFile.php
* Copyright (C) 2016 thegrumpydictator@gmail.com
*
* This software may be modified and distributed under the terms
* of the MIT license. See the LICENSE file for details.
*/
declare(strict_types = 1);
namespace FireflyIII\Console\Commands;
use Crypt;
use Illuminate\Console\Command;
/**
* Class EncryptFile
*
* @package FireflyIII\Console\Commands
*/
class EncryptFile extends Command
{
/**
* The console command description.
*
* @var string
*/
protected $description = 'Encrypts a file and places it in the storage/upload directory.';
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'firefly:encrypt {file} {key}';
/**
* Create a new command instance.
*
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*
* @return mixed
*/
public function handle()
{
$file = e(strval($this->argument('file')));
if (!file_exists($file)) {
$this->error(sprintf('File "%s" does not seem to exist.', $file));
return;
}
$content = file_get_contents($file);
$content = Crypt::encrypt($content);
$newName = e(strval($this->argument('key'))) . '.upload';
$path = storage_path('upload') . '/' . $newName;
file_put_contents($path, $content);
$this->line(sprintf('Encrypted "%s" and put it in "%s"', $file, $path));
}
}

View File

@@ -0,0 +1,113 @@
<?php
/**
* Import.php
* Copyright (C) 2016 thegrumpydictator@gmail.com
*
* This software may be modified and distributed under the terms
* of the MIT license. See the LICENSE file for details.
*/
declare(strict_types = 1);
namespace FireflyIII\Console\Commands;
use FireflyIII\Crud\Account\AccountCrud;
use FireflyIII\Import\Importer\ImporterInterface;
use FireflyIII\Import\ImportStorage;
use FireflyIII\Import\ImportValidator;
use FireflyIII\Import\Logging\CommandHandler;
use FireflyIII\Models\ImportJob;
use Illuminate\Console\Command;
use Log;
/**
* Class Import
*
* @package FireflyIII\Console\Commands
*/
class Import extends Command
{
/**
* The console command description.
*
* @var string
*/
protected $description = 'Import stuff into Firefly III.';
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'firefly:import {key}';
/**
* Create a new command instance.
*
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*
* @return mixed
*/
public function handle()
{
$jobKey = $this->argument('key');
$job = ImportJob::whereKey($jobKey)->first();
if (is_null($job)) {
$this->error('This job does not seem to exist.');
return;
}
if ($job->status != 'settings_complete') {
$this->error('This job is not ready to be imported.');
return;
}
$this->line('Going to import job with key "' . $job->key . '" of type ' . $job->file_type);
$valid = array_keys(config('firefly.import_formats'));
$class = 'INVALID';
if (in_array($job->file_type, $valid)) {
$class = config('firefly.import_formats.' . $job->file_type);
}
/** @var ImporterInterface $importer */
$importer = app($class);
$importer->setJob($job);
// intercept logging by importer.
$monolog = Log::getMonolog();
$handler = new CommandHandler($this);
$monolog->pushHandler($handler);
// create import entries
$collection = $importer->createImportEntries();
// validate / clean collection:
$validator = new ImportValidator($collection);
$validator->setUser($job->user);
if ($job->configuration['import-account'] != 0) {
$repository = app(AccountCrud::class, [$job->user]);
$validator->setDefaultImportAccount($repository->find($job->configuration['import-account']));
}
$cleaned = $validator->clean();
// then import collection:
$storage = new ImportStorage($cleaned);
$storage->setUser($job->user);
// and run store routine:
$storage->store();
$this->line('Something something import: ' . $jobKey);
}
}

View File

@@ -25,7 +25,7 @@ class UpgradeFireflyInstructions extends Command
*
* @var string
*/
protected $description = 'Command description';
protected $description = 'Instructions in case of upgrade trouble.';
/**
* The name and signature of the console command.
*

View File

@@ -11,6 +11,8 @@ declare(strict_types = 1);
namespace FireflyIII\Console;
use FireflyIII\Console\Commands\EncryptFile;
use FireflyIII\Console\Commands\Import;
use FireflyIII\Console\Commands\UpgradeFireflyInstructions;
use FireflyIII\Console\Commands\VerifyDatabase;
use Illuminate\Foundation\Console\Kernel as ConsoleKernel;
@@ -51,5 +53,7 @@ class Kernel extends ConsoleKernel
= [
UpgradeFireflyInstructions::class,
VerifyDatabase::class,
Import::class,
EncryptFile::class,
];
}

View File

@@ -11,6 +11,7 @@ declare(strict_types = 1);
namespace FireflyIII\Crud\Account;
use Carbon\Carbon;
use DB;
use FireflyIII\Models\Account;
use FireflyIII\Models\AccountMeta;
@@ -52,14 +53,17 @@ class AccountCrud implements AccountCrudInterface
*
* @return bool
*/
public function destroy(Account $account, Account $moveTo = null): bool
public function destroy(Account $account, Account $moveTo): bool
{
if (!is_null($moveTo)) {
if (!is_null($moveTo->id)) {
// update all transactions:
DB::table('transactions')->where('account_id', $account->id)->update(['account_id' => $moveTo->id]);
}
if (!is_null($account)) {
Log::debug('Now trigger account delete #' . $account->id);
$account->delete();
}
$account->delete();
return true;
}
@@ -71,14 +75,99 @@ 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)) {
$account = new Account;
return new Account;
}
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(['accounts.*']);
if ($accounts->count() > 0) {
return $accounts->first();
}
return new Account;
}
/**
* @param string $iban
* @param array $types
*
* @return Account
*/
public function findByIban(string $iban, array $types): Account
{
$query = $this->user->accounts()->where('iban', '!=', '');
if (count($types) > 0) {
$query->leftJoin('account_types', 'accounts.account_type_id', '=', 'account_types.id');
$query->whereIn('account_types.type', $types);
}
$accounts = $query->get(['accounts.*']);
/** @var Account $account */
foreach ($accounts as $account) {
if ($account->iban === $iban) {
return $account;
}
}
return new Account;
}
/**
* @param string $name
* @param array $types
*
* @return Account
*/
public function findByName(string $name, array $types): Account
{
$query = $this->user->accounts();
Log::debug('Now in findByName()', ['name' => $name, 'types' => $types]);
if (count($types) > 0) {
$query->leftJoin('account_types', 'accounts.account_type_id', '=', 'account_types.id');
$query->whereIn('account_types.type', $types);
}
$accounts = $query->get(['accounts.*']);
Log::debug(sprintf('Total set count is %d ', $accounts->count()));
/** @var Account $account */
foreach ($accounts as $account) {
if ($account->name === $name) {
Log::debug('Account name is an exact match. ', ['db' => $account->name, 'source' => $name, 'id' => $account->id]);
return $account;
}
}
Log::debug('Found nothing in findByName()', ['name' => $name, 'types' => $types]);
return new Account;
}
/**
* @param array $accountIds
*
@@ -146,25 +235,12 @@ class AccountCrud implements AccountCrudInterface
public function store(array $data): Account
{
$newAccount = $this->storeAccount($data);
if (!is_null($newAccount)) {
if (!is_null($newAccount->id)) {
$this->storeMetadata($newAccount, $data);
}
// continue with the opposing account:
if ($data['openingBalance'] != 0) {
$opposingData = [
'user' => $data['user'],
'accountType' => 'initial',
'virtualBalance' => 0,
'name' => $data['name'] . ' initial balance',
'active' => false,
'iban' => '',
];
$opposing = $this->storeAccount($opposingData);
if (!is_null($opposing) && !is_null($newAccount)) {
$this->storeInitialBalance($newAccount, $opposing, $data);
}
$this->storeInitialBalance($newAccount, $data);
}
return $newAccount;
@@ -199,39 +275,29 @@ class AccountCrud implements AccountCrudInterface
$account->save();
$this->updateMetadata($account, $data);
$openingBalance = $this->openingBalanceTransaction($account);
if ($data['openingBalance'] != 0) {
if (!is_null($openingBalance->id)) {
$this->updateInitialBalance($account, $openingBalance, $data);
return $account;
}
$type = $data['openingBalance'] < 0 ? 'expense' : 'revenue';
$opposingData = [
'user' => $data['user'],
'accountType' => $type,
'name' => $data['name'] . ' initial balance',
'active' => false,
'iban' => '',
'virtualBalance' => 0,
];
$opposing = $this->storeAccount($opposingData);
if (!is_null($opposing)) {
$this->storeInitialBalance($account, $opposing, $data);
}
return $account;
}
if ($openingBalance) { // opening balance is zero, should we delete it?
$openingBalance->delete(); // delete existing opening balance.
}
$this->updateInitialBalance($account, $data);
return $account;
}
/**
* @param Account $account
* @param string $type
*
* @return Account
*/
public function updateAccountType(Account $account, string $type): Account
{
$type = AccountType::whereType($type)->first();
if (!is_null($type)) {
$account->accountType()->associate($type);
$account->save();
}
return $this->find($account->id);
}
/**
* @param array $data
*
@@ -263,8 +329,8 @@ class AccountCrud implements AccountCrudInterface
];
$existingAccount = Account::firstOrNullEncrypted($searchData);
if (!$existingAccount) {
Log::error('Account create error: ' . $newAccount->getErrors()->toJson());
abort(500);
Log::error('Account create error', $newAccount->getErrors()->toArray());
return new Account;
}
$newAccount = $existingAccount;
@@ -276,19 +342,21 @@ class AccountCrud implements AccountCrudInterface
/**
* @param Account $account
* @param Account $opposing
* @param array $data
*
* @return TransactionJournal
*/
protected function storeInitialBalance(Account $account, Account $opposing, array $data): TransactionJournal
protected function storeInitialBalance(Account $account, array $data): TransactionJournal
{
$amount = $data['openingBalance'];
$user = $data['user'];
$name = $data['name'];
$opposing = $this->storeOpposingAccount($amount, $user, $name);
$transactionType = TransactionType::whereType(TransactionType::OPENING_BALANCE)->first();
$journal = TransactionJournal::create(
[
'user_id' => $data['user'],
'transaction_type_id' => $transactionType->id,
'bill_id' => null,
'transaction_currency_id' => $data['openingBalanceCurrency'],
'description' => 'Initial balance for "' . $account->name . '"',
'completed' => true,
@@ -299,24 +367,22 @@ class AccountCrud implements AccountCrudInterface
$firstAccount = $account;
$secondAccount = $opposing;
$firstAmount = $data['openingBalance'];
$secondAmount = $data['openingBalance'] * -1;
$firstAmount = $amount;
$secondAmount = $amount * -1;
if ($data['openingBalance'] < 0) {
$firstAccount = $opposing;
$secondAccount = $account;
$firstAmount = $data['openingBalance'] * -1;
$secondAmount = $data['openingBalance'];
$firstAmount = $amount * -1;
$secondAmount = $amount;
}
$one = new Transaction(['account_id' => $firstAccount->id, 'transaction_journal_id' => $journal->id, 'amount' => $firstAmount]);
$one->save();// first transaction: from
$two = new Transaction(['account_id' => $secondAccount->id, 'transaction_journal_id' => $journal->id, 'amount' => $secondAmount]);
$two->save(); // second transaction: to
return $journal;
}
/**
@@ -342,30 +408,32 @@ class AccountCrud implements AccountCrudInterface
}
/**
* @param Account $account
* @param TransactionJournal $journal
* @param array $data
* @param Account $account
* @param array $data
*
* @return TransactionJournal
* @return bool
*/
protected function updateInitialBalance(Account $account, TransactionJournal $journal, array $data): TransactionJournal
protected function updateInitialBalance(Account $account, array $data): bool
{
$journal->date = $data['openingBalanceDate'];
$journal->save();
$openingBalance = $this->openingBalanceTransaction($account);
if ($data['openingBalance'] != 0) {
if (!is_null($openingBalance->id)) {
$date = $data['openingBalanceDate'];
$amount = $data['openingBalance'];
/** @var Transaction $transaction */
foreach ($journal->transactions()->get() as $transaction) {
if ($account->id == $transaction->account_id) {
$transaction->amount = $data['openingBalance'];
$transaction->save();
}
if ($account->id != $transaction->account_id) {
$transaction->amount = $data['openingBalance'] * -1;
$transaction->save();
return $this->updateJournal($account, $openingBalance, $date, $amount);
}
$this->storeInitialBalance($account, $data);
return true;
}
// else, delete it:
if ($openingBalance) { // opening balance is zero, should we delete it?
$openingBalance->delete(); // delete existing opening balance.
}
return $journal;
return true;
}
/**
@@ -418,4 +486,56 @@ class AccountCrud implements AccountCrudInterface
return $journal;
}
}
/**
* @param float $amount
* @param int $user
* @param string $name
*
* @return Account
*/
private function storeOpposingAccount(float $amount, int $user, string $name):Account
{
$type = $amount < 0 ? 'expense' : 'revenue';
$opposingData = [
'user' => $user,
'accountType' => $type,
'name' => $name . ' initial balance',
'active' => false,
'iban' => '',
'virtualBalance' => 0,
];
return $this->storeAccount($opposingData);
}
/**
* @param Account $account
* @param TransactionJournal $journal
* @param Carbon $date
* @param float $amount
*
* @return bool
*/
private function updateJournal(Account $account, TransactionJournal $journal, Carbon $date, float $amount): bool
{
// update date:
$journal->date = $date;
$journal->save();
// update transactions:
/** @var Transaction $transaction */
foreach ($journal->transactions()->get() as $transaction) {
if ($account->id == $transaction->account_id) {
$transaction->amount = $amount;
$transaction->save();
}
if ($account->id != $transaction->account_id) {
$transaction->amount = $amount * -1;
$transaction->save();
}
}
return true;
}
}

View File

@@ -37,6 +37,30 @@ interface AccountCrudInterface
*/
public function find(int $accountId): Account;
/**
* @param string $number
* @param array $types
*
* @return Account
*/
public function findByAccountNumber(string $number, array $types): Account;
/**
* @param string $iban
* @param array $types
*
* @return Account
*/
public function findByIban(string $iban, array $types): Account;
/**
* @param string $name
* @param array $types
*
* @return Account
*/
public function findByName(string $name, array $types): Account;
/**
* @param array $accountIds
*
@@ -67,7 +91,6 @@ interface AccountCrudInterface
*/
public function storeMeta(Account $account, string $name, $value): AccountMeta;
/**
* @param Account $account
* @param array $data
@@ -75,4 +98,12 @@ interface AccountCrudInterface
* @return Account
*/
public function update(Account $account, array $data): Account;
}
/**
* @param Account $account
* @param string $type
*
* @return Account
*/
public function updateAccountType(Account $account, string $type): Account;
}

View File

@@ -105,9 +105,6 @@ class Journal implements JournalInterface
*/
public function updateJournal(TransactionJournal $journal, array $data): TransactionJournal
{
echo '<pre>';
print_r($data);
$journal->description = $data['journal_description'];
$journal->transaction_currency_id = $data['journal_currency_id'];
$journal->date = $data['date'];
@@ -167,7 +164,8 @@ class Journal implements JournalInterface
{
$destinationAccount = Account::where('user_id', $this->user->id)->where('id', $data['destination_account_id'])->first(['accounts.*']);
if (strlen($data['source_account_name']) > 0) {
if (isset($data['source_account_name']) && strlen($data['source_account_name']) > 0) {
$sourceType = AccountType::where('type', 'Revenue account')->first();
$sourceAccount = Account::firstOrCreateEncrypted(
['user_id' => $this->user->id, 'account_type_id' => $sourceType->id, 'name' => $data['source_account_name'], 'active' => 1]
@@ -215,4 +213,4 @@ class Journal implements JournalInterface
}
}
}

View File

@@ -44,4 +44,4 @@ interface JournalInterface
* @return TransactionJournal
*/
public function updateJournal(TransactionJournal $journal, array $data): TransactionJournal;
}
}

View File

@@ -0,0 +1,40 @@
<?php
/**
* UserIsConfirmed.php
* Copyright (C) 2016 thegrumpydictator@gmail.com
*
* This software may be modified and distributed under the terms
* of the MIT license. See the LICENSE file for details.
*/
declare(strict_types = 1);
namespace FireflyIII\Events;
use FireflyIII\User;
use Illuminate\Queue\SerializesModels;
/**
* Class UserIsConfirmed
*
* @package FireflyIII\Events
*/
class UserIsConfirmed extends Event
{
use SerializesModels;
public $ipAddress;
public $user;
/**
* Create a new event instance.
*
* @param User $user
* @param string $ipAddress
*/
public function __construct(User $user, string $ipAddress)
{
$this->user = $user;
$this->ipAddress = $ipAddress;
}
}

View File

@@ -0,0 +1,40 @@
<?php
/**
* UserIsDeleted.php
* Copyright (C) 2016 thegrumpydictator@gmail.com
*
* This software may be modified and distributed under the terms
* of the MIT license. See the LICENSE file for details.
*/
declare(strict_types = 1);
namespace FireflyIII\Events;
use FireflyIII\User;
use Illuminate\Queue\SerializesModels;
/**
* Class UserIsDeleted
*
* @package FireflyIII\Events
*/
class UserIsDeleted extends Event
{
use SerializesModels;
public $ipAddress;
public $user;
/**
* Create a new event instance.
*
* @param User $user
* @param string $ipAddress
*/
public function __construct(User $user, string $ipAddress)
{
$this->user = $user;
$this->ipAddress = $ipAddress;
}
}

View File

@@ -83,10 +83,10 @@ class AttachmentCollector extends BasicCollector implements CollectorInterface
/** @var TransactionJournal $journal */
$journal = $attachment->attachable;
$args = [
'attachment_name' => $attachment->filename,
'attachment_name' => e($attachment->filename),
'attachment_id' => $attachment->id,
'type' => strtolower($journal->transactionType->type),
'description' => $journal->description,
'description' => e($journal->description),
'journal_id' => $journal->id,
'date' => $journal->date->formatLocalized(strval(trans('config.month_and_day'))),
'amount' => Amount::formatJournal($journal, false),

View File

@@ -33,6 +33,7 @@ class UploadCollector extends BasicCollector implements CollectorInterface
private $uploadDisk;
/**
*
* AttachmentCollector constructor.
*
* @param ExportJob $job

View File

@@ -44,4 +44,4 @@ class EntryAccount
$this->type = $account->accountType->type;
$this->number = $account->getMeta('accountNumber');
}
}
}

View File

@@ -38,4 +38,4 @@ class EntryBill
}
}
}
}

View File

@@ -38,4 +38,4 @@ class EntryBudget
}
}
}
}

View File

@@ -37,4 +37,4 @@ class EntryCategory
$this->name = $category->name;
}
}
}
}

View File

@@ -104,4 +104,4 @@ class BudgetLimitEventHandler
}
}
}
}

View File

@@ -32,10 +32,11 @@ class ConnectTransactionToPiggyBank
*/
public function handle(TransactionStored $event): bool
{
echo '<pre>';
/** @var PiggyBankRepositoryInterface $repository */
$repository = app(PiggyBankRepositoryInterface::class);
$transaction = $event->transaction;
$piggyBank = $repository->find($transaction['piggy_bank_id']);
// valid piggy:

View File

@@ -34,6 +34,10 @@ class UpdateJournalConnection
{
$journal = $event->journal;
if (!$journal->isTransfer()) {
return true;
}
// get the event connected to this journal:
/** @var PiggyBankEvent $event */
$event = PiggyBankEvent::where('transaction_journal_id', $journal->id)->first();

View File

@@ -0,0 +1,62 @@
<?php
/**
* UserSaveIpAddress.php
* Copyright (C) 2016 thegrumpydictator@gmail.com
*
* This software may be modified and distributed under the terms
* of the MIT license. See the LICENSE file for details.
*/
declare(strict_types = 1);
namespace FireflyIII\Handlers\Events;
use FireflyIII\Events\UserIsConfirmed;
use FireflyIII\Events\UserRegistration;
use FireflyIII\User;
use Preferences;
/**
* Class UserSaveIpAddress
*
* @package FireflyIII\Handlers\Events
*/
class UserSaveIpAddress
{
/**
* Create the event listener.
*
*/
public function __construct()
{
//
}
/**
* Handle the event.
*
* @param UserRegistration $event
*
* @return bool
*/
public function saveFromRegistration(UserRegistration $event): bool
{
Preferences::setForUser($event->user, 'registration_ip_address', $event->ipAddress);
return true;
}
/**
* Handle the event.
*
* @param UserIsConfirmed $event
*
* @return bool
*/
public function saveFromConfirmation(UserIsConfirmed $event): bool
{
Preferences::setForUser($event->user, 'confirmation_ip_address', $event->ipAddress);
return true;
}
}

View File

@@ -1,35 +0,0 @@
<?php
/**
* AccountId.php
* Copyright (C) 2016 thegrumpydictator@gmail.com
*
* This software may be modified and distributed under the terms
* of the MIT license. See the LICENSE file for details.
*/
declare(strict_types = 1);
namespace FireflyIII\Helpers\Csv\Converter;
use FireflyIII\Models\Account;
/**
* Class AccountId
*
* @package FireflyIII\Helpers\Csv\Converter
*/
class AccountId extends BasicConverter implements ConverterInterface
{
/**
* @return Account
*/
public function convert(): Account
{
$crud = app('FireflyIII\Crud\Account\AccountCrudInterface');
$var = isset($this->mapped[$this->index][$this->value]) ? $this->mapped[$this->index][$this->value] : $this->value;
$account = $crud->find($var);
return $account;
}
}

View File

@@ -1,32 +0,0 @@
<?php
/**
* Amount.php
* Copyright (C) 2016 thegrumpydictator@gmail.com
*
* This software may be modified and distributed under the terms
* of the MIT license. See the LICENSE file for details.
*/
declare(strict_types = 1);
namespace FireflyIII\Helpers\Csv\Converter;
/**
* Class Amount
*
* @package FireflyIII\Helpers\Csv\Converter
*/
class Amount extends BasicConverter implements ConverterInterface
{
/**
* @return string
*/
public function convert(): string
{
if (is_numeric($this->value)) {
return strval($this->value);
}
return '0';
}
}

View File

@@ -1,36 +0,0 @@
<?php
/**
* AmountComma.php
* Copyright (C) 2016 thegrumpydictator@gmail.com
*
* This software may be modified and distributed under the terms
* of the MIT license. See the LICENSE file for details.
*/
declare(strict_types = 1);
namespace FireflyIII\Helpers\Csv\Converter;
/**
* Class AmountComma
*
* Parses the input as the amount with a comma as decimal separator
*
* @package FireflyIII\Helpers\Csv\Converter
*/
class AmountComma extends BasicConverter implements ConverterInterface
{
/**
* @return float|int
*/
public function convert(): string
{
$value = str_replace(',', '.', strval($this->value));
if (is_numeric($value)) {
return strval($value);
}
return '0';
}
}

View File

@@ -1,89 +0,0 @@
<?php
/**
* AssetAccountIban.php
* Copyright (C) 2016 thegrumpydictator@gmail.com
*
* This software may be modified and distributed under the terms
* of the MIT license. See the LICENSE file for details.
*/
declare(strict_types = 1);
namespace FireflyIII\Helpers\Csv\Converter;
use Auth;
use Carbon\Carbon;
use FireflyIII\Crud\Account\AccountCrudInterface;
use FireflyIII\Models\Account;
use FireflyIII\Models\AccountType;
/**
* Class AssetAccountIban
*
* @package FireflyIII\Helpers\Csv\Converter
*/
class AssetAccountIban extends BasicConverter implements ConverterInterface
{
/**
* @return Account
*/
public function convert(): Account
{
$crud = app('FireflyIII\Crud\Account\AccountCrudInterface');
// is mapped? Then it's easy!
if (isset($this->mapped[$this->index][$this->value])) {
$account = $crud->find(intval($this->mapped[$this->index][$this->value]));
return $account;
}
if (strlen($this->value) > 0) {
$account = $this->searchOrCreate($crud);
return $account;
}
return new Account;
}
/**
* @param AccountCrudInterface $crud
*
* @return Account
*/
private function searchOrCreate(AccountCrudInterface $crud)
{
// find or create new account:
$set = $crud->getAccountsByType([AccountType::DEFAULT, AccountType::ASSET]);
/** @var Account $entry */
foreach ($set as $entry) {
if ($entry->iban == $this->value) {
return $entry;
}
}
// create it if doesn't exist.
$accountData = [
'name' => $this->value,
'accountType' => 'asset',
'virtualBalance' => 0,
'virtualBalanceCurrency' => 1, // hard coded.
'active' => true,
'user' => Auth::user()->id,
'iban' => $this->value,
'accountNumber' => $this->value,
'accountRole' => null,
'openingBalance' => 0,
'openingBalanceDate' => new Carbon,
'openingBalanceCurrency' => 1, // hard coded.
];
$account = $crud->store($accountData);
return $account;
}
}

View File

@@ -1,65 +0,0 @@
<?php
/**
* AssetAccountName.php
* Copyright (C) 2016 thegrumpydictator@gmail.com
*
* This software may be modified and distributed under the terms
* of the MIT license. See the LICENSE file for details.
*/
declare(strict_types = 1);
namespace FireflyIII\Helpers\Csv\Converter;
use Auth;
use Carbon\Carbon;
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(): Account
{
$crud = app('FireflyIII\Crud\Account\AccountCrudInterface');
if (isset($this->mapped[$this->index][$this->value])) {
$account = $crud->find(intval($this->mapped[$this->index][$this->value]));
return $account;
}
$set = $crud->getAccountsByType([AccountType::DEFAULT, AccountType::ASSET]);
/** @var Account $entry */
foreach ($set as $entry) {
if ($entry->name == $this->value) {
return $entry;
}
}
$accountData = [
'name' => $this->value,
'accountType' => 'asset',
'virtualBalance' => 0,
'virtualBalanceCurrency' => 1, // hard coded.
'active' => true,
'user' => Auth::user()->id,
'iban' => null,
'accountNumber' => $this->value,
'accountRole' => null,
'openingBalance' => 0,
'openingBalanceDate' => new Carbon,
'openingBalanceCurrency' => 1, // hard coded.
];
$account = $crud->store($accountData);
return $account;
}
}

View File

@@ -1,77 +0,0 @@
<?php
/**
* AssetAccountNumber.php
* Copyright (C) 2016 thegrumpydictator@gmail.com
*
* This software may be modified and distributed under the terms
* of the MIT license. See the LICENSE file for details.
*/
declare(strict_types = 1);
namespace FireflyIII\Helpers\Csv\Converter;
use Auth;
use Carbon\Carbon;
use FireflyIII\Models\Account;
use FireflyIII\Models\AccountType;
/**
* Class AssetAccountNumber
*
* @package FireflyIII\Helpers\Csv\Converter
*/
class AssetAccountNumber extends BasicConverter implements ConverterInterface
{
/**
* @return Account|null
*/
public function convert(): Account
{
$crud = app('FireflyIII\Crud\Account\AccountCrudInterface');
// is mapped? Then it's easy!
if (isset($this->mapped[$this->index][$this->value])) {
$account = $crud->find(intval($this->mapped[$this->index][$this->value]));
return $account;
}
// if not, search for it (or create it):
$value = $this->value ?? '';
if (strlen($value) > 0) {
// find or create new account:
$set = $crud->getAccountsByType([AccountType::DEFAULT, AccountType::ASSET]);
/** @var Account $entry */
foreach ($set as $entry) {
$accountNumber = $entry->getMeta('accountNumber');
if ($accountNumber == $this->value) {
return $entry;
}
}
$accountData = [
'name' => $this->value,
'accountType' => 'asset',
'virtualBalance' => 0,
'virtualBalanceCurrency' => 1, // hard coded.
'active' => true,
'user' => Auth::user()->id,
'iban' => null,
'accountNumber' => $this->value,
'accountRole' => null,
'openingBalance' => 0,
'openingBalanceDate' => new Carbon,
'openingBalanceCurrency' => 1, // hard coded.
];
$account = $crud->store($accountData);
return $account;
}
return null; // is this accepted?
}
}

View File

@@ -1,114 +0,0 @@
<?php
/**
* BasicConverter.php
* Copyright (C) 2016 thegrumpydictator@gmail.com
*
* This software may be modified and distributed under the terms
* of the MIT license. See the LICENSE file for details.
*/
declare(strict_types = 1);
namespace FireflyIII\Helpers\Csv\Converter;
/**
* Class BasicConverter
*
*
* @SuppressWarnings(PHPMD.NumberOfChildren)
* @package FireflyIII\Helpers\Csv\Converter
*/
class BasicConverter
{
/** @var array */
protected $data;
/** @var string */
protected $field;
/** @var int */
protected $index;
/** @var array */
protected $mapped;
/** @var string */
protected $value;
/**
* @return array
*/
public function getData(): array
{
return $this->data;
}
/**
* @param array $data
*/
public function setData(array $data)
{
$this->data = $data;
}
/**
* @return string
*/
public function getField(): string
{
return $this->field;
}
/**
* @param string $field
*/
public function setField(string $field)
{
$this->field = $field;
}
/**
* @return int
*/
public function getIndex(): int
{
return $this->index;
}
/**
* @param int $index
*/
public function setIndex(int $index)
{
$this->index = $index;
}
/**
* @return array
*/
public function getMapped(): array
{
return $this->mapped;
}
/**
* @param array $mapped
*/
public function setMapped(array $mapped)
{
$this->mapped = $mapped;
}
/**
* @return string
*/
public function getValue(): string
{
return $this->value;
}
/**
* @param string $value
*/
public function setValue(string $value)
{
$this->value = $value;
}
}

View File

@@ -1,36 +0,0 @@
<?php
/**
* BillId.php
* Copyright (C) 2016 thegrumpydictator@gmail.com
*
* This software may be modified and distributed under the terms
* of the MIT license. See the LICENSE file for details.
*/
declare(strict_types = 1);
namespace FireflyIII\Helpers\Csv\Converter;
use FireflyIII\Models\Bill;
use FireflyIII\Repositories\Bill\BillRepositoryInterface;
/**
* Class BillId
*
* @package FireflyIII\Helpers\Csv\Converter
*/
class BillId extends BasicConverter implements ConverterInterface
{
/**
* @return Bill
*/
public function convert(): Bill
{
/** @var BillRepositoryInterface $repository */
$repository = app(BillRepositoryInterface::class);
$value = isset($this->mapped[$this->index][$this->value]) ? $this->mapped[$this->index][$this->value] : $this->value;
$bill = $repository->find($value);
return $bill;
}
}

View File

@@ -1,47 +0,0 @@
<?php
/**
* BillName.php
* Copyright (C) 2016 thegrumpydictator@gmail.com
*
* This software may be modified and distributed under the terms
* of the MIT license. See the LICENSE file for details.
*/
declare(strict_types = 1);
namespace FireflyIII\Helpers\Csv\Converter;
use FireflyIII\Models\Bill;
use FireflyIII\Repositories\Bill\BillRepositoryInterface;
/**
* Class BillName
*
* @package FireflyIII\Helpers\Csv\Converter
*/
class BillName extends BasicConverter implements ConverterInterface
{
/**
* @return Bill
*/
public function convert(): Bill
{
/** @var BillRepositoryInterface $repository */
$repository = app(BillRepositoryInterface::class);
// is mapped? Then it's easy!
if (isset($this->mapped[$this->index][$this->value])) {
return $repository->find($this->mapped[$this->index][$this->value]);
}
$bills = $repository->getBills();
/** @var Bill $bill */
foreach ($bills as $bill) {
if ($bill->name == $this->value) {
return $bill;
}
}
return new Bill;
}
}

View File

@@ -1,36 +0,0 @@
<?php
/**
* BudgetId.php
* Copyright (C) 2016 thegrumpydictator@gmail.com
*
* This software may be modified and distributed under the terms
* of the MIT license. See the LICENSE file for details.
*/
declare(strict_types = 1);
namespace FireflyIII\Helpers\Csv\Converter;
use FireflyIII\Models\Budget;
use FireflyIII\Repositories\Budget\BudgetRepositoryInterface;
/**
* Class BudgetId
*
* @package FireflyIII\Helpers\Csv\Converter
*/
class BudgetId extends BasicConverter implements ConverterInterface
{
/**
* @return Budget
*/
public function convert(): Budget
{
/** @var BudgetRepositoryInterface $repository */
$repository = app(BudgetRepositoryInterface::class);
$value = isset($this->mapped[$this->index][$this->value]) ? $this->mapped[$this->index][$this->value] : $this->value;
$budget = $repository->find($value);
return $budget;
}
}

View File

@@ -1,44 +0,0 @@
<?php
/**
* BudgetName.php
* Copyright (C) 2016 thegrumpydictator@gmail.com
*
* This software may be modified and distributed under the terms
* of the MIT license. See the LICENSE file for details.
*/
declare(strict_types = 1);
namespace FireflyIII\Helpers\Csv\Converter;
use Auth;
use FireflyIII\Models\Budget;
use FireflyIII\Repositories\Budget\BudgetRepositoryInterface;
/**
* Class BudgetName
*
* @package FireflyIII\Helpers\Csv\Converter
*/
class BudgetName extends BasicConverter implements ConverterInterface
{
/**
* @return Budget
*/
public function convert(): Budget
{
/** @var BudgetRepositoryInterface $repository */
$repository = app(BudgetRepositoryInterface::class);
// is mapped? Then it's easy!
if (isset($this->mapped[$this->index][$this->value])) {
$budget = $repository->find($this->mapped[$this->index][$this->value]);
return $budget;
}
$budget = $repository->store(['name' => $this->value, 'user' => Auth::user()->id]);
return $budget;
}
}

View File

@@ -1,36 +0,0 @@
<?php
/**
* CategoryId.php
* Copyright (C) 2016 thegrumpydictator@gmail.com
*
* This software may be modified and distributed under the terms
* of the MIT license. See the LICENSE file for details.
*/
declare(strict_types = 1);
namespace FireflyIII\Helpers\Csv\Converter;
use FireflyIII\Models\Category;
use FireflyIII\Repositories\Category\CategoryRepositoryInterface;
/**
* Class CategoryId
*
* @package FireflyIII\Helpers\Csv\Converter
*/
class CategoryId extends BasicConverter implements ConverterInterface
{
/**
* @return Category
*/
public function convert(): Category
{
/** @var CategoryRepositoryInterface $repository */
$repository = app(CategoryRepositoryInterface::class);
$value = isset($this->mapped[$this->index][$this->value]) ? $this->mapped[$this->index][$this->value] : $this->value;
$category = $repository->find($value);
return $category;
}
}

View File

@@ -1,49 +0,0 @@
<?php
/**
* CategoryName.php
* Copyright (C) 2016 thegrumpydictator@gmail.com
*
* This software may be modified and distributed under the terms
* of the MIT license. See the LICENSE file for details.
*/
declare(strict_types = 1);
namespace FireflyIII\Helpers\Csv\Converter;
use Auth;
use FireflyIII\Models\Category;
use FireflyIII\Repositories\Category\CategoryRepositoryInterface;
/**
* Class CategoryName
*
* @package FireflyIII\Helpers\Csv\Converter
*/
class CategoryName extends BasicConverter implements ConverterInterface
{
/**
* @return Category
*/
public function convert(): Category
{
/** @var CategoryRepositoryInterface $repository */
$repository = app(CategoryRepositoryInterface::class);
// is mapped? Then it's easy!
if (isset($this->mapped[$this->index][$this->value])) {
$category = $repository->find($this->mapped[$this->index][$this->value]);
return $category;
}
$data = [
'name' => $this->value,
'user' => Auth::user()->id,
];
$category = $repository->store($data);
return $category;
}
}

View File

@@ -1,52 +0,0 @@
<?php
/**
* ConverterInterface.php
* Copyright (C) 2016 thegrumpydictator@gmail.com
*
* This software may be modified and distributed under the terms
* of the MIT license. See the LICENSE file for details.
*/
declare(strict_types = 1);
namespace FireflyIII\Helpers\Csv\Converter;
/**
* Interface ConverterInterface
*
* @package FireflyIII\Helpers\Csv\Converter
*/
interface ConverterInterface
{
/**
* @return mixed
*/
public function convert();
/**
* @param array $data
*/
public function setData(array $data);
/**
* @param string $field
*
*/
public function setField(string $field);
/**
* @param int $index
*/
public function setIndex(int $index);
/**
* @param array $mapped
*/
public function setMapped(array $mapped);
/**
* @param string $value
*/
public function setValue(string $value);
}

View File

@@ -1,43 +0,0 @@
<?php
/**
* CurrencyCode.php
* Copyright (C) 2016 thegrumpydictator@gmail.com
*
* This software may be modified and distributed under the terms
* of the MIT license. See the LICENSE file for details.
*/
declare(strict_types = 1);
namespace FireflyIII\Helpers\Csv\Converter;
use FireflyIII\Models\TransactionCurrency;
use FireflyIII\Repositories\Currency\CurrencyRepositoryInterface;
/**
* Class CurrencyCode
*
* @package FireflyIII\Helpers\Csv\Converter
*/
class CurrencyCode extends BasicConverter implements ConverterInterface
{
/**
* @return TransactionCurrency
*/
public function convert(): TransactionCurrency
{
/** @var CurrencyRepositoryInterface $repository */
$repository = app(CurrencyRepositoryInterface::class);
if (isset($this->mapped[$this->index][$this->value])) {
$currency = $repository->find(intval($this->mapped[$this->index][$this->value]));
return $currency;
}
$currency = $repository->findByCode($this->value);
return $currency;
}
}

View File

@@ -1,36 +0,0 @@
<?php
/**
* CurrencyId.php
* Copyright (C) 2016 thegrumpydictator@gmail.com
*
* This software may be modified and distributed under the terms
* of the MIT license. See the LICENSE file for details.
*/
declare(strict_types = 1);
namespace FireflyIII\Helpers\Csv\Converter;
use FireflyIII\Models\TransactionCurrency;
use FireflyIII\Repositories\Currency\CurrencyRepositoryInterface;
/**
* Class CurrencyId
*
* @package FireflyIII\Helpers\Csv\Converter
*/
class CurrencyId extends BasicConverter implements ConverterInterface
{
/**
* @return TransactionCurrency
*/
public function convert(): TransactionCurrency
{
/** @var CurrencyRepositoryInterface $repository */
$repository = app(CurrencyRepositoryInterface::class);
$value = isset($this->mapped[$this->index][$this->value]) ? $this->mapped[$this->index][$this->value] : $this->value;
$currency = $repository->find($value);
return $currency;
}
}

View File

@@ -1,42 +0,0 @@
<?php
/**
* CurrencyName.php
* Copyright (C) 2016 thegrumpydictator@gmail.com
*
* This software may be modified and distributed under the terms
* of the MIT license. See the LICENSE file for details.
*/
declare(strict_types = 1);
namespace FireflyIII\Helpers\Csv\Converter;
use FireflyIII\Models\TransactionCurrency;
use FireflyIII\Repositories\Currency\CurrencyRepositoryInterface;
/**
* Class CurrencyName
*
* @package FireflyIII\Helpers\Csv\Converter
*/
class CurrencyName extends BasicConverter implements ConverterInterface
{
/**
* @return TransactionCurrency
*/
public function convert(): TransactionCurrency
{
/** @var CurrencyRepositoryInterface $repository */
$repository = app(CurrencyRepositoryInterface::class);
if (isset($this->mapped[$this->index][$this->value])) {
$currency = $repository->find($this->mapped[$this->index][$this->value]);
return $currency;
}
$currency = $repository->findByName($this->value);
return $currency;
}
}

View File

@@ -1,43 +0,0 @@
<?php
/**
* CurrencySymbol.php
* Copyright (C) 2016 thegrumpydictator@gmail.com
*
* This software may be modified and distributed under the terms
* of the MIT license. See the LICENSE file for details.
*/
declare(strict_types = 1);
namespace FireflyIII\Helpers\Csv\Converter;
use FireflyIII\Models\TransactionCurrency;
use FireflyIII\Repositories\Currency\CurrencyRepositoryInterface;
/**
* Class CurrencySymbol
*
* @package FireflyIII\Helpers\Csv\Converter
*/
class CurrencySymbol extends BasicConverter implements ConverterInterface
{
/**
* @return TransactionCurrency
*/
public function convert(): TransactionCurrency
{
/** @var CurrencyRepositoryInterface $repository */
$repository = app(CurrencyRepositoryInterface::class);
if (isset($this->mapped[$this->index][$this->value])) {
$currency = $repository->find($this->mapped[$this->index][$this->value]);
return $currency;
}
$currency = $repository->findBySymbol($this->value);
return $currency;
}
}

View File

@@ -1,46 +0,0 @@
<?php
/**
* Date.php
* Copyright (C) 2016 thegrumpydictator@gmail.com
*
* This software may be modified and distributed under the terms
* of the MIT license. See the LICENSE file for details.
*/
declare(strict_types = 1);
namespace FireflyIII\Helpers\Csv\Converter;
use Carbon\Carbon;
use FireflyIII\Exceptions\FireflyException;
use InvalidArgumentException;
use Log;
/**
* Class Date
*
* @package FireflyIII\Helpers\Csv\Converter
*/
class Date extends BasicConverter implements ConverterInterface
{
/**
* @return Carbon
* @throws FireflyException
*/
public function convert(): Carbon
{
$format = session('csv-date-format');
try {
$date = Carbon::createFromFormat($format, $this->value);
} catch (InvalidArgumentException $e) {
Log::error('Date conversion error: ' . $e->getMessage() . '. Value was "' . $this->value . '", format was "' . $format . '".');
$message = trans('firefly.csv_date_parse_error', ['format' => $format, 'value' => $this->value]);
throw new FireflyException($message);
}
return $date;
}
}

View File

@@ -1,64 +0,0 @@
<?php
/**
* OpposingAccountIban.php
* Copyright (C) 2016 thegrumpydictator@gmail.com
*
* This software may be modified and distributed under the terms
* of the MIT license. See the LICENSE file for details.
*/
declare(strict_types = 1);
namespace FireflyIII\Helpers\Csv\Converter;
use FireflyIII\Crud\Account\AccountCrudInterface;
use FireflyIII\Models\Account;
/**
* Class OpposingAccountIban
*
* @package FireflyIII\Helpers\Csv\Converter
*/
class OpposingAccountIban extends BasicConverter implements ConverterInterface
{
/**
* If mapped, return account. Otherwise, only return the name itself.
*
* @return Account|string
*/
public function convert()
{
$crud = app('FireflyIII\Crud\Account\AccountCrudInterface');
if (isset($this->mapped[$this->index][$this->value])) {
$account = $crud->find($this->mapped[$this->index][$this->value]);
return $account;
}
return $this->findAccount($crud);
}
/**
* @param AccountCrudInterface $crud
*
* @return Account|string
*/
private function findAccount(AccountCrudInterface $crud)
{
if (strlen($this->value) > 0) {
$set = $crud->getAccountsByType([]);
/** @var Account $account */
foreach ($set as $account) {
if ($account->iban == $this->value) {
return $account;
}
}
}
return $this->value;
}
}

View File

@@ -1,35 +0,0 @@
<?php
/**
* OpposingAccountId.php
* Copyright (C) 2016 thegrumpydictator@gmail.com
*
* This software may be modified and distributed under the terms
* of the MIT license. See the LICENSE file for details.
*/
declare(strict_types = 1);
namespace FireflyIII\Helpers\Csv\Converter;
use FireflyIII\Models\Account;
/**
* Class OpposingAccountId
*
* @package FireflyIII\Helpers\Csv\Converter
*/
class OpposingAccountId extends BasicConverter implements ConverterInterface
{
/**
* @return Account
*/
public function convert(): Account
{
$crud = app('FireflyIII\Crud\Account\AccountCrudInterface');
$value = isset($this->mapped[$this->index][$this->value]) ? $this->mapped[$this->index][$this->value] : $this->value;
$account = $crud->find($value);
return $account;
}
}

View File

@@ -1,41 +0,0 @@
<?php
/**
* OpposingAccountName.php
* Copyright (C) 2016 thegrumpydictator@gmail.com
*
* This software may be modified and distributed under the terms
* of the MIT license. See the LICENSE file for details.
*/
declare(strict_types = 1);
namespace FireflyIII\Helpers\Csv\Converter;
use FireflyIII\Models\Account;
/**
* Class OpposingAccountName
*
* @package FireflyIII\Helpers\Csv\Converter
*/
class OpposingAccountName extends BasicConverter implements ConverterInterface
{
/**
* If mapped, return account. Otherwise, only return the name itself.
*
* @return Account|string
*/
public function convert()
{
$crud = app('FireflyIII\Crud\Account\AccountCrudInterface');
if (isset($this->mapped[$this->index][$this->value])) {
$account = $crud->find($this->mapped[$this->index][$this->value]);
return $account;
}
return $this->value;
}
}

View File

@@ -1,53 +0,0 @@
<?php
/**
* TagsComma.php
* Copyright (C) 2016 thegrumpydictator@gmail.com
*
* This software may be modified and distributed under the terms
* of the MIT license. See the LICENSE file for details.
*/
declare(strict_types = 1);
namespace FireflyIII\Helpers\Csv\Converter;
use FireflyIII\Repositories\Tag\TagRepositoryInterface;
use Illuminate\Support\Collection;
/**
* Class TagsComma
*
* @package FireflyIII\Helpers\Csv\Converter
*/
class TagsComma extends BasicConverter implements ConverterInterface
{
/**
* @return Collection
*/
public function convert(): Collection
{
/** @var TagRepositoryInterface $repository */
$repository = app(TagRepositoryInterface::class);
$tags = new Collection;
$strings = explode(',', $this->value);
foreach ($strings as $string) {
$data = [
'tag' => $string,
'date' => null,
'description' => null,
'latitude' => null,
'longitude' => null,
'zoomLevel' => null,
'tagMode' => 'nothing',
];
if (strlen($string) > 0) {
$tag = $repository->store($data); // should validate first?
$tags->push($tag);
}
}
$tags = $tags->merge($this->data['tags']);
return $tags;
}
}

View File

@@ -1,54 +0,0 @@
<?php
/**
* TagsSpace.php
* Copyright (C) 2016 thegrumpydictator@gmail.com
*
* This software may be modified and distributed under the terms
* of the MIT license. See the LICENSE file for details.
*/
declare(strict_types = 1);
namespace FireflyIII\Helpers\Csv\Converter;
use FireflyIII\Repositories\Tag\TagRepositoryInterface;
use Illuminate\Support\Collection;
/**
* Class TagsSpace
*
* @package FireflyIII\Helpers\Csv\Converter
*/
class TagsSpace extends BasicConverter implements ConverterInterface
{
/**
* @return Collection
*/
public function convert(): Collection
{
/** @var TagRepositoryInterface $repository */
$repository = app(TagRepositoryInterface::class);
$tags = new Collection;
$strings = explode(' ', $this->value);
foreach ($strings as $string) {
$data = [
'tag' => $string,
'date' => null,
'description' => null,
'latitude' => null,
'longitude' => null,
'zoomLevel' => null,
'tagMode' => 'nothing',
];
if (strlen($string) > 0) {
$tag = $repository->store($data); // should validate first?
$tags->push($tag);
}
}
$tags = $tags->merge($this->data['tags']);
return $tags;
}
}

View File

@@ -1,336 +0,0 @@
<?php
/**
* Data.php
* Copyright (C) 2016 thegrumpydictator@gmail.com
*
* This software may be modified and distributed under the terms
* of the MIT license. See the LICENSE file for details.
*/
declare(strict_types = 1);
namespace FireflyIII\Helpers\Csv;
use Crypt;
use League\Csv\Reader;
use Session;
use Storage;
/**
* Class Data
*
* @package FireflyIII\Helpers\Csv
*/
class Data
{
/** @var string */
protected $csvFileContent = '';
/** @var string */
protected $csvFileLocation = '';
/** @var string */
protected $dateFormat = '';
/** @var string */
protected $delimiter = '';
/** @var bool */
protected $hasHeaders;
/** @var int */
protected $importAccount = 0;
/** @var array */
protected $map = [];
/** @var array */
protected $mapped = [];
/** @var Reader */
protected $reader;
/** @var array */
protected $roles = [];
/** @var array */
protected $specifix = [];
/**
*/
public function __construct()
{
$this->sessionHasHeaders();
$this->sessionDateFormat();
$this->sessionCsvFileLocation();
$this->sessionMap();
$this->sessionRoles();
$this->sessionMapped();
$this->sessionSpecifix();
$this->sessionImportAccount();
$this->sessionDelimiter();
}
/**
*
* @return string
*/
public function getCsvFileContent(): string
{
return $this->csvFileContent ?? '';
}
/**
*
* @param string $csvFileContent
*/
public function setCsvFileContent(string $csvFileContent)
{
$this->csvFileContent = $csvFileContent;
}
/**
* FIXxME may return null
*
* @return string
*/
public function getCsvFileLocation(): string
{
return $this->csvFileLocation;
}
/**
*
* @param string $csvFileLocation
*/
public function setCsvFileLocation(string $csvFileLocation)
{
Session::put('csv-file', $csvFileLocation);
$this->csvFileLocation = $csvFileLocation;
}
/**
* FIXxME may return null
*
* @return string
*/
public function getDateFormat(): string
{
return $this->dateFormat;
}
/**
*
* @param string $dateFormat
*/
public function setDateFormat(string $dateFormat)
{
Session::put('csv-date-format', $dateFormat);
$this->dateFormat = $dateFormat;
}
/**
* FIXxME may return null
*
* @return string
*/
public function getDelimiter(): string
{
return $this->delimiter;
}
/**
*
* @param string $delimiter
*/
public function setDelimiter(string $delimiter)
{
Session::put('csv-delimiter', $delimiter);
$this->delimiter = $delimiter;
}
/**
*
* @return array
*/
public function getMap(): array
{
return $this->map;
}
/**
*
* @param array $map
*/
public function setMap(array $map)
{
Session::put('csv-map', $map);
$this->map = $map;
}
/**
*
* @return array
*/
public function getMapped(): array
{
return $this->mapped;
}
/**
*
* @param array $mapped
*/
public function setMapped(array $mapped)
{
Session::put('csv-mapped', $mapped);
$this->mapped = $mapped;
}
/**
*
* @return Reader
*/
public function getReader(): Reader
{
if (!is_null($this->csvFileContent) && strlen($this->csvFileContent) === 0) {
$this->loadCsvFile();
}
if (is_null($this->reader)) {
$this->reader = Reader::createFromString($this->getCsvFileContent());
$this->reader->setDelimiter($this->delimiter);
}
return $this->reader;
}
/**
*
* @return array
*/
public function getRoles(): array
{
return $this->roles;
}
/**
*
* @param array $roles
*/
public function setRoles(array $roles)
{
Session::put('csv-roles', $roles);
$this->roles = $roles;
}
/**
*
* @return array
*/
public function getSpecifix(): array
{
return is_array($this->specifix) ? $this->specifix : [];
}
/**
*
* @param array $specifix
*/
public function setSpecifix(array $specifix)
{
Session::put('csv-specifix', $specifix);
$this->specifix = $specifix;
}
/**
*
* @return bool
*/
public function hasHeaders(): bool
{
return $this->hasHeaders;
}
/**
*
* @param bool $hasHeaders
*/
public function setHasHeaders(bool $hasHeaders)
{
Session::put('csv-has-headers', $hasHeaders);
$this->hasHeaders = $hasHeaders;
}
/**
*
* @param int $importAccount
*/
public function setImportAccount(int $importAccount)
{
Session::put('csv-import-account', $importAccount);
$this->importAccount = $importAccount;
}
protected function loadCsvFile()
{
$file = $this->getCsvFileLocation();
$disk = Storage::disk('upload');
$content = $disk->get($file);
$contentDecrypted = Crypt::decrypt($content);
$this->setCsvFileContent($contentDecrypted);
}
protected function sessionCsvFileLocation()
{
if (Session::has('csv-file')) {
$this->csvFileLocation = (string)session('csv-file');
}
}
protected function sessionDateFormat()
{
if (Session::has('csv-date-format')) {
$this->dateFormat = (string)session('csv-date-format');
}
}
protected function sessionDelimiter()
{
if (Session::has('csv-delimiter')) {
$this->delimiter = session('csv-delimiter');
}
}
protected function sessionHasHeaders()
{
if (Session::has('csv-has-headers')) {
$this->hasHeaders = (bool)session('csv-has-headers');
}
}
protected function sessionImportAccount()
{
if (Session::has('csv-import-account')) {
$this->importAccount = intval(session('csv-import-account'));
}
}
protected function sessionMap()
{
if (Session::has('csv-map')) {
$this->map = (array)session('csv-map');
}
}
protected function sessionMapped()
{
if (Session::has('csv-mapped')) {
$this->mapped = (array)session('csv-mapped');
}
}
protected function sessionRoles()
{
if (Session::has('csv-roles')) {
$this->roles = (array)session('csv-roles');
}
}
protected function sessionSpecifix()
{
if (Session::has('csv-specifix')) {
$this->specifix = (array)session('csv-specifix');
}
}
}

View File

@@ -151,6 +151,7 @@ class Importer
$transactionType = $this->getTransactionType(); // defaults to deposit
$errors = new MessageBag;
$journal = TransactionJournal::create(
[
'user_id' => Auth::user()->id,

View File

@@ -1,42 +0,0 @@
<?php
/**
* AnyAccount.php
* Copyright (C) 2016 thegrumpydictator@gmail.com
*
* This software may be modified and distributed under the terms
* of the MIT license. See the LICENSE file for details.
*/
declare(strict_types = 1);
namespace FireflyIII\Helpers\Csv\Mapper;
use Auth;
use FireflyIII\Models\Account;
/**
* Class AnyAccount
*
* @package FireflyIII\Helpers\Csv\Mapper
*/
class AnyAccount implements MapperInterface
{
/**
* @return array
*/
public function getMap(): array
{
$result = Auth::user()->accounts()->with('accountType')->orderBy('accounts.name', 'ASC')->get(['accounts.*']);
$list = [];
/** @var Account $account */
foreach ($result as $account) {
$list[$account->id] = $account->name . ' (' . $account->accountType->type . ')';
}
asort($list);
$list = [0 => trans('firefly.csv_do_not_map')] + $list;
return $list;
}
}

View File

@@ -1,42 +0,0 @@
<?php
/**
* Bill.php
* Copyright (C) 2016 thegrumpydictator@gmail.com
*
* This software may be modified and distributed under the terms
* of the MIT license. See the LICENSE file for details.
*/
declare(strict_types = 1);
namespace FireflyIII\Helpers\Csv\Mapper;
use Auth;
use FireflyIII\Models\Bill as BillModel;
/**
* Class Bill
*
* @package FireflyIII\Helpers\Csv\Mapper
*/
class Bill implements MapperInterface
{
/**
* @return array
*/
public function getMap(): array
{
$result = Auth::user()->bills()->get(['bills.*']);
$list = [];
/** @var BillModel $bill */
foreach ($result as $bill) {
$list[$bill->id] = $bill->name . ' [' . $bill->match . ']';
}
asort($list);
$list = [0 => trans('firefly.csv_do_not_map')] + $list;
return $list;
}
}

View File

@@ -1,42 +0,0 @@
<?php
/**
* Budget.php
* Copyright (C) 2016 thegrumpydictator@gmail.com
*
* This software may be modified and distributed under the terms
* of the MIT license. See the LICENSE file for details.
*/
declare(strict_types = 1);
namespace FireflyIII\Helpers\Csv\Mapper;
use Auth;
use FireflyIII\Models\Budget as BudgetModel;
/**
* Class Budget
*
* @package FireflyIII\Helpers\Csv\Mapper
*/
class Budget implements MapperInterface
{
/**
* @return array
*/
public function getMap(): array
{
$result = Auth::user()->budgets()->get(['budgets.*']);
$list = [];
/** @var BudgetModel $budget */
foreach ($result as $budget) {
$list[$budget->id] = $budget->name;
}
asort($list);
$list = [0 => trans('firefly.csv_do_not_map')] + $list;
return $list;
}
}

View File

@@ -1,42 +0,0 @@
<?php
/**
* Category.php
* Copyright (C) 2016 thegrumpydictator@gmail.com
*
* This software may be modified and distributed under the terms
* of the MIT license. See the LICENSE file for details.
*/
declare(strict_types = 1);
namespace FireflyIII\Helpers\Csv\Mapper;
use Auth;
use FireflyIII\Models\Category as CategoryModel;
/**
* Class Category
*
* @package FireflyIII\Helpers\Csv\Mapper
*/
class Category implements MapperInterface
{
/**
* @return array
*/
public function getMap(): array
{
$result = Auth::user()->categories()->get(['categories.*']);
$list = [];
/** @var CategoryModel $category */
foreach ($result as $category) {
$list[$category->id] = $category->name;
}
asort($list);
$list = [0 => trans('firefly.csv_do_not_map')] + $list;
return $list;
}
}

View File

@@ -1,42 +0,0 @@
<?php
/**
* Tag.php
* Copyright (C) 2016 thegrumpydictator@gmail.com
*
* This software may be modified and distributed under the terms
* of the MIT license. See the LICENSE file for details.
*/
declare(strict_types = 1);
namespace FireflyIII\Helpers\Csv\Mapper;
use Auth;
use FireflyIII\Models\Tag as TagModel;
/**
* Class Tag
*
* @package FireflyIII\Helpers\Csv\Mapper
*/
class Tag implements MapperInterface
{
/**
* @return array
*/
public function getMap(): array
{
$result = Auth::user()->budgets()->get(['tags.*']);
$list = [];
/** @var TagModel $tag */
foreach ($result as $tag) {
$list[$tag->id] = $tag->tag;
}
asort($list);
$list = [0 => trans('firefly.csv_do_not_map')] + $list;
return $list;
}
}

View File

@@ -1,44 +0,0 @@
<?php
/**
* Amount.php
* Copyright (C) 2016 thegrumpydictator@gmail.com
*
* This software may be modified and distributed under the terms
* of the MIT license. See the LICENSE file for details.
*/
declare(strict_types = 1);
namespace FireflyIII\Helpers\Csv\PostProcessing;
/**
* Class Amount
*
* @package FireflyIII\Helpers\Csv\PostProcessing
*/
class Amount implements PostProcessorInterface
{
/** @var array */
protected $data;
/**
* @return array
*/
public function process(): array
{
$amount = $this->data['amount'] ?? '0';
$modifier = strval($this->data['amount-modifier']);
$this->data['amount'] = bcmul($amount, $modifier);
return $this->data;
}
/**
* @param array $data
*/
public function setData(array $data)
{
$this->data = $data;
}
}

View File

@@ -1,274 +0,0 @@
<?php
/**
* AssetAccount.php
* Copyright (C) 2016 thegrumpydictator@gmail.com
*
* This software may be modified and distributed under the terms
* of the MIT license. See the LICENSE file for details.
*/
declare(strict_types = 1);
namespace FireflyIII\Helpers\Csv\PostProcessing;
use Auth;
use Carbon\Carbon;
use FireflyIII\Crud\Account\AccountCrudInterface;
use FireflyIII\Models\Account;
use FireflyIII\Models\AccountType;
use Validator;
/**
* Class AssetAccount
*
* @package FireflyIII\Helpers\Csv\PostProcessing
*/
class AssetAccount implements PostProcessorInterface
{
/** @var array */
protected $data;
/**
* @return array
*/
public function process(): array
{
$result = $this->checkIdNameObject(); // has object in ID or Name?
if (!is_null($result)) {
return $result;
}
// no object? maybe asset-account-iban is a string and we can find the matching account.
$result = $this->checkIbanString();
if (!is_null($result)) {
return $result;
}
// no object still? maybe we can find the account by name.
$result = $this->checkNameString();
if (!is_null($result)) {
return $result;
}
// still nothing? Perhaps the account number can lead us to an account:
$result = $this->checkAccountNumberString();
if (!is_null($result)) {
return $result;
}
return null;
}
/**
* @param array $data
*/
public function setData(array $data)
{
$this->data = $data;
}
/**
* @return array|null
*/
protected function checkAccountNumberString()
{
$accountNumber = $this->data['asset-account-number'] ?? null;
if ($accountNumber instanceof Account) { // fourth: try to find account based on name, if any.
$this->data['asset-account-object'] = $accountNumber;
return $this->data;
}
if (is_string($accountNumber)) { // it's an actual account number
$this->data['asset-account-object'] = $this->parseAccountNumberString();
return $this->data;
}
return null;
}
/**
* @return array|null
*/
protected function checkIbanString()
{
$iban = $this->data['asset-account-iban'] ?? '';
$rules = ['iban' => 'iban'];
$check = ['iban' => $iban];
$validator = Validator::make($check, $rules);
if (!$validator->fails()) {
$this->data['asset-account-object'] = $this->parseIbanString();
return $this->data;
}
return null;
}
/**
* @return array
*/
protected function checkIdNameObject()
{
$accountId = $this->data['asset-account-id'] ?? null;
$accountIban = $this->data['asset-account-iban'] ?? null;
$accountNumber = $this->data['asset-account-number'] ?? null;
if ($accountId instanceof Account) { // first priority. try to find the account based on ID, if any
$this->data['asset-account-object'] = $accountId;
return $this->data;
}
if ($accountIban instanceof Account) { // second: try to find the account based on IBAN, if any.
$this->data['asset-account-object'] = $accountIban;
return $this->data;
}
if ($accountNumber instanceof Account) { // second: try to find the account based on account number, if any.
$this->data['asset-account-object'] = $accountNumber;
return $this->data;
}
return null;
}
/**
* @return array|null
*/
protected function checkNameString()
{
$accountName = $this->data['asset-account-name'] ?? null;
if ($accountName instanceof Account) { // third: try to find account based on name, if any.
$this->data['asset-account-object'] = $accountName;
return $this->data;
}
if (is_string($accountName)) {
$this->data['asset-account-object'] = $this->parseNameString();
return $this->data;
}
return null;
}
/**
* @return Account|null
*/
protected function createAccount()
{
$accountType = $this->getAccountType();
$name = $this->data['asset-account-name'] ?? '';
$iban = $this->data['asset-account-iban'] ?? '';
// create if not exists: // See issue #180
$name = strlen($name) > 0 ? $name : $iban;
$account = Account::firstOrCreateEncrypted(
[
'user_id' => Auth::user()->id,
'account_type_id' => $accountType->id,
'name' => $name,
'iban' => $iban,
'active' => true,
]
);
return $account;
}
/**
*
* @return AccountType
*/
protected function getAccountType()
{
return AccountType::where('type', 'Asset account')->first();
}
/**
* @return Account|null
*/
protected function parseIbanString()
{
// create by name and/or iban.
$iban = $this->data['asset-account-iban'] ?? '';
$accounts = Auth::user()->accounts()->get();
foreach ($accounts as $entry) {
if ($iban !== '' && $entry->iban === $iban) {
return $entry;
}
}
$account = $this->createAccount();
return $account;
}
/**
* @return Account|null
*/
protected function parseNameString()
{
$accountType = $this->getAccountType();
$accounts = Auth::user()->accounts()->where('account_type_id', $accountType->id)->get();
foreach ($accounts as $entry) {
if ($entry->name == $this->data['asset-account-name']) {
return $entry;
}
}
// create if not exists:
// See issue #180
$account = Account::firstOrCreateEncrypted(
[
'user_id' => Auth::user()->id,
'account_type_id' => $accountType->id,
'name' => $this->data['asset-account-name'],
'iban' => '',
'active' => true,
]
);
return $account;
}
/**
* @return Account|null
*/
private function parseAccountNumberString()
{
/** @var AccountCrudInterface $crud */
$crud = app(AccountCrudInterface::class);
$accountNumber = $this->data['asset-account-number'] ?? '';
$accountType = $this->getAccountType();
$accounts = Auth::user()->accounts()->with(['accountmeta'])->where('account_type_id', $accountType->id)->get();
/** @var Account $entry */
foreach ($accounts as $entry) {
$metaFieldValue = $entry->getMeta('accountNumber');
if ($metaFieldValue === $accountNumber && $metaFieldValue !== '') {
return $entry;
}
}
// create new if not exists and return that one:
$accountData = [
'name' => $accountNumber,
'accountType' => 'asset',
'virtualBalance' => 0,
'virtualBalanceCurrency' => 1, // hard coded.
'active' => true,
'user' => Auth::user()->id,
'iban' => null,
'accountNumber' => $accountNumber,
'accountRole' => null,
'openingBalance' => 0,
'openingBalanceDate' => new Carbon,
'openingBalanceCurrency' => 1, // hard coded.
];
$account = $crud->store($accountData);
return $account;
}
}

View File

@@ -1,45 +0,0 @@
<?php
/**
* Bill.php
* Copyright (C) 2016 thegrumpydictator@gmail.com
*
* This software may be modified and distributed under the terms
* of the MIT license. See the LICENSE file for details.
*/
declare(strict_types = 1);
namespace FireflyIII\Helpers\Csv\PostProcessing;
/**
* Class Bill
*
* @package FireflyIII\Helpers\Csv\PostProcessing
*/
class Bill implements PostProcessorInterface
{
/** @var array */
protected $data;
/**
* @return array
*/
public function process(): array
{
// get bill id.
if (!is_null($this->data['bill']) && !is_null($this->data['bill']->id)) {
$this->data['bill-id'] = $this->data['bill']->id;
}
return $this->data;
}
/**
* @param array $data
*/
public function setData(array $data)
{
$this->data = $data;
}
}

View File

@@ -1,49 +0,0 @@
<?php
/**
* Currency.php
* Copyright (C) 2016 thegrumpydictator@gmail.com
*
* This software may be modified and distributed under the terms
* of the MIT license. See the LICENSE file for details.
*/
declare(strict_types = 1);
namespace FireflyIII\Helpers\Csv\PostProcessing;
use FireflyIII\Models\TransactionCurrency;
use Preferences;
/**
* Class Currency
*
* @package FireflyIII\Helpers\Csv\PostProcessing
*/
class Currency implements PostProcessorInterface
{
/** @var array */
protected $data;
/**
* @return array
*/
public function process(): array
{
// fix currency
if (is_null($this->data['currency'])) {
$currencyPreference = Preferences::get('currencyPreference', env('DEFAULT_CURRENCY', 'EUR'));
$this->data['currency'] = TransactionCurrency::whereCode($currencyPreference->data)->first();
}
return $this->data;
}
/**
* @param array $data
*/
public function setData(array $data)
{
$this->data = $data;
}
}

View File

@@ -1,47 +0,0 @@
<?php
/**
* Description.php
* Copyright (C) 2016 thegrumpydictator@gmail.com
*
* This software may be modified and distributed under the terms
* of the MIT license. See the LICENSE file for details.
*/
declare(strict_types = 1);
namespace FireflyIII\Helpers\Csv\PostProcessing;
/**
* Class Description
*
* @package FireflyIII\Helpers\Csv\PostProcessing
*/
class Description implements PostProcessorInterface
{
/** @var array */
protected $data;
/**
* @return array
*/
public function process(): array
{
$description = $this->data['description'] ?? '';
$this->data['description'] = trim($description);
if (strlen($this->data['description']) == 0) {
$this->data['description'] = trans('firefly.csv_empty_description');
}
return $this->data;
}
/**
* @param array $data
*/
public function setData(array $data)
{
$this->data = $data;
}
}

View File

@@ -1,210 +0,0 @@
<?php
/**
* OpposingAccount.php
* Copyright (C) 2016 thegrumpydictator@gmail.com
*
* This software may be modified and distributed under the terms
* of the MIT license. See the LICENSE file for details.
*/
declare(strict_types = 1);
namespace FireflyIII\Helpers\Csv\PostProcessing;
use Auth;
use FireflyIII\Models\Account;
use FireflyIII\Models\AccountType;
use Validator;
/**
* Class OpposingAccount
*
* @package FireflyIII\Helpers\Csv\PostProcessing
*/
class OpposingAccount implements PostProcessorInterface
{
/** @var array */
protected $data;
/**
* @return array
*/
public function process(): array
{
// three values:
// opposing-account-id, opposing-account-iban, opposing-account-name
$result = $this->checkIdNameObject();
if (!is_null($result)) {
return $result;
}
$result = $this->checkIbanString();
if (!is_null($result)) {
return $result;
}
$result = $this->checkNameString();
if (!is_null($result)) {
return $result;
}
return null;
}
/**
* @param array $data
*/
public function setData(array $data)
{
$this->data = $data;
}
/**
* @return array|null
*/
protected function checkIbanString()
{
$rules = ['iban' => 'iban'];
$iban = $this->data['opposing-account-iban'];
$check = ['iban' => $iban];
$validator = Validator::make($check, $rules);
if (is_string($iban) && strlen($iban) > 0 && !$validator->fails()) {
$this->data['opposing-account-object'] = $this->parseIbanString();
return $this->data;
}
return null;
}
/**
* @return array
*/
protected function checkIdNameObject()
{
if ($this->data['opposing-account-id'] instanceof Account) { // first priority. try to find the account based on ID, if any
$this->data['opposing-account-object'] = $this->data['opposing-account-id'];
return $this->data;
}
if ($this->data['opposing-account-iban'] instanceof Account) { // second: try to find the account based on IBAN, if any.
$this->data['opposing-account-object'] = $this->data['opposing-account-iban'];
return $this->data;
}
return null;
}
/**
* @return array|null
*/
protected function checkNameString()
{
if ($this->data['opposing-account-name'] instanceof Account) { // third: try to find account based on name, if any.
$this->data['opposing-account-object'] = $this->data['opposing-account-name'];
return $this->data;
}
if (is_string($this->data['opposing-account-name'])) {
$this->data['opposing-account-object'] = $this->parseNameString();
return $this->data;
}
return null;
}
/**
* @return Account|null
*/
protected function createAccount()
{
$accountType = $this->getAccountType();
// create if not exists:
$name = is_string($this->data['opposing-account-name']) && strlen($this->data['opposing-account-name']) > 0 ? $this->data['opposing-account-name']
: $this->data['opposing-account-iban'];
$account = Account::firstOrCreateEncrypted( // See issue #180
[
'user_id' => Auth::user()->id,
'account_type_id' => $accountType->id,
'name' => $name,
'iban' => $this->data['opposing-account-iban'],
'active' => true,
]
);
return $account;
}
/**
*
* @return AccountType
*/
protected function getAccountType()
{
// opposing account type:
if ($this->data['amount'] < 0) {
// create expense account:
return AccountType::where('type', 'Expense account')->first();
}
// create revenue account:
return AccountType::where('type', 'Revenue account')->first();
}
/**
* @return Account|null
*/
protected function parseIbanString()
{
// create by name and/or iban.
$accounts = Auth::user()->accounts()->get();
foreach ($accounts as $entry) {
if ($entry->iban == $this->data['opposing-account-iban']) {
return $entry;
}
}
$account = $this->createAccount();
return $account;
}
/**
* @return Account|null
*/
protected function parseNameString()
{
$accountType = $this->getAccountType();
$accounts = Auth::user()->accounts()->where('account_type_id', $accountType->id)->get();
foreach ($accounts as $entry) {
if ($entry->name == $this->data['opposing-account-name']) {
return $entry;
}
}
// create if not exists:
$account = Account::firstOrCreateEncrypted( // See issue #180
[
'user_id' => Auth::user()->id,
'account_type_id' => $accountType->id,
'name' => $this->data['opposing-account-name'],
'iban' => '',
'active' => true,
]
);
return $account;
}
}

View File

@@ -1,31 +0,0 @@
<?php
/**
* PostProcessorInterface.php
* Copyright (C) 2016 thegrumpydictator@gmail.com
*
* This software may be modified and distributed under the terms
* of the MIT license. See the LICENSE file for details.
*/
declare(strict_types = 1);
namespace FireflyIII\Helpers\Csv\PostProcessing;
/**
* Interface PostProcessorInterface
*
* @package FireflyIII\Helpers\Csv\PostProcessing
*/
interface PostProcessorInterface
{
/**
* @return array
*/
public function process(): array;
/**
* @param array $data
*/
public function setData(array $data);
}

View File

@@ -1,60 +0,0 @@
<?php
/**
* Dummy.php
* Copyright (C) 2016 thegrumpydictator@gmail.com
*
* This software may be modified and distributed under the terms
* of the MIT license. See the LICENSE file for details.
*/
declare(strict_types = 1);
namespace FireflyIII\Helpers\Csv\Specifix;
/**
* Class Dummy
*
* @package FireflyIII\Helpers\Csv\Specifix
*/
class Dummy extends Specifix implements SpecifixInterface
{
/** @var array */
protected $data;
/** @var array */
protected $row;
/**
* Dummy constructor.
*/
public function __construct()
{
$this->setProcessorType(self::POST_PROCESSOR);
}
/**
* @return array
*/
public function fix(): array
{
return $this->data;
}
/**
* @param array $data
*/
public function setData(array $data)
{
$this->data = $data;
}
/**
* @param array $row
*/
public function setRow(array $row)
{
$this->row = $row;
}
}

View File

@@ -1,76 +0,0 @@
<?php
/**
* RabobankDescription.php
* Copyright (C) 2016 thegrumpydictator@gmail.com
*
* This software may be modified and distributed under the terms
* of the MIT license. See the LICENSE file for details.
*/
declare(strict_types = 1);
namespace FireflyIII\Helpers\Csv\Specifix;
/**
* Class RabobankDescription
*
* @package FireflyIII\Helpers\Csv\Specifix
*/
class RabobankDescription extends Specifix implements SpecifixInterface
{
/** @var array */
protected $data;
/** @var array */
protected $row;
/**
* RabobankDescription constructor.
*/
public function __construct()
{
$this->setProcessorType(self::POST_PROCESSOR);
}
/**
* @return array
*/
public function fix(): array
{
$this->rabobankFixEmptyOpposing();
return $this->data;
}
/**
* @param array $data
*/
public function setData(array $data)
{
$this->data = $data;
}
/**
* @param array $row
*/
public function setRow(array $row)
{
$this->row = $row;
}
/**
* Fixes Rabobank specific thing.
*/
protected function rabobankFixEmptyOpposing()
{
if (is_string($this->data['opposing-account-name']) && strlen($this->data['opposing-account-name']) == 0) {
$this->data['opposing-account-name'] = $this->row[10];
$this->data['description'] = trim(str_replace($this->row[10], '', $this->data['description']));
}
}
}

View File

@@ -1,46 +0,0 @@
<?php
/**
* Specifix.php
* Copyright (C) 2016 thegrumpydictator@gmail.com
*
* This software may be modified and distributed under the terms
* of the MIT license. See the LICENSE file for details.
*/
declare(strict_types = 1);
namespace FireflyIII\Helpers\Csv\Specifix;
/**
* Class Specifix
*
* @package FireflyIII\Helpers\Csv\Specifix
*/
class Specifix
{
/** @var int */
protected $processorType;
/**
* @return int
*/
public function getProcessorType(): int
{
return $this->processorType;
}
/**
* @param int $processorType
*
* @return $this
*/
public function setProcessorType(int $processorType)
{
$this->processorType = $processorType;
return $this;
}
}

View File

@@ -1,49 +0,0 @@
<?php
/**
* SpecifixInterface.php
* Copyright (C) 2016 thegrumpydictator@gmail.com
*
* This software may be modified and distributed under the terms
* of the MIT license. See the LICENSE file for details.
*/
declare(strict_types = 1);
namespace FireflyIII\Helpers\Csv\Specifix;
/**
* Interface SpecifixInterface
*
* @package FireflyIII\Helpers\Csv\Specifix
*/
interface SpecifixInterface
{
const PRE_PROCESSOR = 1;
const POST_PROCESSOR = 2;
/**
* Implement bank and locale related fixes.
*/
public function fix();
/**
* @return int
*/
public function getProcessorType(): int;
/**
* @param array $data
*/
public function setData(array $data);
/**
* @param int $processorType
*
* @return $this
*/
public function setProcessorType(int $processorType);
/**
* @param array $row
*/
public function setRow(array $row);
}

View File

@@ -1,202 +0,0 @@
<?php
/**
* Wizard.php
* Copyright (C) 2016 thegrumpydictator@gmail.com
*
* This software may be modified and distributed under the terms
* of the MIT license. See the LICENSE file for details.
*/
declare(strict_types = 1);
namespace FireflyIII\Helpers\Csv;
use Auth;
use Crypt;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Helpers\Csv\Mapper\MapperInterface;
use League\Csv\Reader;
use Log;
use ReflectionException;
use Session;
use SplFileObject;
use Storage;
/**
* Class Wizard
*
* @package FireflyIII\Helpers\Csv
*/
class Wizard implements WizardInterface
{
/**
* @param Reader $reader
* @param array $map
* @param bool $hasHeaders
*
* @return array
*/
public function getMappableValues(Reader $reader, array $map, bool $hasHeaders): array
{
$values = [];
/*
* Loop over the CSV and collect mappable data:
*/
$keys = array_keys($map);
foreach ($reader as $index => $row) {
if ($this->useRow($hasHeaders, $index)) {
// collect all map values
foreach ($keys as $column) {
$values[$column][] = $row[$column];
}
}
}
/*
* Make each one unique.
*/
$values = $this->uniqueRecursive($values);
return $values;
}
/**
* @param array $roles
* @param array $map
*
* @return array
*/
public function processSelectedMapping(array $roles, array $map): array
{
$configRoles = config('csv.roles');
$maps = [];
$keys = array_keys($map);
foreach ($keys as $index) {
if (isset($roles[$index])) {
$name = $roles[$index];
if ($configRoles[$name]['mappable']) {
$maps[$index] = $name;
}
}
}
return $maps;
}
/**
* @param array $input
*
* @return array
*/
public function processSelectedRoles(array $input): array
{
$roles = [];
/*
* Store all rows for each column:
*/
if (is_array($input)) {
foreach ($input as $index => $role) {
if ($role != '_ignore') {
$roles[$index] = $role;
}
}
}
return $roles;
}
/**
* @param array $fields
*
* @return bool
*/
public function sessionHasValues(array $fields): bool
{
foreach ($fields as $field) {
if (!Session::has($field)) {
Log::error('Session is missing field: ' . $field);
return false;
}
}
return true;
}
/**
* @param array $map
*
* @return array
* @throws FireflyException
*/
public function showOptions(array $map): array
{
$options = [];
foreach ($map as $index => $columnRole) {
$mapper = config('csv.roles.' . $columnRole . '.mapper');
if (is_null($mapper)) {
throw new FireflyException('Cannot map field of type "' . $columnRole . '".');
}
$class = 'FireflyIII\Helpers\Csv\Mapper\\' . $mapper;
try {
/** @var MapperInterface $mapObject */
$mapObject = app($class);
} catch (ReflectionException $e) {
throw new FireflyException('Column "' . $columnRole . '" cannot be mapped because mapper class ' . $mapper . ' does not exist.');
}
$set = $mapObject->getMap();
$options[$index] = $set;
}
return $options;
}
/**
* @param string $path
*
* @return string
*/
public function storeCsvFile(string $path): string
{
$time = str_replace(' ', '-', microtime());
$fileName = 'csv-upload-' . Auth::user()->id . '-' . $time . '.csv.encrypted';
$disk = Storage::disk('upload');
$file = new SplFileObject($path, 'r');
$content = $file->fread($file->getSize());
$contentEncrypted = Crypt::encrypt($content);
$disk->put($fileName, $contentEncrypted);
return $fileName;
}
/**
* @param array $array
*
* @return array
*/
protected function uniqueRecursive(array $array)
{
foreach ($array as $column => $found) {
$array[$column] = array_unique($found);
}
return $array;
}
/**
* @param bool $hasHeaders
* @param int $index
*
* @return bool
*/
protected function useRow(bool $hasHeaders, int $index)
{
return ($hasHeaders && $index > 1) || !$hasHeaders;
}
}

View File

@@ -1,68 +0,0 @@
<?php
/**
* WizardInterface.php
* Copyright (C) 2016 thegrumpydictator@gmail.com
*
* This software may be modified and distributed under the terms
* of the MIT license. See the LICENSE file for details.
*/
declare(strict_types = 1);
namespace FireflyIII\Helpers\Csv;
use League\Csv\Reader;
/**
* Interface WizardInterface
*
* @package FireflyIII\Helpers\Csv
*/
interface WizardInterface
{
/**
* @param Reader $reader
* @param array $map
* @param bool $hasHeaders
*
* @return array
*/
public function getMappableValues(Reader $reader, array $map, bool $hasHeaders): array;
/**
* @param array $roles
* @param array $map
*
* @return array
*/
public function processSelectedMapping(array $roles, array $map): array;
/**
* @param array $input
*
* @return array
*/
public function processSelectedRoles(array $input): array;
/**
* @param array $fields
*
* @return bool
*/
public function sessionHasValues(array $fields): bool;
/**
* @param array $map
*
* @return array
*/
public function showOptions(array $map): array;
/**
* @param string $path
*
* @return string
*/
public function storeCsvFile(string $path): string;
}

View File

@@ -58,8 +58,7 @@ class BalanceReportHelper implements BalanceReportHelperInterface
*/
public function getBalanceReport(Carbon $start, Carbon $end, Collection $accounts): Balance
{
$balance = new Balance;
// build a balance header:
$balance = new Balance;
$header = new BalanceHeader;
$limitRepetitions = $this->budgetRepository->getAllBudgetLimitRepetitions($start, $end);
foreach ($accounts as $account) {

View File

@@ -18,6 +18,7 @@ use FireflyIII\Helpers\Collection\BudgetLine;
use FireflyIII\Models\Budget;
use FireflyIII\Models\LimitRepetition;
use FireflyIII\Repositories\Budget\BudgetRepositoryInterface;
use FireflyIII\Support\CacheProperties;
use Illuminate\Support\Collection;
/**
@@ -40,6 +41,73 @@ class BudgetReportHelper implements BudgetReportHelperInterface
$this->repository = $repository;
}
/**
* @param Carbon $start
* @param Carbon $end
* @param Collection $accounts
*
* @return Collection
*/
public function budgetYearOverview(Carbon $start, Carbon $end, Collection $accounts): Collection
{
// chart properties for cache:
$cache = new CacheProperties;
$cache->addProperty($start);
$cache->addProperty($end);
$cache->addProperty('budget-year');
$cache->addProperty($accounts->pluck('id')->toArray());
if ($cache->has()) {
return $cache->get();
}
$headers = [];
$current = clone $start;
$return = new Collection;
$set = $this->repository->getBudgets();
$budgets = [];
$spent = [];
while ($current < $end) {
$short = $current->format('m-Y');
$headers[$short] = $current->formatLocalized((string)trans('config.month'));
$current->addMonth();
}
/** @var Budget $budget */
foreach ($set as $budget) {
$id = $budget->id;
$budgets[$id] = $budget->name;
$spent[$id] = [];
$current = clone $start;
$sum = '0';
while ($current < $end) {
$currentEnd = clone $current;
$currentEnd->endOfMonth();
$format = $current->format('m-Y');
$budgetSpent = $this->repository->spentInPeriod(new Collection([$budget]), $accounts, $current, $currentEnd);
$spent[$id][$format] = $budgetSpent;
$sum = bcadd($sum, $budgetSpent);
$current->addMonth();
}
if (bccomp('0', $sum) === 0) {
// not spent anything.
unset($spent[$id]);
unset($budgets[$id]);
}
}
$return->put('headers', $headers);
$return->put('budgets', $budgets);
$return->put('spent', $spent);
$cache->store($return);
return $return;
}
/**
* @param Carbon $start
* @param Carbon $end

View File

@@ -23,6 +23,15 @@ use Illuminate\Support\Collection;
*/
interface BudgetReportHelperInterface
{
/**
* @param Carbon $start
* @param Carbon $end
* @param Collection $accounts
*
* @return Collection
*/
public function budgetYearOverview(Carbon $start, Carbon $end, Collection $accounts): Collection;
/**
* @param Carbon $start
* @param Carbon $end

View File

@@ -251,6 +251,7 @@ class AccountController extends Controller
$end = Navigation::subtractPeriod($end, $range, 1);
}
$cache->store($entries);
return view('accounts.show', compact('account', 'what', 'entries', 'subTitleIcon', 'journals', 'subTitle'));
}
@@ -270,6 +271,7 @@ class AccountController extends Controller
$end = Navigation::endOfPeriod($carbon, $range);
$subTitle = $account->name . ' (' . Navigation::periodShow($start, $range) . ')';
$page = intval(Input::get('page'));
$page = $page === 0 ? 1 : $page;
$pageSize = Preferences::get('transactionPageSize', 50)->data;
$offset = ($page - 1) * $pageSize;
$set = $repository->journalsInPeriod(new Collection([$account]), [], $start, $end);

View File

@@ -0,0 +1,136 @@
<?php
/**
* DomainController.php
* Copyright (C) 2016 thegrumpydictator@gmail.com
*
* This software may be modified and distributed under the terms
* of the MIT license. See the LICENSE file for details.
*/
declare(strict_types = 1);
namespace FireflyIII\Http\Controllers\Admin;
use FireflyIII\Http\Controllers\Controller;
use FireflyIII\Support\Facades\FireflyConfig;
use FireflyIII\User;
use Illuminate\Http\Request;
use Session;
/**
* Class DomainController
*
* @package FireflyIII\Http\Controllers\Admin
*/
class DomainController extends Controller
{
/**
* @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
*/
public function domains()
{
$title = strval(trans('firefly.administration'));
$mainTitleIcon = 'fa-hand-spock-o';
$subTitle = strval(trans('firefly.blocked_domains'));
$subTitleIcon = 'fa-users';
$domains = FireflyConfig::get('blocked-domains', [])->data;
// known domains
$knownDomains = $this->getKnownDomains();
return view('admin.domains.index', compact('title', 'mainTitleIcon', 'knownDomains', 'subTitle', 'subTitleIcon', 'domains'));
}
/**
* @param Request $request
*
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
*/
public function manual(Request $request)
{
if (strlen($request->get('domain')) === 0) {
Session::flash('error', trans('firefly.no_domain_filled_in'));
return redirect(route('admin.users.domains'));
}
$domain = $request->get('domain');
$blocked = FireflyConfig::get('blocked-domains', [])->data;
if (in_array($domain, $blocked)) {
Session::flash('error', trans('firefly.domain_already_blocked', ['domain' => $domain]));
return redirect(route('admin.users.domains'));
}
$blocked[] = $domain;
FireflyConfig::set('blocked-domains', $blocked);
Session::flash('success', trans('firefly.domain_is_now_blocked', ['domain' => $domain]));
return redirect(route('admin.users.domains'));
}
/**
* @param string $domain
*
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
*/
public function toggleDomain(string $domain)
{
$blocked = FireflyConfig::get('blocked-domains', [])->data;
if (in_array($domain, $blocked)) {
$key = array_search($domain, $blocked);
unset($blocked[$key]);
sort($blocked);
FireflyConfig::set('blocked-domains', $blocked);
Session::flash('message', trans('firefly.domain_now_unblocked', ['domain' => $domain]));
return redirect(route('admin.users.domains'));
}
$blocked[] = $domain;
FireflyConfig::set('blocked-domains', $blocked);
Session::flash('message', trans('firefly.domain_now_blocked', ['domain' => $domain]));
return redirect(route('admin.users.domains'));
}
/**
* @return array
*/
private function getKnownDomains(): array
{
$users = User::get();
$set = [];
$filtered = [];
/** @var User $user */
foreach ($users as $user) {
$email = $user->email;
$parts = explode('@', $email);
$domain = $parts[1];
$set[] = $domain;
}
$set = array_unique($set);
// filter for already banned domains:
$blocked = FireflyConfig::get('blocked-domains', [])->data;
foreach ($set as $domain) {
// in the block array? ignore it.
if (!in_array($domain, $blocked)) {
$filtered[] = $domain;
}
}
asort($filtered);
return $filtered;
}
}

View File

@@ -24,8 +24,23 @@ use Preferences;
*/
class UserController extends Controller
{
/**
* @param User $user
*
* @return int
*/
public function edit(User $user)
{
return $user->id;
}
/**
* @param UserRepositoryInterface $repository
*
* @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
*/
public function index(UserRepositoryInterface $repository)
{
@@ -61,4 +76,5 @@ class UserController extends Controller
}
}

View File

@@ -18,6 +18,7 @@ use FireflyIII\Http\Requests\AttachmentFormRequest;
use FireflyIII\Models\Attachment;
use FireflyIII\Repositories\Attachment\AttachmentRepositoryInterface;
use Input;
use Log;
use Preferences;
use Response;
use Session;
@@ -93,9 +94,11 @@ class AttachmentController extends Controller
if ($disk->exists($file)) {
$quoted = sprintf('"%s"', addcslashes(basename($attachment->filename), '"\\'));
$content = Crypt::decrypt($disk->get($file));
Log::debug('Send file to user', ['file' => $quoted, 'size' => strlen($content)]);
return response(Crypt::decrypt($disk->get($file)), 200)
return response($content, 200)
->header('Content-Description', 'File Transfer')
->header('Content-Type', 'application/octet-stream')
->header('Content-Disposition', 'attachment; filename=' . $quoted)
@@ -104,7 +107,7 @@ class AttachmentController extends Controller
->header('Expires', '0')
->header('Cache-Control', 'must-revalidate, post-check=0, pre-check=0')
->header('Pragma', 'public')
->header('Content-Length', $disk->size($file));
->header('Content-Length', strlen($content));
}
throw new FireflyException('Could not find the indicated attachment. The file is no longer there.');

View File

@@ -15,6 +15,7 @@ use Auth;
use FireflyIII\Events\UserRegistration;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Http\Controllers\Controller;
use FireflyIII\Support\Facades\FireflyConfig;
use FireflyIII\User;
use Illuminate\Foundation\Auth\AuthenticatesAndRegistersUsers;
use Illuminate\Foundation\Auth\ThrottlesLogins;
@@ -63,6 +64,7 @@ class AuthController extends Controller
*/
public function login(Request $request)
{
$this->validate($request, [$this->loginUsername() => 'required', 'password' => 'required',]);
$throttles = $this->isUsingThrottlesLoginsTrait();
@@ -177,16 +179,7 @@ class AuthController extends Controller
*/
protected function getBlockedDomains()
{
$set = explode(',', env('BLOCKED_DOMAINS', ''));
$domains = [];
foreach ($set as $entry) {
$domain = trim($entry);
if (strlen($domain) > 0) {
$domains[] = $domain;
}
}
return $domains;
return FireflyConfig::get('blocked-domains', [])->data;
}
/**

View File

@@ -13,6 +13,7 @@ namespace FireflyIII\Http\Controllers\Auth;
use Auth;
use FireflyIII\Events\ResendConfirmation;
use FireflyIII\Events\UserIsConfirmed;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Http\Controllers\Controller;
use Illuminate\Http\Request;
@@ -36,12 +37,13 @@ class ConfirmationController extends Controller
}
/**
* @param string $code
* @param Request $request
* @param string $code
*
* @return mixed
* @throws FireflyException
*/
public function doConfirmation(string $code)
public function doConfirmation(Request $request, string $code)
{
// check user_confirmed_last_mail
@@ -51,6 +53,10 @@ class ConfirmationController extends Controller
$maxDiff = config('firefly.confirmation_age');
if ($database === $code && ($now - $time <= $maxDiff)) {
// trigger user registration event:
event(new UserIsConfirmed(Auth::user(), $request->ip()));
Preferences::setForUser(Auth::user(), 'user_confirmed', true);
Preferences::setForUser(Auth::user(), 'user_confirmed_confirmed', time());
Session::flash('success', strval(trans('firefly.account_is_confirmed')));

View File

@@ -11,6 +11,7 @@ declare(strict_types = 1);
namespace FireflyIII\Http\Controllers;
use Carbon\Carbon;
use FireflyIII\Http\Requests\BillFormRequest;
use FireflyIII\Models\Bill;
use FireflyIII\Models\TransactionJournal;
@@ -190,15 +191,20 @@ class BillController extends Controller
*/
public function show(BillRepositoryInterface $repository, Bill $bill)
{
$page = intval(Input::get('page')) == 0 ? 1 : intval(Input::get('page'));
$pageSize = Preferences::get('transactionPageSize', 50)->data;
$journals = $repository->getJournals($bill, $page, $pageSize);
/** @var Carbon $date */
$date = session('start');
$year = $date->year;
$page = intval(Input::get('page')) == 0 ? 1 : intval(Input::get('page'));
$pageSize = Preferences::get('transactionPageSize', 50)->data;
$journals = $repository->getJournals($bill, $page, $pageSize);
$yearAverage = $repository->getYearAverage($bill, $date);
$overallAverage = $repository->getOverallAverage($bill);
$journals->setPath('/bills/show/' . $bill->id);
$bill->nextExpectedMatch = $repository->nextExpectedMatch($bill);
$hideBill = true;
$subTitle = e($bill->name);
return view('bills.show', compact('journals', 'hideBill', 'bill', 'subTitle'));
return view('bills.show', compact('journals', 'yearAverage', 'overallAverage', 'year', 'hideBill', 'bill', 'subTitle'));
}
/**

View File

@@ -164,6 +164,8 @@ class BudgetController extends Controller
*/
public function index(BudgetRepositoryInterface $repository, AccountCrudInterface $crud)
{
$repository->cleanupBudgets();
$budgets = $repository->getActiveBudgets();
$inactive = $repository->getInactiveBudgets();
$spent = '0';

View File

@@ -13,7 +13,9 @@ namespace FireflyIII\Http\Controllers;
use Auth;
use Carbon\Carbon;
use FireflyIII\Crud\Account\AccountCrudInterface;
use FireflyIII\Http\Requests\CategoryFormRequest;
use FireflyIII\Models\AccountType;
use FireflyIII\Models\Category;
use FireflyIII\Repositories\Category\CategoryRepositoryInterface as CRI;
use FireflyIII\Support\CacheProperties;
@@ -156,12 +158,13 @@ class CategoryController extends Controller
}
/**
* @param CRI $repository
* @param Category $category
* @param CRI $repository
* @param AccountCrudInterface $crud
* @param Category $category
*
* @return \Illuminate\View\View
* @return View
*/
public function show(CRI $repository, Category $category)
public function show(CRI $repository, AccountCrudInterface $crud, Category $category)
{
/** @var Carbon $carbon */
$range = Preferences::get('viewRange', '1M')->data;
@@ -205,12 +208,12 @@ class CategoryController extends Controller
$categoryCollection = new Collection([$category]);
$empty = new Collection;
$accounts = $crud->getAccountsByType([AccountType::DEFAULT, AccountType::ASSET]);
while ($end >= $start) {
$end = Navigation::startOfPeriod($end, $range);
$currentEnd = Navigation::endOfPeriod($end, $range);
$spent = $repository->spentInPeriod($categoryCollection, $empty, $end, $currentEnd);
$earned = $repository->earnedInPeriod($categoryCollection, $empty, $end, $currentEnd);
$spent = $repository->spentInPeriod($categoryCollection, $accounts, $end, $currentEnd);
$earned = $repository->earnedInPeriod($categoryCollection, $accounts, $end, $currentEnd);
$dateStr = $end->format('Y-m-d');
$dateName = Navigation::periodShow($end, $range);
$entries->push([$dateStr, $dateName, $spent, $earned]);

View File

@@ -32,9 +32,12 @@ use Response;
class BudgetController extends Controller
{
/** @var \FireflyIII\Generator\Chart\Budget\BudgetChartGeneratorInterface */
/** @var BudgetChartGeneratorInterface */
protected $generator;
/** @var BudgetRepositoryInterface */
protected $repository;
/**
*
*/
@@ -43,6 +46,8 @@ class BudgetController extends Controller
parent::__construct();
// create chart generator:
$this->generator = app(BudgetChartGeneratorInterface::class);
$this->repository = app(BudgetRepositoryInterface::class);
}
/**
@@ -136,11 +141,9 @@ class BudgetController extends Controller
/**
* Shows a budget list with spent/left/overspent.
*
* @param BudgetRepositoryInterface $repository
*
* @return \Symfony\Component\HttpFoundation\Response
*/
public function frontpage(BudgetRepositoryInterface $repository)
public function frontpage()
{
$start = session('start', Carbon::now()->startOfMonth());
$end = session('end', Carbon::now()->endOfMonth());
@@ -153,54 +156,26 @@ class BudgetController extends Controller
if ($cache->has()) {
return Response::json($cache->get());
}
$budgets = $repository->getActiveBudgets();
$repetitions = $repository->getAllBudgetLimitRepetitions($start, $end);
$budgets = $this->repository->getActiveBudgets();
$repetitions = $this->repository->getAllBudgetLimitRepetitions($start, $end);
$allEntries = new Collection;
$format = strval(trans('config.month_and_day'));
/** @var Budget $budget */
foreach ($budgets as $budget) {
// get relevant repetitions:
$name = $budget->name;
$reps = $repetitions->filter(
function (LimitRepetition $repetition) use ($budget, $start, $end) {
if ($repetition->startdate < $end && $repetition->enddate > $start && $repetition->budget_id === $budget->id) {
return $repetition;
}
}
);
$reps = $this->filterRepetitions($repetitions, $budget, $start, $end);
if ($reps->count() === 0) {
$amount = '0';
$left = '0';
$spent = $repository->spentInPeriod(new Collection([$budget]), new Collection, $start, $end);
$overspent = '0';
$allEntries->push([$name, $left, $spent, $overspent, $amount, $spent]);
}
/** @var LimitRepetition $repetition */
foreach ($reps as $repetition) {
$expenses = $repository->spentInPeriod(new Collection([$budget]), new Collection, $repetition->startdate, $repetition->enddate);
if ($reps->count() > 1) {
$name = $budget->name . ' ' . trans(
'firefly.between_dates',
['start' => $repetition->startdate->formatLocalized($format), 'end' => $repetition->enddate->formatLocalized($format)]
);
}
$amount = $repetition->amount;
$left = bccomp(bcadd($amount, $expenses), '0') < 1 ? '0' : bcadd($amount, $expenses);
$spent = bccomp(bcadd($amount, $expenses), '0') < 1 ? bcmul($amount, '-1') : $expenses;
$overspent = bccomp(bcadd($amount, $expenses), '0') < 1 ? bcadd($amount, $expenses) : '0';
$allEntries->push([$name, $left, $spent, $overspent, $amount, $spent]);
$collection = $this->spentInPeriodSingle($budget, $start, $end);
$allEntries = $allEntries->merge($collection);
continue;
}
$collection = $this->spentInPeriodMulti($budget, $reps);
$allEntries = $allEntries->merge($collection);
}
$list = $repository->journalsInPeriodWithoutBudget(new Collection, $start, $end);
$sum = '0';
/** @var TransactionJournal $entry */
foreach ($list as $entry) {
$sum = bcadd(TransactionJournal::amount($entry), $sum);
}
$allEntries->push([trans('firefly.no_budget'), '0', '0', $sum, '0', '0']);
$entry = $this->spentInPeriodWithout($start, $end);
$allEntries->push($entry);
$data = $this->generator->frontpage($allEntries);
$cache->store($data);
@@ -335,4 +310,94 @@ class BudgetController extends Controller
return Response::json($data);
}
/**
* @param Collection $repetitions
* @param Budget $budget
* @param Carbon $start
* @param Carbon $end
*
* @return Collection
*/
private function filterRepetitions(Collection $repetitions, Budget $budget, Carbon $start, Carbon $end): Collection
{
return $repetitions->filter(
function (LimitRepetition $repetition) use ($budget, $start, $end) {
if ($repetition->startdate < $end && $repetition->enddate > $start && $repetition->budget_id === $budget->id) {
return $repetition;
}
}
);
}
/**
* @param Budget $budget
* @param Collection $repetitions
*
* @return Collection
*/
private function spentInPeriodMulti(Budget $budget, Collection $repetitions): Collection
{
$format = strval(trans('config.month_and_day'));
$collection = new Collection;
$name = $budget->name;
/** @var LimitRepetition $repetition */
foreach ($repetitions as $repetition) {
$expenses = $this->repository->spentInPeriod(new Collection([$budget]), new Collection, $repetition->startdate, $repetition->enddate);
if ($repetitions->count() > 1) {
$name = $budget->name . ' ' . trans(
'firefly.between_dates',
['start' => $repetition->startdate->formatLocalized($format), 'end' => $repetition->enddate->formatLocalized($format)]
);
}
$amount = $repetition->amount;
$left = bccomp(bcadd($amount, $expenses), '0') < 1 ? '0' : bcadd($amount, $expenses);
$spent = bccomp(bcadd($amount, $expenses), '0') < 1 ? bcmul($amount, '-1') : $expenses;
$overspent = bccomp(bcadd($amount, $expenses), '0') < 1 ? bcadd($amount, $expenses) : '0';
$array = [$name, $left, $spent, $overspent, $amount, $spent];
$collection->push($array);
}
return $collection;
}
/**
* @param Budget $budget
* @param Carbon $start
* @param Carbon $end
*
* @return Collection
*/
private function spentInPeriodSingle(Budget $budget, Carbon $start, Carbon $end): Collection
{
$collection = new Collection;
$amount = '0';
$left = '0';
$spent = $this->repository->spentInPeriod(new Collection([$budget]), new Collection, $start, $end);
$overspent = '0';
$array = [$budget->name, $left, $spent, $overspent, $amount, $spent];
$collection->push($array);
return $collection;
}
/**
* @param Carbon $start
* @param Carbon $end
*
* @return array
*/
private function spentInPeriodWithout(Carbon $start, Carbon $end):array
{
$list = $this->repository->journalsInPeriodWithoutBudget(new Collection, $start, $end);
$sum = '0';
/** @var TransactionJournal $entry */
foreach ($list as $entry) {
$sum = bcadd(TransactionJournal::amount($entry), $sum);
}
return [trans('firefly.no_budget'), '0', '0', $sum, '0', '0'];
}
}

View File

@@ -13,8 +13,10 @@ namespace FireflyIII\Http\Controllers\Chart;
use Carbon\Carbon;
use FireflyIII\Crud\Account\AccountCrudInterface;
use FireflyIII\Generator\Chart\Category\CategoryChartGeneratorInterface;
use FireflyIII\Http\Controllers\Controller;
use FireflyIII\Models\AccountType;
use FireflyIII\Models\Category;
use FireflyIII\Repositories\Category\CategoryRepositoryInterface as CRI;
use FireflyIII\Support\CacheProperties;
@@ -48,12 +50,13 @@ class CategoryController extends Controller
/**
* Show an overview for a category for all time, per month/week/year.
*
* @param CRI $repository
* @param Category $category
* @param CRI $repository
* @param AccountCrudInterface $crud
* @param Category $category
*
* @return \Symfony\Component\HttpFoundation\Response
*/
public function all(CRI $repository, Category $category)
public function all(CRI $repository, AccountCrudInterface $crud, Category $category)
{
$start = $repository->firstUseDate($category, new Collection);
$range = Preferences::get('viewRange', '1M')->data;
@@ -62,6 +65,7 @@ class CategoryController extends Controller
$end = new Carbon;
$entries = new Collection;
$cache = new CacheProperties;
$accounts = $crud->getAccountsByType([AccountType::DEFAULT, AccountType::ASSET]);
$cache->addProperty($start);
$cache->addProperty($end);
$cache->addProperty('all');
@@ -72,8 +76,8 @@ class CategoryController extends Controller
while ($start <= $end) {
$currentEnd = Navigation::endOfPeriod($start, $range);
$spent = $repository->spentInPeriod($categoryCollection, new Collection, $start, $currentEnd);
$earned = $repository->earnedInPeriod($categoryCollection, new Collection, $start, $currentEnd);
$spent = $repository->spentInPeriod($categoryCollection, $accounts, $start, $currentEnd);
$earned = $repository->earnedInPeriod($categoryCollection, $accounts, $start, $currentEnd);
$date = Navigation::periodShow($start, $range);
$entries->push([clone $start, $date, $spent, $earned]);
$start = Navigation::addPeriod($start, $range, 0);
@@ -250,18 +254,24 @@ class CategoryController extends Controller
{
$categoryCollection = new Collection([$category]);
$cache = new CacheProperties;
/** @var AccountCrudInterface $crud */
$crud = app(AccountCrudInterface::class);
$accounts = $crud->getAccountsByType([AccountType::DEFAULT, AccountType::ASSET]);
$cache->addProperty($start);
$cache->addProperty($end);
$cache->addProperty($accounts);
$cache->addProperty($category->id);
$cache->addProperty('specific-period');
if ($cache->has()) {
return $cache->get();
}
$entries = new Collection;
while ($start <= $end) {
$spent = $repository->spentInPeriod($categoryCollection, new Collection, $start, $start);
$earned = $repository->earnedInPeriod($categoryCollection, new Collection, $start, $start);
$spent = $repository->spentInPeriod($categoryCollection, $accounts, $start, $start);
$earned = $repository->earnedInPeriod($categoryCollection, $accounts, $start, $start);
$date = Navigation::periodShow($start, '1D');
$entries->push([clone $start, $date, $spent, $earned]);
$start->addDay();

View File

@@ -1,444 +0,0 @@
<?php
/**
* CsvController.php
* Copyright (C) 2016 thegrumpydictator@gmail.com
*
* This software may be modified and distributed under the terms
* of the MIT license. See the LICENSE file for details.
*/
declare(strict_types = 1);
namespace FireflyIII\Http\Controllers;
use ExpandedForm;
use FireflyIII\Crud\Account\AccountCrudInterface;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Helpers\Csv\Data;
use FireflyIII\Helpers\Csv\Importer;
use FireflyIII\Helpers\Csv\WizardInterface;
use FireflyIII\Models\AccountType;
use Illuminate\Http\Request;
use Input;
use Log;
use Preferences;
use Session;
use View;
/**
* Class CsvController
*
* @package FireflyIII\Http\Controllers
*/
class CsvController extends Controller
{
/** @var Data */
protected $data;
/** @var WizardInterface */
protected $wizard;
/**
*
*/
public function __construct()
{
parent::__construct();
View::share('title', trans('firefly.csv'));
View::share('mainTitleIcon', 'fa-file-text-o');
if (config('firefly.csv_import_enabled') === false) {
throw new FireflyException('CSV Import is not enabled.');
}
$this->wizard = app(WizardInterface::class);
$this->data = app(Data::class);
}
/**
* Define column roles and mapping.
*
* STEP THREE
*
* @return \Illuminate\Http\RedirectResponse|\Illuminate\View\View
*/
public function columnRoles()
{
$fields = ['csv-file', 'csv-date-format', 'csv-has-headers', 'csv-import-account', 'csv-specifix', 'csv-delimiter'];
if (!$this->wizard->sessionHasValues($fields)) {
Log::error('Could not recover upload.');
Session::flash('warning', strval(trans('firefly.could_not_recover')));
return redirect(route('csv.index'));
}
$subTitle = trans('firefly.csv_define_column_roles');
$firstRow = $this->data->getReader()->fetchOne();
$count = count($firstRow);
$headers = [];
$example = $this->data->getReader()->fetchOne(1);
$availableRoles = [];
$roles = $this->data->getRoles();
$map = $this->data->getMap();
for ($i = 1; $i <= $count; $i++) {
$headers[] = trans('firefly.csv_column') . ' #' . $i;
}
if ($this->data->hasHeaders()) {
$headers = $firstRow;
}
$keys = array_keys(config('csv.roles'));
foreach ($keys as $name) {
$availableRoles[$name] = trans('firefly.csv_column_' . $name);
}
asort($availableRoles);
return view('csv.column-roles', compact('availableRoles', 'map', 'roles', 'headers', 'example', 'subTitle'));
}
/**
* Optional download of mapping.
*
* STEP FOUR THREE-A
*
* @return \Illuminate\Http\RedirectResponse|string
*/
public function downloadConfig()
{
$fields = ['csv-date-format', 'csv-has-headers', 'csv-delimiter'];
if (!$this->wizard->sessionHasValues($fields)) {
Session::flash('warning', strval(trans('firefly.could_not_recover')));
return redirect(route('csv.index'));
}
$data = [
'date-format' => session('csv-date-format'),
'has-headers' => session('csv-has-headers'),
];
if (Session::has('csv-map')) {
$data['map'] = session('csv-map');
}
if (Session::has('csv-roles')) {
$data['roles'] = session('csv-roles');
}
if (Session::has('csv-mapped')) {
$data['mapped'] = session('csv-mapped');
}
if (Session::has('csv-specifix')) {
$data['specifix'] = session('csv-specifix');
}
$result = json_encode($data, JSON_PRETTY_PRINT);
$name = sprintf('"%s"', addcslashes('csv-configuration-' . date('Y-m-d') . '.json', '"\\'));
return response($result, 200)
->header('Content-disposition', 'attachment; filename=' . $name)
->header('Content-Type', 'application/json')
->header('Content-Description', 'File Transfer')
->header('Connection', 'Keep-Alive')
->header('Expires', '0')
->header('Cache-Control', 'must-revalidate, post-check=0, pre-check=0')
->header('Pragma', 'public')
->header('Content-Length', strlen($result));
}
/**
* @return \Illuminate\View\View
*/
public function downloadConfigPage()
{
$fields = ['csv-date-format', 'csv-has-headers', 'csv-delimiter'];
if (!$this->wizard->sessionHasValues($fields)) {
Session::flash('warning', strval(trans('firefly.could_not_recover')));
return redirect(route('csv.index'));
}
$subTitle = trans('firefly.csv_download_config_title');
return view('csv.download-config', compact('subTitle'));
}
/**
* This method shows the initial upload form.
*
* STEP ONE
*
* @param AccountCrudInterface $crud
*
* @return \Illuminate\View\View
*/
public function index(AccountCrudInterface $crud)
{
$subTitle = trans('firefly.csv_import');
Session::forget('csv-date-format');
Session::forget('csv-has-headers');
Session::forget('csv-file');
Session::forget('csv-import-account');
Session::forget('csv-map');
Session::forget('csv-roles');
Session::forget('csv-mapped');
Session::forget('csv-specifix');
Session::forget('csv-delimiter');
// get list of supported specifix
$specifix = [];
foreach (config('csv.specifix') as $entry) {
$specifix[$entry] = trans('firefly.csv_specifix_' . $entry);
}
// get a list of delimiters:
$delimiters = [
',' => trans('form.csv_comma'),
';' => trans('form.csv_semicolon'),
'tab' => trans('form.csv_tab'),
];
// get a list of asset accounts:
$accounts = ExpandedForm::makeSelectList($crud->getAccountsByType([AccountType::ASSET, AccountType::DEFAULT]));
// can actually upload?
$uploadPossible = is_writable(storage_path('upload'));
$path = storage_path('upload');
return view('csv.index', compact('subTitle', 'uploadPossible', 'path', 'specifix', 'accounts', 'delimiters'));
}
/**
* Parse the file.
*
* STEP FOUR
*
* @return \Illuminate\Http\RedirectResponse
*/
public function initialParse()
{
$fields = ['csv-file', 'csv-date-format', 'csv-has-headers', 'csv-delimiter'];
if (!$this->wizard->sessionHasValues($fields)) {
Session::flash('warning', strval(trans('firefly.could_not_recover')));
return redirect(route('csv.index'));
}
// process given roles and mapping:
$inputMap = Input::get('map') ?? [];
$inputRoles = Input::get('role') ?? [];
$roles = $this->wizard->processSelectedRoles($inputRoles);
$maps = $this->wizard->processSelectedMapping($roles, $inputMap);
Session::put('csv-map', $maps);
Session::put('csv-roles', $roles);
// Go back when no roles defined:
if (count($roles) === 0) {
Session::flash('warning', strval(trans('firefly.must_select_roles')));
return redirect(route('csv.column-roles'));
}
/*
* Continue with map specification when necessary.
*/
if (count($maps) > 0) {
return redirect(route('csv.map'));
}
/*
* Or simply start processing.
*/
// proceed to download config
return redirect(route('csv.download-config-page'));
}
/**
*
* Map first if necessary,
*
* STEP FIVE.
*
* @return \Illuminate\Http\RedirectResponse|\Illuminate\View\View
* @throws FireflyException
*/
public function map()
{
// Make sure all fields we need are accounted for.
$fields = ['csv-file', 'csv-date-format', 'csv-has-headers', 'csv-map', 'csv-roles', 'csv-delimiter'];
if (!$this->wizard->sessionHasValues($fields)) {
Session::flash('warning', strval(trans('firefly.could_not_recover')));
return redirect(route('csv.index'));
}
/*
* The "options" array contains all options the user has
* per column, where the key represents the column.
*
* For each key there is an array which in turn represents
* all the options available: grouped by ID.
*
* options[column index] = [
* field id => field identifier.
* ]
*/
$options = $this->wizard->showOptions($this->data->getMap());
// After these values are prepped, read the actual CSV file
$reader = $this->data->getReader();
$map = $this->data->getMap();
$hasHeaders = $this->data->hasHeaders();
$values = $this->wizard->getMappableValues($reader, $map, $hasHeaders);
$map = $this->data->getMap();
$mapped = $this->data->getMapped();
$subTitle = trans('firefly.csv_map_values');
return view('csv.map', compact('map', 'options', 'values', 'mapped', 'subTitle'));
}
/**
*
* Finally actually process the CSV file.
*
* STEP SEVEN
*
* @return \Illuminate\Http\RedirectResponse|\Illuminate\View\View
*/
public function process()
{
/*
* Make sure all fields we need are accounted for.
*/
$fields = ['csv-file', 'csv-date-format', 'csv-has-headers', 'csv-map', 'csv-roles', 'csv-mapped', 'csv-delimiter'];
if (!$this->wizard->sessionHasValues($fields)) {
Session::flash('warning', strval(trans('firefly.could_not_recover')));
return redirect(route('csv.index'));
}
/** @var Importer $importer */
$importer = app(Importer::class);
$importer->setData($this->data);
$importer->run();
$rows = $importer->getRows();
$errors = $importer->getErrors();
$imported = $importer->getImported();
$journals = $importer->getJournals();
Preferences::mark();
$subTitle = trans('firefly.csv_process_title');
return view('csv.process', compact('rows', 'errors', 'imported', 'subTitle', 'journals'));
}
/**
* Store the mapping the user has made. This is
*
* STEP SIX
*
*
* @return \Illuminate\Http\RedirectResponse
*/
public function saveMapping()
{
/*
* Make sure all fields we need are accounted for.
*/
$fields = ['csv-file', 'csv-date-format', 'csv-has-headers', 'csv-map', 'csv-roles', 'csv-delimiter'];
if (!$this->wizard->sessionHasValues($fields)) {
Session::flash('warning', strval(trans('firefly.could_not_recover')));
return redirect(route('csv.index'));
}
// save mapping to session.
$mapped = [];
if (!is_array(Input::get('mapping'))) {
Session::flash('warning', strval(trans('firefly.invalid_mapping')));
return redirect(route('csv.map'));
}
foreach (Input::get('mapping') as $index => $data) {
$mapped[$index] = [];
foreach ($data as $value => $mapping) {
if (intval($mapping) !== 0) {
$mapped[$index][$value] = $mapping;
}
}
}
Session::put('csv-mapped', $mapped);
// proceed to process.
return redirect(route('csv.download-config-page'));
}
/**
*
* This method processes the file, puts it away somewhere safe
* and sends you onwards.
*
* STEP TWO
*
* @param Request $request
*
* @return \Illuminate\Http\RedirectResponse
*/
public function upload(Request $request)
{
if (!$request->hasFile('csv')) {
Session::flash('warning', strval(trans('firefly.no_file_uploaded')));
return redirect(route('csv.index'));
}
$path = $this->wizard->storeCsvFile($request->file('csv')->getRealPath());
$settings = [];
$settings['date-format'] = Input::get('date_format');
$settings['has-headers'] = intval(Input::get('has_headers')) === 1;
$settings['specifix'] = is_array(Input::get('specifix')) ? Input::get('specifix') : [];
$settings['import-account'] = intval(Input::get('csv_import_account'));
$settings['delimiter'] = Input::get('csv_delimiter', ',');
// A tab character cannot be used itself as option value in HTML
// See http://stackoverflow.com/questions/6064135/valid-characters-in-option-value
if ($settings['delimiter'] == 'tab') {
$settings['delimiter'] = "\t";
}
$settings['map'] = [];
$settings['mapped'] = [];
$settings['roles'] = [];
if ($request->hasFile('csv_config')) { // Process config file if present.
$size = $request->file('csv_config')->getSize();
$data = $request->file('csv_config')->openFile()->fread($size);
$json = json_decode($data, true);
if (is_array($json)) {
$settings = array_merge($settings, $json);
}
}
$this->data->setCsvFileLocation($path);
$this->data->setDateFormat($settings['date-format']);
$this->data->setHasHeaders($settings['has-headers']);
$this->data->setMap($settings['map']);
$this->data->setMapped($settings['mapped']);
$this->data->setRoles($settings['roles']);
$this->data->setSpecifix($settings['specifix']);
$this->data->setImportAccount($settings['import-account']);
$this->data->setDelimiter($settings['delimiter']);
return redirect(route('csv.column-roles'));
}
}

View File

@@ -18,8 +18,9 @@ use FireflyIII\Models\AccountType;
use FireflyIII\Models\Tag;
use FireflyIII\Repositories\Account\AccountRepositoryInterface as ARI;
use FireflyIII\Repositories\Tag\TagRepositoryInterface;
use Illuminate\Http\Request;
use Illuminate\Support\Collection;
use Input;
use Log;
use Preferences;
use Route;
use Session;
@@ -41,18 +42,24 @@ class HomeController extends Controller
parent::__construct();
}
public function dateRange()
/**
* @param Request $request
*/
public function dateRange(Request $request)
{
$start = new Carbon(Input::get('start'));
$end = new Carbon(Input::get('end'));
$label = Input::get('label');
$start = new Carbon($request->get('start'));
$end = new Carbon($request->get('end'));
$label = $request->get('label');
$isCustomRange = false;
Log::debug('Received dateRange', ['start' => $request->get('start'), 'end' => $request->get('end'), 'label' => $request->get('label')]);
// check if the label is "everything" or "Custom range" which will betray
// a possible problem with the budgets.
if ($label === strval(trans('firefly.everything')) || $label === strval(trans('firefly.customRange'))) {
$isCustomRange = true;
Log::debug('Range is now marked as "custom".');
}
$diff = $start->diffInDays($end);
@@ -112,6 +119,7 @@ class HomeController extends Controller
*/
public function index(ARI $repository, AccountCrudInterface $crud)
{
$types = config('firefly.accountTypesByIdentifier.asset');
$count = $repository->countAccounts($types);
@@ -173,11 +181,11 @@ class HomeController extends Controller
$search = [
'{account}', '{what}', '{rule}', '{tj}', '{category}', '{budget}', '{code}', '{date}', '{attachment}', '{bill}', '{limitrepetition}',
'{currency}', '{jobKey}', '{piggyBank}', '{ruleGroup}', '{rule}', '{route}', '{unfinishedJournal}',
'{reportType}', '{start_date}', '{end_date}', '{accountList}','{tag}','{journalList}'
'{reportType}', '{start_date}', '{end_date}', '{accountList}', '{tag}', '{journalList}',
];
$replace = [1, 'asset', 1, 1, 1, 1, 'abc', '2016-01-01', 1, 1, 1, 1, 1, 1, 1, 1, 'index', 1,
'default', '20160101', '20160131', '1,2',1,'1,2'
'default', '20160101', '20160131', '1,2', 1, '1,2',
];
if (count($search) != count($replace)) {
echo 'count';

View File

@@ -0,0 +1,361 @@
<?php
/**
* ImportController.php
* Copyright (C) 2016 thegrumpydictator@gmail.com
*
* This software may be modified and distributed under the terms
* of the MIT license. See the LICENSE file for details.
*/
namespace FireflyIII\Http\Controllers;
use Crypt;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Http\Requests;
use FireflyIII\Http\Requests\ImportUploadRequest;
use FireflyIII\Import\Setup\SetupInterface;
use FireflyIII\Models\ImportJob;
use FireflyIII\Repositories\ImportJob\ImportJobRepositoryInterface;
use Illuminate\Http\Request;
use Log;
use SplFileObject;
use Storage;
use Symfony\Component\HttpFoundation\File\UploadedFile;
use View;
/**
* Class ImportController
*
* @package FireflyIII\Http\Controllers
*/
class ImportController extends Controller
{
/**
*
*/
public function __construct()
{
parent::__construct();
View::share('mainTitleIcon', 'fa-archive');
View::share('title', trans('firefly.import_data_full'));
}
/**
* This is the last step before the import starts.
*
* @param ImportJob $job
*
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector|View
*/
public function complete(ImportJob $job)
{
Log::debug('Now in complete()', ['job' => $job->key]);
if (!$this->jobInCorrectStep($job, 'complete')) {
return $this->redirectToCorrectStep($job);
}
$subTitle = trans('firefy.import_complete');
$subTitleIcon = 'fa-star';
return view('import.complete', compact('job', 'subTitle', 'subTitleIcon'));
}
/**
* This is step 3.
* This is the first step in configuring the job. It can only be executed
* when the job is set to "import_status_never_started".
*
* @param ImportJob $job
*
* @return View
* @throws FireflyException
*/
public function configure(ImportJob $job)
{
Log::debug('Now at start of configure()');
if (!$this->jobInCorrectStep($job, 'configure')) {
Log::debug('Job is not in correct state for configure()', ['status' => $job->status]);
return $this->redirectToCorrectStep($job);
}
// actual code
$importer = $this->makeImporter($job);
$importer->configure();
$data = $importer->getConfigurationData();
$subTitle = trans('firefly.configure_import');
$subTitleIcon = 'fa-wrench';
return view('import.' . $job->file_type . '.configure', compact('data', 'job', 'subTitle', 'subTitleIcon'));
}
/**
* Generate a JSON file of the job's config and send it to the user.
*
* @param ImportJob $job
*
* @return mixed
*/
public function download(ImportJob $job)
{
Log::debug('Now in download()', ['job' => $job->key]);
$config = $job->configuration;
$config['column-roles-complete'] = false;
$config['column-mapping-complete'] = false;
$result = json_encode($config, JSON_PRETTY_PRINT);
$name = sprintf('"%s"', addcslashes('import-configuration-' . date('Y-m-d') . '.json', '"\\'));
return response($result, 200)
->header('Content-disposition', 'attachment; filename=' . $name)
->header('Content-Type', 'application/json')
->header('Content-Description', 'File Transfer')
->header('Connection', 'Keep-Alive')
->header('Expires', '0')
->header('Cache-Control', 'must-revalidate, post-check=0, pre-check=0')
->header('Pragma', 'public')
->header('Content-Length', strlen($result));
}
/**
* This is step 1. Upload a file.
*
* @return View
*/
public function index()
{
Log::debug('Now at index');
$subTitle = trans('firefly.import_data_index');
$subTitleIcon = 'fa-home';
$importFileTypes = [];
$defaultImportType = config('firefly.default_import_format');
foreach (array_keys(config('firefly.import_formats')) as $type) {
$importFileTypes[$type] = trans('firefly.import_file_type_' . $type);
}
return view('import.index', compact('subTitle', 'subTitleIcon', 'importFileTypes', 'defaultImportType'));
}
/**
* Step 4. Save the configuration.
*
* @param Request $request
* @param ImportJob $job
*
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
* @throws FireflyException
*/
public function postConfigure(Request $request, ImportJob $job)
{
Log::debug('Now in postConfigure()', ['job' => $job->key]);
if (!$this->jobInCorrectStep($job, 'process')) {
return $this->redirectToCorrectStep($job);
}
Log::debug('Continue postConfigure()', ['job' => $job->key]);
// actual code
$importer = $this->makeImporter($job);
$data = $request->all();
$files = $request->files;
$importer->saveImportConfiguration($data, $files);
// update job:
$job->status = 'import_configuration_saved';
$job->save();
// return redirect to settings.
// this could loop until the user is done.
return redirect(route('import.settings', [$job->key]));
}
/**
* This step 6. Depending on the importer, this will process the
* settings given and store them.
*
* @param Request $request
* @param ImportJob $job
*
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
* @throws FireflyException
*/
public function postSettings(Request $request, ImportJob $job)
{
Log::debug('Now in postSettings()', ['job' => $job->key]);
if (!$this->jobInCorrectStep($job, 'store-settings')) {
return $this->redirectToCorrectStep($job);
}
$importer = $this->makeImporter($job);
$importer->storeSettings($request);
// return redirect to settings (for more settings perhaps)
return redirect(route('import.settings', [$job->key]));
}
/**
* Step 5. Depending on the importer, this will show the user settings to
* fill in.
*
* @param ImportJob $job
*
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
* @throws FireflyException
*/
public function settings(ImportJob $job)
{
Log::debug('Now in settings()', ['job' => $job->key]);
if (!$this->jobInCorrectStep($job, 'settings')) {
Log::debug('Job should not be in settings()');
return $this->redirectToCorrectStep($job);
}
Log::debug('Continue in settings()');
$importer = $this->makeImporter($job);
$subTitle = trans('firefly.settings_for_import');
$subTitleIcon = 'fa-wrench';
// now show settings screen to user.
if ($importer->requireUserSettings()) {
Log::debug('Job requires user config.');
$data = $importer->getDataForSettings();
$view = $importer->getViewForSettings();
return view($view, compact('data', 'job', 'subTitle', 'subTitleIcon'));
}
Log::debug('Job does NOT require user config.');
$job->status = 'settings_complete';
$job->save();
// if no more settings, save job and continue to process thing.
return redirect(route('import.complete', [$job->key]));
// ask the importer for the requested action.
// for example pick columns or map data.
// depends of course on the data in the job.
}
/**
* This is step 2. It creates an Import Job. Stores the import.
*
* @param ImportUploadRequest $request
* @param ImportJobRepositoryInterface $repository
*
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
*/
public function upload(ImportUploadRequest $request, ImportJobRepositoryInterface $repository)
{
Log::debug('Now in upload()');
// create import job:
$type = $request->get('import_file_type');
$job = $repository->create($type);
Log::debug('Created new job', ['key' => $job->key, 'id' => $job->id]);
/** @var UploadedFile $upload */
$upload = $request->files->get('import_file');
$newName = $job->key . '.upload';
$uploaded = new SplFileObject($upload->getRealPath());
$content = $uploaded->fread($uploaded->getSize());
$contentEncrypted = Crypt::encrypt($content);
$disk = Storage::disk('upload');
$disk->put($newName, $contentEncrypted);
Log::debug('Uploaded file', ['name' => $upload->getClientOriginalName(), 'size' => $upload->getSize(), 'mime' => $upload->getClientMimeType()]);
// store configuration file's content into the job's configuration
// thing.
// otherwise, leave it empty.
if ($request->files->has('configuration_file')) {
/** @var UploadedFile $configFile */
$configFile = $request->files->get('configuration_file');
Log::debug(
'Uploaded configuration file',
['name' => $configFile->getClientOriginalName(), 'size' => $configFile->getSize(), 'mime' => $configFile->getClientMimeType()]
);
$configFileObject = new SplFileObject($configFile->getRealPath());
$configRaw = $configFileObject->fread($configFileObject->getSize());
$configuration = json_decode($configRaw, true);
if (!is_null($configuration) && is_array($configuration)) {
Log::debug('Found configuration', $configuration);
$job->configuration = $configuration;
$job->save();
}
}
return redirect(route('import.configure', [$job->key]));
}
/**
* @param ImportJob $job
* @param string $method
*
* @return bool
*/
private function jobInCorrectStep(ImportJob $job, string $method): bool
{
Log::debug('Now in jobInCorrectStep()', ['job' => $job->key, 'method' => $method]);
switch ($method) {
case 'configure':
case 'process':
return $job->status === 'import_status_never_started';
case 'settings':
case 'store-settings':
return $job->status === 'import_configuration_saved';
case 'complete':
return $job->status === 'settings_complete';
}
return false;
}
/**
* @param ImportJob $job
*
* @return SetupInterface
*/
private function makeImporter(ImportJob $job): SetupInterface
{
// create proper importer (depends on job)
$type = $job->file_type;
/** @var SetupInterface $importer */
$importer = app('FireflyIII\Import\Setup\\' . ucfirst($type) . 'Setup');
$importer->setJob($job);
return $importer;
}
/**
* @param ImportJob $job
*
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
* @throws FireflyException
*/
private function redirectToCorrectStep(ImportJob $job)
{
Log::debug('Now in redirectToCorrectStep()', ['job' => $job->key]);
switch ($job->status) {
case 'import_status_never_started':
Log::debug('Will redirect to configure()');
return redirect(route('import.configure', [$job->key]));
case 'import_configuration_saved':
Log::debug('Will redirect to settings()');
return redirect(route('import.settings', [$job->key]));
case 'settings_complete':
Log::debug('Will redirect to complete()');
return redirect(route('import.complete', [$job->key]));
}
throw new FireflyException('Cannot redirect for job state ' . $job->status);
}
}

View File

@@ -42,6 +42,7 @@ class NewUserController extends Controller
*/
public function index(ARI $repository)
{
View::share('title', 'Welcome to Firefly!');
View::share('mainTitleIcon', 'fa-fire');

View File

@@ -48,6 +48,26 @@ class PiggyBankController extends Controller
View::share('mainTitleIcon', 'fa-sort-amount-asc');
}
/**
* Add money to piggy bank (for mobile devices)
*
* @param ARI $repository
* @param PiggyBank $piggyBank
*
* @return $this
*/
public function addMobile(ARI $repository, PiggyBank $piggyBank)
{
/** @var Carbon $date */
$date = session('end', Carbon::now()->endOfMonth());
$leftOnAccount = $repository->leftOnAccount($piggyBank->account, $date);
$savedSoFar = $piggyBank->currentRelevantRep()->currentamount;
$leftToSave = bcsub($piggyBank->targetamount, $savedSoFar);
$maxAmount = min($leftOnAccount, $leftToSave);
return view('piggy-banks.add-mobile', compact('piggyBank', 'maxAmount'));
}
/**
* Add money to piggy bank
*
@@ -270,7 +290,7 @@ class PiggyBankController extends Controller
*/
public function postRemove(PiggyBankRepositoryInterface $repository, PiggyBank $piggyBank)
{
$amount = round(Input::get('amount'), 2);
$amount = strval(round(Input::get('amount'), 2));
$savedSoFar = $piggyBank->currentRelevantRep()->currentamount;
@@ -335,8 +355,6 @@ class PiggyBankController extends Controller
'startdate' => new Carbon,
'account_id' => intval($request->get('account_id')),
'targetamount' => round($request->get('targetamount'), 2),
'remind_me' => false,
'reminder_skip' => 0,
'order' => $repository->getMaxOrder() + 1,
'targetdate' => strlen($request->get('targetdate')) > 0 ? new Carbon($request->get('targetdate')) : null,
];
@@ -371,8 +389,6 @@ class PiggyBankController extends Controller
'startdate' => is_null($piggyBank->startdate) ? $piggyBank->created_at : $piggyBank->startdate,
'account_id' => intval($request->get('account_id')),
'targetamount' => round($request->get('targetamount'), 2),
'remind_me' => false,
'reminder_skip' => 0,
'targetdate' => strlen($request->get('targetdate')) > 0 ? new Carbon($request->get('targetdate')) : null,
];

View File

@@ -12,10 +12,12 @@ declare(strict_types = 1);
namespace FireflyIII\Http\Controllers;
use Auth;
use FireflyIII\Events\UserIsDeleted;
use FireflyIII\Http\Requests\DeleteAccountFormRequest;
use FireflyIII\Http\Requests\ProfileFormRequest;
use FireflyIII\User;
use Hash;
use Preferences;
use Session;
/**
@@ -106,6 +108,13 @@ class ProfileController extends Controller
return redirect(route('profile.delete-account'));
}
// respond to deletion:
event(new UserIsDeleted(Auth::user(), $request->ip()));
// store some stuff for the future:
$registration = Preferences::get('registration_ip_address')->data;
$confirmation = Preferences::get('confirmation_ip_address')->data;
// DELETE!
$email = Auth::user()->email;
Auth::user()->delete();
@@ -114,7 +123,7 @@ class ProfileController extends Controller
Session::flash('gaEventAction', 'delete-account');
// create a new user with the same email address so re-registration is blocked.
User::create(
$newUser = User::create(
[
'email' => $email,
'password' => 'deleted',
@@ -122,6 +131,13 @@ class ProfileController extends Controller
'blocked_code' => 'deleted',
]
);
if (strlen($registration) > 0) {
Preferences::setForUser($newUser, 'registration_ip_address', $registration);
}
if (strlen($confirmation) > 0) {
Preferences::setForUser($newUser, 'confirmation_ip_address', $confirmation);
}
return redirect(route('index'));
}

View File

@@ -320,9 +320,7 @@ class ReportController extends Controller
$incomes = $this->helper->getIncomeReport($start, $end, $accounts);
$expenses = $this->helper->getExpenseReport($start, $end, $accounts);
$tags = $this->helper->tagReport($start, $end, $accounts);
// find the budgets we've spent money on this period with these accounts:
$budgets = $this->budgetHelper->getBudgetsWithExpenses($start, $end, $accounts);
$budgets = $this->budgetHelper->budgetYearOverview($start, $end, $accounts);
Session::flash('gaEventCategory', 'report');
Session::flash('gaEventAction', 'year');

View File

@@ -110,13 +110,40 @@ class MassController extends Controller
$crud = app('FireflyIII\Crud\Account\AccountCrudInterface');
$accountList = ExpandedForm::makeSelectList($crud->getAccountsByType([AccountType::DEFAULT, AccountType::ASSET]));
// skip transactions that have multiple destinations
// or multiple sources:
$filtered = new Collection;
$messages = [];
/**
* @var int $index
* @var TransactionJournal $journal
*/
foreach ($journals as $index => $journal) {
$sources = TransactionJournal::sourceAccountList($journal);
$destinations = TransactionJournal::destinationAccountList($journal);
if ($sources->count() > 1) {
$messages[] = trans('firefly.cannot_edit_multiple_source', ['description' => $journal->description, 'id' => $journal->id]);
continue;
}
if ($destinations->count() > 1) {
$messages[] = trans('firefly.cannot_edit_multiple_dest', ['description' => $journal->description, 'id' => $journal->id]);
continue;
}
$filtered->push($journal);
}
if (count($messages)) {
Session::flash('info', $messages);
}
// put previous url in session
Session::put('transactions.mass-edit.url', URL::previous());
Session::flash('gaEventCategory', 'transactions');
Session::flash('gaEventAction', 'mass-edit');
// set some values to be used in the edit routine:
$journals->each(
$filtered->each(
function (TransactionJournal $journal) {
$journal->amount = TransactionJournal::amountPositive($journal);
$sources = TransactionJournal::sourceAccountList($journal);
@@ -133,6 +160,12 @@ class MassController extends Controller
}
);
if ($filtered->count() === 0) {
Session::flash('error', trans('firefly.no_edit_multiple_left'));
}
$journals = $filtered;
return view('transactions.mass-edit', compact('journals', 'subTitle', 'accountList'));
}
@@ -151,33 +184,26 @@ class MassController extends Controller
$journal = $repository->find(intval($journalId));
if ($journal) {
// get optional fields:
$what = strtolower(TransactionJournal::transactionTypeStr($journal));
$sourceAccountId = $request->get('source_account_id')[$journal->id] ?? 0;
$destAccountId = $request->get('destination_account_id')[$journal->id] ?? 0;
$expenseAccount = $request->get('expense_account')[$journal->id] ?? '';
$revenueAccount = $request->get('revenue_account')[$journal->id] ?? '';
$budgetId = $journal->budgets->first() ? $journal->budgets->first()->id : 0;
$category = $journal->categories->first() ? $journal->categories->first()->name : '';
$tags = $journal->tags->pluck('tag')->toArray();
$what = strtolower(TransactionJournal::transactionTypeStr($journal));
// for a deposit, the 'account_id' is the account the money is deposited on.
// needs a better way of handling.
// more uniform source/destination field names
$accountId = $sourceAccountId;
if ($what == 'deposit') {
$accountId = $destAccountId;
}
$sourceAccountId = $request->get('source_account_id')[$journal->id] ?? 0;
$sourceAccountName = $request->get('source_account_name')[$journal->id] ?? '';
$destAccountId = $request->get('destination_account_id')[$journal->id] ?? 0;
$destAccountName = $request->get('destination_account_name')[$journal->id] ?? '';
$budgetId = $journal->budgets->first() ? $journal->budgets->first()->id : 0;
$category = $journal->categories->first() ? $journal->categories->first()->name : '';
$tags = $journal->tags->pluck('tag')->toArray();
// build data array
$data = [
'id' => $journal->id,
'what' => $what,
'description' => $request->get('description')[$journal->id],
'account_id' => intval($accountId),
'account_from_id' => intval($sourceAccountId),
'account_to_id' => intval($destAccountId),
'expense_account' => $expenseAccount,
'revenue_account' => $revenueAccount,
'source_account_id' => intval($sourceAccountId),
'source_account_name' => intval($destAccountId),
'destination_account_id' => $sourceAccountName,
'destination_account_name' => $destAccountName,
'amount' => round($request->get('amount')[$journal->id], 4),
'user' => Auth::user()->id,
'amount_currency_id_amount' => intval($request->get('amount_currency_id_amount_' . $journal->id)),
@@ -204,4 +230,4 @@ class MassController extends Controller
return redirect(session('transactions.mass-edit.url'));
}
}
}

View File

@@ -358,4 +358,4 @@ class SplitController extends Controller
return $return;
}
}
}

View File

@@ -197,7 +197,7 @@ class TransactionController extends Controller
*/
public function index(Request $request, JournalRepositoryInterface $repository, string $what)
{
$pageSize = Preferences::get('transactionPageSize', 50)->data;
$pageSize = intval(Preferences::get('transactionPageSize', 50)->data);
$subTitleIcon = config('firefly.transactionIconsByWhat.' . $what);
$types = config('firefly.transactionTypesByWhat.' . $what);
$subTitle = trans('firefly.title_' . $what);
@@ -223,7 +223,7 @@ class TransactionController extends Controller
if (count($ids) > 0) {
$order = 0;
foreach ($ids as $id) {
$journal = $repository->find($id);
$journal = $repository->find(intval($id));
if ($journal && $journal->date->format('Y-m-d') == $date->format('Y-m-d')) {
$journal->order = $order;
$order++;
@@ -274,6 +274,8 @@ class TransactionController extends Controller
// store the journal only, flash the rest.
if ($doSplit) {
$journal = $repository->storeJournal($journalData);
$journal->completed = false;
$journal->save();
// store attachments:
$att->saveAttachmentsForModel($journal);

View File

@@ -13,6 +13,7 @@ namespace FireflyIII\Http\Middleware;
use Carbon\Carbon;
use Closure;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Repositories\Journal\JournalRepositoryInterface;
use Illuminate\Contracts\Auth\Guard;
use Illuminate\Http\Request;
@@ -64,7 +65,6 @@ class Range
// ignore preference. set the range to be the current month:
if (!Session::has('start') && !Session::has('end')) {
/** @var \FireflyIII\Models\Preference $viewRange */
$viewRange = Preferences::get('viewRange', '1M')->data;
$start = new Carbon;
$start = Navigation::updateStartDate($viewRange, $start);
@@ -84,16 +84,61 @@ class Range
}
Session::put('first', $first);
}
$current = Carbon::now()->formatLocalized('%B %Y');
$next = Carbon::now()->endOfMonth()->addDay()->formatLocalized('%B %Y');
$prev = Carbon::now()->startOfMonth()->subDay()->formatLocalized('%B %Y');
View::share('currentMonthName', $current);
View::share('previousMonthName', $prev);
View::share('nextMonthName', $next);
}
$this->datePicker();
return $theNext($request);
}
private function datePicker()
{
$viewRange = Preferences::get('viewRange', '1M')->data;
$start = Session::get('start');
$end = Session::get('end');
$prevStart = Navigation::subtractPeriod($start, $viewRange);// subtract for previous period
$prevEnd = Navigation::endOfPeriod($prevStart, $viewRange);
$nextStart = Navigation::addPeriod($start, $viewRange, 0); // add for previous period
$nextEnd = Navigation::endOfPeriod($nextStart, $viewRange);
$ranges = [];
$ranges['current'] = [$start->format('Y-m-d'), $end->format('Y-m-d')];
$ranges['previous'] = [$prevStart->format('Y-m-d'), $prevEnd->format('Y-m-d')];
$ranges['next'] = [$nextStart->format('Y-m-d'), $nextEnd->format('Y-m-d')];
switch ($viewRange) {
default:
throw new FireflyException('The date picker does not yet support "' . $viewRange . '".');
case '1D':
$format = (string)trans('config.month_and_day');
break;
case '3M':
$format = (string)trans('config.quarter_in_year');
break;
case '6M':
$format = (string)trans('config.half_year');
break;
case '1Y':
$format = (string)trans('config.year');
break;
case '1M':
$format = (string)trans('config.month');
break;
case '1W':
$format = (string)trans('config.week_in_year');
break;
}
$current = $start->formatLocalized($format);
$next = $nextStart->formatLocalized($format);
$prev = $prevStart->formatLocalized($format);
View::share('dpStart', $start->format('Y-m-d'));
View::share('dpEnd', $end->format('Y-m-d'));
View::share('dpCurrent', $current);
View::share('dpPrevious', $prev);
View::share('dpNext', $next);
View::share('dpRanges', $ranges);
}
}

View File

@@ -0,0 +1,46 @@
<?php
/**
* ImportUploadRequest.php
* Copyright (C) 2016 thegrumpydictator@gmail.com
*
* This software may be modified and distributed under the terms
* of the MIT license. See the LICENSE file for details.
*/
declare(strict_types = 1);
namespace FireflyIII\Http\Requests;
use Auth;
/**
* Class ImportUploadRequest
*
*
* @package FireflyIII\Http\Requests
*/
class ImportUploadRequest extends Request
{
/**
* @return bool
*/
public function authorize()
{
// Only allow logged in users
return Auth::check();
}
/**
* @return array
*/
public function rules()
{
$types = array_keys(config('firefly.import_formats'));
return [
'import_file' => 'required|file',
'import_file_type' => 'required|in:' . join(',', $types),
];
}
}

View File

@@ -49,29 +49,9 @@ class SplitJournalFormRequest extends Request
'interest_date' => $this->get('interest_date') ? new Carbon($this->get('interest_date')) : null,
'book_date' => $this->get('book_date') ? new Carbon($this->get('book_date')) : null,
'process_date' => $this->get('process_date') ? new Carbon($this->get('process_date')) : null,
'transactions' => [],
'transactions' => $this->getTransactionData(),
];
// description is leading because it is one of the mandatory fields.
foreach ($this->get('description') as $index => $description) {
$transaction = [
'description' => $description,
'amount' => round($this->get('amount')[$index], 2),
'budget_id' => $this->get('budget_id')[$index] ? intval($this->get('budget_id')[$index]) : 0,
'category' => $this->get('category')[$index] ?? '',
'source_account_id' => intval($this->get('journal_source_account_id')),
'source_account_name' => $this->get('journal_source_account_name'),
'piggy_bank_id' => isset($this->get('piggy_bank_id')[$index])
? intval($this->get('piggy_bank_id')[$index])
: 0,
'destination_account_id' => isset($this->get('destination_account_id')[$index])
? intval($this->get('destination_account_id')[$index])
: intval($this->get('journal_destination_account_id')),
'destination_account_name' => $this->get('destination_account_name')[$index] ?? '',
];
$data['transactions'][] = $transaction;
}
return $data;
}
@@ -91,14 +71,46 @@ class SplitJournalFormRequest extends Request
'interest_date' => 'date',
'book_date' => 'date',
'process_date' => 'date',
'description.*' => 'required|between:1,255',
'destination_account_id.*' => 'numeric|belongsToUser:accounts,id',
'destination_account_name.*' => 'between:1,255',
'amount.*' => 'required|numeric',
'budget_id.*' => 'belongsToUser:budgets,id',
'category.*' => 'between:1,255',
'piggy_bank_id.*' => 'between:1,255',
'description.*' => 'required|between:1,255',
'destination_account_id.*' => 'numeric|belongsToUser:accounts,id',
'destination_account_name.*' => 'between:1,255',
'amount.*' => 'required|numeric',
'budget_id.*' => 'belongsToUser:budgets,id',
'category.*' => 'between:1,255',
'piggy_bank_id.*' => 'between:1,255',
];
}
}
/**
* @return array
*/
private function getTransactionData(): array
{
$return = [];
// description is leading because it is one of the mandatory fields.
foreach ($this->get('description') as $index => $description) {
$transaction = [
'description' => $description,
'amount' => round($this->get('amount')[$index], 2),
'budget_id' => $this->get('budget_id')[$index] ? intval($this->get('budget_id')[$index]) : 0,
'category' => $this->get('category')[$index] ?? '',
'source_account_id' => isset($this->get('source_account_id')[$index])
? intval($this->get('source_account_id')[$index])
: intval(
$this->get('journal_source_account_id')
),
'source_account_name' => $this->get('source_account_name')[$index] ?? '',
'piggy_bank_id' => isset($this->get('piggy_bank_id')[$index]) ? intval($this->get('piggy_bank_id')[$index]) : 0,
'destination_account_id' => isset($this->get('destination_account_id')[$index])
? intval($this->get('destination_account_id')[$index])
: intval(
$this->get('journal_destination_account_id')
),
'destination_account_name' => $this->get('destination_account_name')[$index] ?? '',
];
$return[] = $transaction;
}
return $return;
}
}

View File

@@ -96,6 +96,30 @@ Breadcrumbs::register(
}
);
/**
* ADMIN
*/
Breadcrumbs::register(
'admin.index', function (BreadCrumbGenerator $breadcrumbs) {
$breadcrumbs->parent('home');
$breadcrumbs->push(trans('firefly.administration'), route('admin.index'));
}
);
Breadcrumbs::register(
'admin.users', function (BreadCrumbGenerator $breadcrumbs) {
$breadcrumbs->parent('admin.index');
$breadcrumbs->push(trans('firefly.list_all_users'), route('admin.users'));
}
);
Breadcrumbs::register(
'admin.users.domains', function (BreadCrumbGenerator $breadcrumbs) {
$breadcrumbs->parent('admin.index');
$breadcrumbs->push(trans('firefly.blocked_domains'), route('admin.users.domains'));
}
);
/**
* ATTACHMENTS
*/
@@ -269,44 +293,6 @@ Breadcrumbs::register(
}
);
/**
* CSV CONTROLLER
*/
Breadcrumbs::register(
'csv.index', function (BreadCrumbGenerator $breadcrumbs) {
$breadcrumbs->parent('home');
$breadcrumbs->push(trans('firefly.csv_index_title'), route('csv.index'));
}
);
Breadcrumbs::register(
'csv.column-roles', function (BreadCrumbGenerator $breadcrumbs) {
$breadcrumbs->parent('csv.index');
$breadcrumbs->push(trans('firefly.csv_define_column_roles'), route('csv.column-roles'));
}
);
Breadcrumbs::register(
'csv.map', function (BreadCrumbGenerator $breadcrumbs) {
$breadcrumbs->parent('csv.index');
$breadcrumbs->push(trans('firefly.csv_map_values'), route('csv.map'));
}
);
Breadcrumbs::register(
'csv.download-config-page', function (BreadCrumbGenerator $breadcrumbs) {
$breadcrumbs->parent('csv.index');
$breadcrumbs->push(trans('firefly.csv_download_config'), route('csv.download-config-page'));
}
);
Breadcrumbs::register(
'csv.process', function (BreadCrumbGenerator $breadcrumbs) {
$breadcrumbs->parent('csv.index');
$breadcrumbs->push(trans('firefly.csv_process_title'), route('csv.process'));
}
);
/**
* CURRENCIES
*/
@@ -613,4 +599,4 @@ Breadcrumbs::register(
$breadcrumbs->parent('transactions.index', $what);
$breadcrumbs->push(trans('breadcrumbs.create_' . e($what)), route('split.journal.create', [$what]));
}
);
);

View File

@@ -157,21 +157,6 @@ Route::group(
Route::post('/categories/update/{category}', ['uses' => 'CategoryController@update', 'as' => 'categories.update']);
Route::post('/categories/destroy/{category}', ['uses' => 'CategoryController@destroy', 'as' => 'categories.destroy']);
/**
* CSV controller
*/
Route::get('/csv', ['uses' => 'CsvController@index', 'as' => 'csv.index']);
Route::post('/csv/upload', ['uses' => 'CsvController@upload', 'as' => 'csv.upload']);
Route::get('/csv/column_roles', ['uses' => 'CsvController@columnRoles', 'as' => 'csv.column-roles']);
Route::post('/csv/initial_parse', ['uses' => 'CsvController@initialParse', 'as' => 'csv.initial_parse']);
Route::get('/csv/map', ['uses' => 'CsvController@map', 'as' => 'csv.map']);
Route::get('/csv/download-config', ['uses' => 'CsvController@downloadConfig', 'as' => 'csv.download-config']);
Route::get('/csv/download', ['uses' => 'CsvController@downloadConfigPage', 'as' => 'csv.download-config-page']);
Route::post('/csv/save_mapping', ['uses' => 'CsvController@saveMapping', 'as' => 'csv.save_mapping']);
Route::get('/csv/process', ['uses' => 'CsvController@process', 'as' => 'csv.process']);
/**
* Currency Controller
*/
@@ -235,6 +220,18 @@ Route::group(
Route::get('/chart/report/in-out-sum/{reportType}/{start_date}/{end_date}/{accountList}', ['uses' => 'Chart\ReportController@yearInOutSummarized']);
Route::get('/chart/report/net-worth/{reportType}/{start_date}/{end_date}/{accountList}', ['uses' => 'Chart\ReportController@netWorth']);
/**
* IMPORT CONTROLLER
*/
Route::get('/import', ['uses' => 'ImportController@index', 'as' => 'import.index']);
Route::post('/import/upload', ['uses' => 'ImportController@upload', 'as' => 'import.upload']);
Route::get('/import/configure/{importJob}', ['uses' => 'ImportController@configure', 'as' => 'import.configure']);
Route::post('/import/configure/{importJob}', ['uses' => 'ImportController@postConfigure', 'as' => 'import.process_configuration']);
Route::get('/import/settings/{importJob}', ['uses' => 'ImportController@settings', 'as' => 'import.settings']);
Route::post('/import/settings/{importJob}', ['uses' => 'ImportController@postSettings', 'as' => 'import.postSettings']);
Route::get('/import/complete/{importJob}', ['uses' => 'ImportController@complete', 'as' => 'import.complete']);
Route::get('/import/download/{importJob}', ['uses' => 'ImportController@download', 'as' => 'import.download']);
/**
* Help Controller
@@ -272,6 +269,13 @@ Route::group(
Route::get('/piggy-banks', ['uses' => 'PiggyBankController@index', 'as' => 'piggy-banks.index']);
Route::get('/piggy-banks/add/{piggyBank}', ['uses' => 'PiggyBankController@add', 'as' => 'piggy-banks.addMoney']);
Route::get('/piggy-banks/remove/{piggyBank}', ['uses' => 'PiggyBankController@remove', 'as' => 'piggy-banks.removeMoney']);
Route::get('/piggy-banks/add-money/{piggyBank}', ['uses' => 'PiggyBankController@addMobile', 'as' => 'piggy-banks.add-money-mobile']);
Route::get('/piggy-banks/remove-money/{piggyBank}', ['uses' => 'PiggyBankController@removeMobile', 'as' => 'piggy-banks.remove-money-mobile']);
Route::post('/piggy-banks/add-money/{piggyBank}', ['uses' => 'PiggyBankController@postAddMobile', 'as' => 'piggy-banks.post-add-mobile']);
Route::post('/piggy-banks/remove-money/{piggyBank}', ['uses' => 'PiggyBankController@postRemoveMobile', 'as' => 'piggy-banks.post-remove-mobile']);
Route::get('/piggy-banks/create', ['uses' => 'PiggyBankController@create', 'as' => 'piggy-banks.create']);
Route::get('/piggy-banks/edit/{piggyBank}', ['uses' => 'PiggyBankController@edit', 'as' => 'piggy-banks.edit']);
Route::get('/piggy-banks/delete/{piggyBank}', ['uses' => 'PiggyBankController@delete', 'as' => 'piggy-banks.delete']);
@@ -420,6 +424,12 @@ Route::group(
// user manager
Route::get('/admin/users', ['uses' => 'Admin\UserController@index', 'as' => 'admin.users']);
Route::get('/admin/users/edit/{user}', ['uses' => 'Admin\UserController@edit', 'as' => 'admin.users.edit']);
// user domains:
Route::get('/admin/domains', ['uses' => 'Admin\DomainController@domains', 'as' => 'admin.users.domains']);
Route::get('/admin/domains/toggle/{domain}', ['uses' => 'Admin\DomainController@toggleDomain', 'as' => 'admin.users.domains.block-toggle']);
Route::post('/admin/domains/manual', ['uses' => 'Admin\DomainController@manual', 'as' => 'admin.users.domains.manual']);
}
);

View File

@@ -0,0 +1,65 @@
<?php
/**
* AccountId.php
* Copyright (C) 2016 thegrumpydictator@gmail.com
*
* This software may be modified and distributed under the terms
* of the MIT license. See the LICENSE file for details.
*/
declare(strict_types = 1);
namespace FireflyIII\Import\Converter;
use FireflyIII\Crud\Account\AccountCrudInterface;
use FireflyIII\Models\Account;
use Log;
/**
* Class AccountId
*
* @package FireflyIII\Import\Converter
*/
class AccountId extends BasicConverter implements ConverterInterface
{
/**
* @param $value
*
* @return Account
*/
public function convert($value)
{
$value = intval(trim($value));
Log::debug('Going to convert using AssetAccountId', ['value' => $value]);
if ($value === 0) {
$this->setCertainty(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]);
$this->setCertainty(100);
return $account;
}
}
$account = $repository->find($value);// not mapped? Still try to find it first:
if (!is_null($account->id)) {
$this->setCertainty(90);
Log::debug('Found account by ID ', ['id' => $account->id]);
return $account;
}
$this->setCertainty(0); // should not really happen. If the ID does not match FF, what is FF supposed to do?
return new Account;
}
}

View File

@@ -0,0 +1,65 @@
<?php
/**
* Amount.php
* Copyright (C) 2016 thegrumpydictator@gmail.com
*
* This software may be modified and distributed under the terms
* of the MIT license. See the LICENSE file for details.
*/
declare(strict_types = 1);
namespace FireflyIII\Import\Converter;
/**
* Class RabobankDebetCredit
*
* @package FireflyIII\Import\Converter
*/
class Amount extends BasicConverter implements ConverterInterface
{
/**
* Some people, when confronted with a problem, think "I know, I'll use regular expressions." Now they have two problems.
* - Jamie Zawinski
*
* @param $value
*
* @return float
*/
public function convert($value): float
{
$len = strlen($value);
$decimalPosition = $len - 3;
$decimal = null;
if ($len > 2 && $value{$decimalPosition} == '.') {
$decimal = '.';
}
if ($len > 2 && $value{$decimalPosition} == ',') {
$decimal = ',';
}
// if decimal is dot, replace all comma's and spaces with nothing. then parse as float (round to 4 pos)
if ($decimal === '.') {
$search = [',', ' '];
$value = str_replace($search, '', $value);
}
if ($decimal === ',') {
$search = ['.', ' '];
$value = str_replace($search, '', $value);
$value = str_replace(',', '.', $value);
}
if (is_null($decimal)) {
// replace all:
$search = ['.', ' ', ','];
$value = str_replace($search, '', $value);
}
$this->setCertainty(90);
return round(floatval($value), 4);
}
}

View File

@@ -0,0 +1,84 @@
<?php
/**
* AssetAccountIban.php
* Copyright (C) 2016 thegrumpydictator@gmail.com
*
* This software may be modified and distributed under the terms
* of the MIT license. See the LICENSE file for details.
*/
declare(strict_types = 1);
namespace FireflyIII\Import\Converter;
use FireflyIII\Crud\Account\AccountCrudInterface;
use FireflyIII\Models\Account;
use FireflyIII\Models\AccountType;
use Log;
/**
* Class AssetAccountIban
*
* @package FireflyIII\Import\Converter
*/
class AssetAccountIban extends BasicConverter implements ConverterInterface
{
/**
* @param $value
*
* @return Account
*/
public function convert($value): Account
{
$value = trim($value);
Log::debug('Going to convert ', ['value' => $value]);
if (strlen($value) === 0) {
$this->setCertainty(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)) {
$this->setCertainty(100);
Log::debug('Found account by ID', ['id' => $account->id]);
return $account;
}
}
// not mapped? Still try to find it first:
$account = $repository->findByIban($value, [AccountType::ASSET]);
if (!is_null($account->id)) {
Log::debug('Found account by IBAN', ['id' => $account->id]);
$this->setCertainty(50);
return $account;
}
$account = $repository->store(
['name' => 'Asset account with IBAN ' . $value, 'iban' => $value, 'user' => $this->user->id, 'accountType' => 'asset', 'virtualBalance' => 0,
'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);
return $account;
}
}

Some files were not shown because too many files have changed in this diff Show More