From 91fe1493a714cde0fcfeede6c51656322d40f89f Mon Sep 17 00:00:00 2001 From: James Cole Date: Fri, 6 Apr 2018 12:44:43 +0200 Subject: [PATCH 001/117] Improve edit routine for split transactions. --- .../Controllers/Transaction/SplitController.php | 17 +++++++++++++---- app/Support/Twig/Extension/Transaction.php | 2 +- app/Transformers/TransactionTransformer.php | 1 - resources/views/transactions/single/edit.twig | 11 ++++++++--- resources/views/transactions/split/edit.twig | 2 +- 5 files changed, 23 insertions(+), 10 deletions(-) diff --git a/app/Http/Controllers/Transaction/SplitController.php b/app/Http/Controllers/Transaction/SplitController.php index 5b184eb55b..d0a961fb41 100644 --- a/app/Http/Controllers/Transaction/SplitController.php +++ b/app/Http/Controllers/Transaction/SplitController.php @@ -33,6 +33,7 @@ use FireflyIII\Models\Account; use FireflyIII\Models\AccountType; use FireflyIII\Models\Transaction; use FireflyIII\Models\TransactionJournal; +use FireflyIII\Models\TransactionType; use FireflyIII\Repositories\Account\AccountRepositoryInterface; use FireflyIII\Repositories\Budget\BudgetRepositoryInterface; use FireflyIII\Repositories\Currency\CurrencyRepositoryInterface; @@ -114,7 +115,7 @@ class SplitController extends Controller /** @var Account $account */ foreach ($accountList as $account) { $accountArray[$account->id] = $account; - $accountArray[$account->id]['currency_id'] = (int)$account->getMeta('currency_id'); + $accountArray[$account->id]['currency_id'] = (int)$this->accounts->getMetaValue($account, 'currency_id'); } // put previous url in session if not redirect from store (not "return_to_edit"). @@ -235,11 +236,19 @@ class SplitController extends Controller $set = $collector->getJournals(); $transactions = []; $transformer = new TransactionTransformer(new ParameterBag); - /** @var Transaction $transaction */ foreach ($set as $transaction) { - if ($transaction->transaction_amount > 0) { - $transactions[] = $transformer->transform($transaction); + $res = []; + if ((float)$transaction->transaction_amount > 0 && $journal->transactionType->type === TransactionType::DEPOSIT) { + $res = $transformer->transform($transaction); + } + if ((float)$transaction->transaction_amount < 0 && $journal->transactionType->type !== TransactionType::DEPOSIT) { + $res = $transformer->transform($transaction); + } + + if (count($res) > 0) { + $res['amount'] = app('steam')->positive((string)$res['amount']); + $transactions[] = $res; } } diff --git a/app/Support/Twig/Extension/Transaction.php b/app/Support/Twig/Extension/Transaction.php index c461925e78..622d08d6ed 100644 --- a/app/Support/Twig/Extension/Transaction.php +++ b/app/Support/Twig/Extension/Transaction.php @@ -357,7 +357,7 @@ class Transaction extends Twig_Extension { $res = ''; if ($transaction->is_split === true) { - $res = '!!!'; + $res = ''; } if ($transaction->is_split === null) { diff --git a/app/Transformers/TransactionTransformer.php b/app/Transformers/TransactionTransformer.php index 4f028bc60e..0a12a23c2a 100644 --- a/app/Transformers/TransactionTransformer.php +++ b/app/Transformers/TransactionTransformer.php @@ -215,7 +215,6 @@ class TransactionTransformer extends TransformerAbstract if (null !== $transaction->transaction_foreign_amount) { $data['foreign_amount'] = round($transaction->transaction_foreign_amount, (int)$transaction->foreign_currency_dp); } - // switch on type for consistency switch ($transaction->transaction_type_type) { case TransactionType::WITHDRAWAL: diff --git a/resources/views/transactions/single/edit.twig b/resources/views/transactions/single/edit.twig index aba0cb3a51..13c50709be 100644 --- a/resources/views/transactions/single/edit.twig +++ b/resources/views/transactions/single/edit.twig @@ -33,6 +33,7 @@

{{ 'mandatoryFields'|_ }}

+ {# ALWAYS AVAILABLE #} {{ ExpandedForm.text('description',journal.description) }} @@ -81,7 +82,11 @@
{% if what == 'withdrawal' %} - {{ ExpandedForm.select('budget_id',budgetList,data['budget_id']) }} + {% if budgetList|length > 1 %} + {{ ExpandedForm.select('budget_id', budgetList, data['budget_id']) }} + {% else %} + {{ ExpandedForm.select('budget_id', budgetList, data['budget_id'], {helpText: trans('firefly.no_budget_pointer')}) }} + {% endif %} {% endif %} {{ ExpandedForm.text('category',data['category']) }} {{ ExpandedForm.text('tags') }} @@ -209,8 +214,8 @@
- - + + diff --git a/resources/views/transactions/split/edit.twig b/resources/views/transactions/split/edit.twig index 111529da7f..1cb3cbc0cb 100644 --- a/resources/views/transactions/split/edit.twig +++ b/resources/views/transactions/split/edit.twig @@ -228,7 +228,7 @@ {% if preFilled.what == 'withdrawal' %}
+ value="{% if transaction.destination_type != 'Cash account' %}{{ transaction.destination_name }}{% endif %}" class="form-control"/>
{% endif %} From 538e045e4cf1354535f3776058512e535bd2d6a7 Mon Sep 17 00:00:00 2001 From: James Cole Date: Fri, 6 Apr 2018 13:36:36 +0200 Subject: [PATCH 002/117] Give error for proc_close. --- .../Controllers/System/InstallController.php | 48 +++++++++++++++++-- public/js/ff/install/index.js | 34 +++++++++++-- 2 files changed, 72 insertions(+), 10 deletions(-) diff --git a/app/Http/Controllers/System/InstallController.php b/app/Http/Controllers/System/InstallController.php index 5aded663df..40dc71ce37 100644 --- a/app/Http/Controllers/System/InstallController.php +++ b/app/Http/Controllers/System/InstallController.php @@ -35,6 +35,8 @@ use phpseclib\Crypt\RSA; */ class InstallController extends Controller { + + public const FORBIDDEN_ERROR = 'Internal PHP function "proc_close" is disabled for your installation. Auto-migration is not possible.'; /** @noinspection MagicMethodsValidityInspection */ /** @noinspection PhpMissingParentConstructorInspection */ /** @@ -58,6 +60,9 @@ class InstallController extends Controller */ public function keys() { + if ($this->hasForbiddenFunctions()) { + return response()->json(['error' => true, 'message' => self::FORBIDDEN_ERROR]); + } // create keys manually because for some reason the passport namespace // does not exist $rsa = new RSA(); @@ -69,13 +74,13 @@ class InstallController extends Controller ]; if (file_exists($publicKey) || file_exists($privateKey)) { - return response()->json(['OK']); + return response()->json(['error' => false, 'message' => 'OK']); } file_put_contents($publicKey, array_get($keys, 'publickey')); file_put_contents($privateKey, array_get($keys, 'privatekey')); - return response()->json(['OK']); + return response()->json(['error' => false, 'message' => 'OK']); } /** @@ -83,11 +88,15 @@ class InstallController extends Controller */ public function migrate() { + if ($this->hasForbiddenFunctions()) { + return response()->json(['error' => true, 'message' => self::FORBIDDEN_ERROR]); + } + Log::debug('Am now calling migrate routine...'); Artisan::call('migrate', ['--seed' => true, '--force' => true]); Log::debug(Artisan::output()); - return response()->json(['OK']); + return response()->json(['error' => false, 'message' => 'OK']); } /** @@ -95,11 +104,14 @@ class InstallController extends Controller */ public function upgrade() { + if ($this->hasForbiddenFunctions()) { + return response()->json(['error' => true, 'message' => self::FORBIDDEN_ERROR]); + } Log::debug('Am now calling upgrade database routine...'); Artisan::call('firefly:upgrade-database'); Log::debug(Artisan::output()); - return response()->json(['OK']); + return response()->json(['error' => false, 'message' => 'OK']); } /** @@ -107,11 +119,37 @@ class InstallController extends Controller */ public function verify() { + if ($this->hasForbiddenFunctions()) { + return response()->json(['error' => true, 'message' => self::FORBIDDEN_ERROR]); + } Log::debug('Am now calling verify database routine...'); Artisan::call('firefly:verify'); Log::debug(Artisan::output()); - return response()->json(['OK']); + return response()->json(['error' => false, 'message' => 'OK']); + } + + /** + * @return bool + */ + private function hasForbiddenFunctions(): bool + { + $list = ['proc_close']; + $forbidden = explode(',', ini_get('disable_functions')); + $trimmed = array_map( + function (string $value) { + return trim($value); + }, $forbidden + ); + foreach ($list as $entry) { + if (\in_array($entry, $trimmed, true)) { + Log::error('Method "%s" is FORBIDDEN, so the console command cannot be executed.'); + + return true; + } + } + + return false; } } diff --git a/public/js/ff/install/index.js b/public/js/ff/install/index.js index ac3f5e34b3..ce385c79a9 100644 --- a/public/js/ff/install/index.js +++ b/public/js/ff/install/index.js @@ -28,8 +28,13 @@ $(function () { function startMigration() { $('#status-box').html(' Setting up DB...'); - $.post(migrateUri, {_token: token}).done(function () { - startPassport(); + $.post(migrateUri, {_token: token}).done(function (data) { + if(data.error === false) { + startPassport(); + } else { + displaySoftFail(data.message); + } + }).fail(function () { $('#status-box').html(' Migration failed! See log files :('); }); @@ -41,7 +46,12 @@ function startMigration() { function startPassport() { $('#status-box').html(' Setting up OAuth2...'); $.post(keysUri, {_token: token}).done(function () { - startUpgrade(); + if(data.error === false) { + startUpgrade(); + } else { + displaySoftFail(data.message); + } + }).fail(function () { $('#status-box').html(' OAuth2 failed! See log files :('); }); @@ -53,7 +63,11 @@ function startPassport() { function startUpgrade() { $('#status-box').html(' Upgrading database...'); $.post(upgradeUri, {_token: token}).done(function () { - startVerify(); + if(data.error === false) { + startVerify(); + } else { + displaySoftFail(data.message); + } }).fail(function () { $('#status-box').html(' Upgrade failed! See log files :('); }); @@ -65,7 +79,11 @@ function startUpgrade() { function startVerify() { $('#status-box').html(' Verify database integrity...'); $.post(verifyUri, {_token: token}).done(function () { - completeDone(); + if(data.error === false) { + completeDone(); + } else { + displaySoftFail(data.message); + } }).fail(function () { $('#status-box').html(' Verification failed! See log files :('); }); @@ -79,4 +97,10 @@ function completeDone() { setTimeout(function () { window.location = homeUri; }, 3000); +} + +function displaySoftFail(message) { + $('#status-box').html(' ' + message + '

Please read the ' + + '' + + 'official documentation about this.'); } \ No newline at end of file From 7812a1bb51ac3c1c51c25175fbdbce5773586759 Mon Sep 17 00:00:00 2001 From: James Cole Date: Fri, 6 Apr 2018 18:14:48 +0200 Subject: [PATCH 003/117] Fix for #1320 --- .deploy/docker/entrypoint.sh | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/.deploy/docker/entrypoint.sh b/.deploy/docker/entrypoint.sh index 088a999742..c04a7d10ff 100755 --- a/.deploy/docker/entrypoint.sh +++ b/.deploy/docker/entrypoint.sh @@ -1,8 +1,11 @@ #!/bin/bash # make sure we own the volumes: -chown -R www-data:www-data $FIREFLY_PATH/storage/export $FIREFLY_PATH/storage/upload -chmod -R 775 $FIREFLY_PATH/storage/export $FIREFLY_PATH/storage/upload +chown -R www-data:www-data -R $FIREFLY_PATH/storage/export $FIREFLY_PATH/storage/upload $FIREFLY_PATH/storage/logs +chmod -R 775 $FIREFLY_PATH/storage/export $FIREFLY_PATH/storage/upload $FIREFLY_PATH/storage/upload $FIREFLY_PATH/storage/logs + +# remove any lingering files that may break upgrades: +rm -f $FIREFLY_PATH/storage/logs/laravel.log cat .env.docker | envsubst > .env && cat .env composer dump-autoload From 371b58a8070b53beee1ff8bfdbac61b081af2095 Mon Sep 17 00:00:00 2001 From: James Cole Date: Fri, 6 Apr 2018 21:38:17 +0200 Subject: [PATCH 004/117] Make upgrade routine not trigger everywhere. --- app/Http/Kernel.php | 1 - public/js/ff/install/index.js | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/app/Http/Kernel.php b/app/Http/Kernel.php index 6b6b17dd59..5fcf14adda 100644 --- a/app/Http/Kernel.php +++ b/app/Http/Kernel.php @@ -67,7 +67,6 @@ class Kernel extends HttpKernel TrimStrings::class, ConvertEmptyStringsToNull::class, TrustProxies::class, - Installer::class, ]; /** diff --git a/public/js/ff/install/index.js b/public/js/ff/install/index.js index ce385c79a9..dca7ec945e 100644 --- a/public/js/ff/install/index.js +++ b/public/js/ff/install/index.js @@ -102,5 +102,5 @@ function completeDone() { function displaySoftFail(message) { $('#status-box').html(' ' + message + '

Please read the ' + '' + - 'official documentation about this.'); + 'official documentation about this, and upgrade by hand.'); } \ No newline at end of file From 43e49bf14a69cdfee35c2b34a6fa0d8e6f7ff9d1 Mon Sep 17 00:00:00 2001 From: James Cole Date: Fri, 6 Apr 2018 21:38:43 +0200 Subject: [PATCH 005/117] Fire middleware on index. --- app/Http/Controllers/HomeController.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/app/Http/Controllers/HomeController.php b/app/Http/Controllers/HomeController.php index f47bce951f..55d0183346 100644 --- a/app/Http/Controllers/HomeController.php +++ b/app/Http/Controllers/HomeController.php @@ -28,6 +28,7 @@ use Exception; use FireflyIII\Events\RequestedVersionCheckStatus; use FireflyIII\Exceptions\FireflyException; use FireflyIII\Helpers\Collector\JournalCollectorInterface; +use FireflyIII\Http\Middleware\Installer; use FireflyIII\Http\Middleware\IsDemoUser; use FireflyIII\Http\Middleware\IsSandStormUser; use FireflyIII\Models\AccountType; @@ -54,8 +55,10 @@ class HomeController extends Controller parent::__construct(); app('view')->share('title', 'Firefly III'); app('view')->share('mainTitleIcon', 'fa-fire'); + $this->middleware(Installer::class); $this->middleware(IsDemoUser::class)->except(['dateRange', 'index']); $this->middleware(IsSandStormUser::class)->only('routes'); + } /** From cee6bbf1349d020227a68649d5b9a698d5487d92 Mon Sep 17 00:00:00 2001 From: James Cole Date: Fri, 6 Apr 2018 22:24:57 +0200 Subject: [PATCH 006/117] Update files for Sandstorm. --- .sandstorm/sandstorm-files.list | 239 ++++++++++++++++++------------ .sandstorm/sandstorm-pkgdef.capnp | 2 +- 2 files changed, 145 insertions(+), 96 deletions(-) diff --git a/.sandstorm/sandstorm-files.list b/.sandstorm/sandstorm-files.list index a79d0bb307..06a302593d 100644 --- a/.sandstorm/sandstorm-files.list +++ b/.sandstorm/sandstorm-files.list @@ -202,7 +202,6 @@ lib/x86_64-linux-gnu/libz.so.1.2.8 lib64/ld-linux-x86-64.so.2 opt/app/.codeclimate.yml opt/app/.env -opt/app/.env.current opt/app/.env.docker opt/app/.env.example opt/app/.env.heroku @@ -341,12 +340,14 @@ opt/app/app/Helpers/Collection/Category.php opt/app/app/Helpers/Collector/JournalCollector.php opt/app/app/Helpers/Collector/JournalCollectorInterface.php opt/app/app/Helpers/Filter/AmountFilter.php +opt/app/app/Helpers/Filter/CountAttachmentsFilter.php opt/app/app/Helpers/Filter/EmptyFilter.php opt/app/app/Helpers/Filter/FilterInterface.php opt/app/app/Helpers/Filter/InternalTransferFilter.php opt/app/app/Helpers/Filter/NegativeAmountFilter.php opt/app/app/Helpers/Filter/OpposingAccountFilter.php opt/app/app/Helpers/Filter/PositiveAmountFilter.php +opt/app/app/Helpers/Filter/SplitIndicatorFilter.php opt/app/app/Helpers/Filter/TransferFilter.php opt/app/app/Helpers/FiscalHelper.php opt/app/app/Helpers/FiscalHelperInterface.php @@ -418,6 +419,7 @@ opt/app/app/Http/Controllers/ReportController.php opt/app/app/Http/Controllers/RuleController.php opt/app/app/Http/Controllers/RuleGroupController.php opt/app/app/Http/Controllers/SearchController.php +opt/app/app/Http/Controllers/System/InstallController.php opt/app/app/Http/Controllers/TagController.php opt/app/app/Http/Controllers/Transaction/BulkController.php opt/app/app/Http/Controllers/Transaction/ConvertController.php @@ -431,6 +433,7 @@ opt/app/app/Http/Middleware/Authenticate.php opt/app/app/Http/Middleware/AuthenticateTwoFactor.php opt/app/app/Http/Middleware/Binder.php opt/app/app/Http/Middleware/EncryptCookies.php +opt/app/app/Http/Middleware/Installer.php opt/app/app/Http/Middleware/IsAdmin.php opt/app/app/Http/Middleware/IsDemoUser.php opt/app/app/Http/Middleware/IsSandStormUser.php @@ -475,6 +478,7 @@ opt/app/app/Http/Requests/TestRuleFormRequest.php opt/app/app/Http/Requests/TokenFormRequest.php opt/app/app/Http/Requests/UserFormRequest.php opt/app/app/Http/Requests/UserRegistrationRequest.php +opt/app/app/Import/Configuration/BunqConfigurator.php opt/app/app/Import/Configuration/ConfiguratorInterface.php opt/app/app/Import/Configuration/FileConfigurator.php opt/app/app/Import/Configuration/SpectreConfigurator.php @@ -510,6 +514,7 @@ opt/app/app/Import/Prerequisites/BunqPrerequisites.php opt/app/app/Import/Prerequisites/FilePrerequisites.php opt/app/app/Import/Prerequisites/PrerequisitesInterface.php opt/app/app/Import/Prerequisites/SpectrePrerequisites.php +opt/app/app/Import/Routine/BunqRoutine.php opt/app/app/Import/Routine/FileRoutine.php opt/app/app/Import/Routine/RoutineInterface.php opt/app/app/Import/Routine/SpectreRoutine.php @@ -605,8 +610,6 @@ opt/app/app/Repositories/ImportJob/ImportJobRepository.php opt/app/app/Repositories/ImportJob/ImportJobRepositoryInterface.php opt/app/app/Repositories/Journal/JournalRepository.php opt/app/app/Repositories/Journal/JournalRepositoryInterface.php -opt/app/app/Repositories/Journal/JournalTasker.php -opt/app/app/Repositories/Journal/JournalTaskerInterface.php opt/app/app/Repositories/LinkType/LinkTypeRepository.php opt/app/app/Repositories/LinkType/LinkTypeRepositoryInterface.php opt/app/app/Repositories/PiggyBank/PiggyBankRepository.php @@ -633,10 +636,14 @@ opt/app/app/Services/Bunq/Object/Amount.php opt/app/app/Services/Bunq/Object/Avatar.php opt/app/app/Services/Bunq/Object/BunqObject.php opt/app/app/Services/Bunq/Object/DeviceServer.php +opt/app/app/Services/Bunq/Object/Image.php +opt/app/app/Services/Bunq/Object/LabelMonetaryAccount.php +opt/app/app/Services/Bunq/Object/LabelUser.php opt/app/app/Services/Bunq/Object/MonetaryAccountBank.php opt/app/app/Services/Bunq/Object/MonetaryAccountProfile.php opt/app/app/Services/Bunq/Object/MonetaryAccountSetting.php opt/app/app/Services/Bunq/Object/NotificationFilter.php +opt/app/app/Services/Bunq/Object/Payment.php opt/app/app/Services/Bunq/Object/ServerPublicKey.php opt/app/app/Services/Bunq/Object/UserCompany.php opt/app/app/Services/Bunq/Object/UserLight.php @@ -648,28 +655,36 @@ opt/app/app/Services/Bunq/Request/DeviceSessionRequest.php opt/app/app/Services/Bunq/Request/InstallationTokenRequest.php opt/app/app/Services/Bunq/Request/ListDeviceServerRequest.php opt/app/app/Services/Bunq/Request/ListMonetaryAccountRequest.php +opt/app/app/Services/Bunq/Request/ListPaymentRequest.php opt/app/app/Services/Bunq/Request/ListUserRequest.php opt/app/app/Services/Bunq/Token/BunqToken.php opt/app/app/Services/Bunq/Token/InstallationToken.php opt/app/app/Services/Bunq/Token/SessionToken.php opt/app/app/Services/Currency/ExchangeRateInterface.php opt/app/app/Services/Currency/FixerIO.php +opt/app/app/Services/Currency/FixerIOv2.php opt/app/app/Services/Github/Object/GithubObject.php opt/app/app/Services/Github/Object/Release.php opt/app/app/Services/Github/Request/GithubRequest.php opt/app/app/Services/Github/Request/UpdateRequest.php opt/app/app/Services/Internal/Destroy/AccountDestroyService.php opt/app/app/Services/Internal/Destroy/BillDestroyService.php +opt/app/app/Services/Internal/Destroy/CategoryDestroyService.php +opt/app/app/Services/Internal/Destroy/CurrencyDestroyService.php opt/app/app/Services/Internal/Destroy/JournalDestroyService.php +opt/app/app/Services/Internal/File/EncryptService.php opt/app/app/Services/Internal/Support/AccountServiceTrait.php opt/app/app/Services/Internal/Support/BillServiceTrait.php opt/app/app/Services/Internal/Support/JournalServiceTrait.php opt/app/app/Services/Internal/Support/TransactionServiceTrait.php opt/app/app/Services/Internal/Update/AccountUpdateService.php opt/app/app/Services/Internal/Update/BillUpdateService.php +opt/app/app/Services/Internal/Update/CategoryUpdateService.php +opt/app/app/Services/Internal/Update/CurrencyUpdateService.php opt/app/app/Services/Internal/Update/JournalUpdateService.php opt/app/app/Services/Internal/Update/TransactionUpdateService.php opt/app/app/Services/Password/PwndVerifier.php +opt/app/app/Services/Password/PwndVerifierV2.php opt/app/app/Services/Password/Verifier.php opt/app/app/Services/Spectre/Exception/DuplicatedCustomerException.php opt/app/app/Services/Spectre/Exception/SpectreException.php @@ -711,6 +726,7 @@ opt/app/app/Support/Facades/Navigation.php opt/app/app/Support/Facades/Preferences.php opt/app/app/Support/Facades/Steam.php opt/app/app/Support/FireflyConfig.php +opt/app/app/Support/Import/Configuration/Bunq/HaveAccounts.php opt/app/app/Support/Import/Configuration/ConfigurationInterface.php opt/app/app/Support/Import/Configuration/File/Initial.php opt/app/app/Support/Import/Configuration/File/Map.php @@ -824,8 +840,10 @@ opt/app/config/database.php opt/app/config/filesystems.php opt/app/config/firefly.php opt/app/config/google2fa.php +opt/app/config/hashing.php opt/app/config/import.php opt/app/config/intro.php +opt/app/config/logging.php opt/app/config/mail.php opt/app/config/queue.php opt/app/config/services.php @@ -834,6 +852,7 @@ opt/app/config/twigbridge.php opt/app/config/upgrade.php opt/app/config/view.php opt/app/database/factories/ModelFactory.php +opt/app/database/migrations opt/app/database/migrations/2016_06_16_000000_create_support_tables.php opt/app/database/migrations/2016_06_16_000001_create_users_table.php opt/app/database/migrations/2016_06_16_000002_create_main_tables.php @@ -853,7 +872,9 @@ opt/app/database/migrations/2018_01_01_000002_create_oauth_access_tokens_table.p opt/app/database/migrations/2018_01_01_000003_create_oauth_refresh_tokens_table.php opt/app/database/migrations/2018_01_01_000004_create_oauth_clients_table.php opt/app/database/migrations/2018_01_01_000005_create_oauth_personal_access_clients_table.php +opt/app/database/migrations/2018_03_19_141348_changes_for_v472.php opt/app/database/seeds/AccountTypeSeeder.php +opt/app/database/seeds/ConfigSeeder.php opt/app/database/seeds/DatabaseSeeder.php opt/app/database/seeds/LinkTypeSeeder.php opt/app/database/seeds/PermissionSeeder.php @@ -1046,6 +1067,7 @@ opt/app/public/js/ff/guest.js opt/app/public/js/ff/help.js opt/app/public/js/ff/import/status.js opt/app/public/js/ff/index.js +opt/app/public/js/ff/install/index.js opt/app/public/js/ff/intro/intro.js opt/app/public/js/ff/piggy-banks/create.js opt/app/public/js/ff/piggy-banks/edit.js @@ -1085,6 +1107,7 @@ opt/app/public/js/lib/bootstrap-sortable.js opt/app/public/js/lib/bootstrap-tagsinput.min.js opt/app/public/js/lib/bootstrap-tagsinput.min.js.map opt/app/public/js/lib/bootstrap3-typeahead.min.js +opt/app/public/js/lib/chartjs-plugin-annotation.min.js opt/app/public/js/lib/daterangepicker.js opt/app/public/js/lib/html5shiv.min.js opt/app/public/js/lib/jquery-ui.min.js @@ -1115,7 +1138,6 @@ opt/app/public/lib/leaflet/leaflet.js.map opt/app/public/manifest.json opt/app/public/mix-manifest.json opt/app/public/mstile-150x150.png -opt/app/public/report.html opt/app/public/robots.txt opt/app/public/safari-pinned-tab.svg opt/app/public/web.config @@ -1128,7 +1150,6 @@ opt/app/resources/assets/js/components/passport/AuthorizedClients.vue opt/app/resources/assets/js/components/passport/Clients.vue opt/app/resources/assets/js/components/passport/PersonalAccessTokens.vue opt/app/resources/assets/js/lang.js -opt/app/resources/assets/js/messages.js opt/app/resources/assets/sass/_variables.scss opt/app/resources/assets/sass/app.scss opt/app/resources/lang/de_DE/auth.php @@ -1208,6 +1229,21 @@ opt/app/resources/lang/id_ID/list.php opt/app/resources/lang/id_ID/pagination.php opt/app/resources/lang/id_ID/passwords.php opt/app/resources/lang/id_ID/validation.php +opt/app/resources/lang/it_IT/auth.php +opt/app/resources/lang/it_IT/bank.php +opt/app/resources/lang/it_IT/breadcrumbs.php +opt/app/resources/lang/it_IT/components.php +opt/app/resources/lang/it_IT/config.php +opt/app/resources/lang/it_IT/csv.php +opt/app/resources/lang/it_IT/demo.php +opt/app/resources/lang/it_IT/firefly.php +opt/app/resources/lang/it_IT/form.php +opt/app/resources/lang/it_IT/import.php +opt/app/resources/lang/it_IT/intro.php +opt/app/resources/lang/it_IT/list.php +opt/app/resources/lang/it_IT/pagination.php +opt/app/resources/lang/it_IT/passwords.php +opt/app/resources/lang/it_IT/validation.php opt/app/resources/lang/nl_NL/auth.php opt/app/resources/lang/nl_NL/bank.php opt/app/resources/lang/nl_NL/breadcrumbs.php @@ -1289,7 +1325,6 @@ opt/app/resources/stubs/binary.bin opt/app/resources/stubs/csv.csv opt/app/resources/stubs/demo-configuration.json opt/app/resources/stubs/demo-import.csv -opt/app/resources/tests/blns.base64.json opt/app/resources/views/accounts/create.twig opt/app/resources/views/accounts/delete.twig opt/app/resources/views/accounts/edit.twig @@ -1400,6 +1435,7 @@ opt/app/resources/views/form/tags.twig opt/app/resources/views/form/text.twig opt/app/resources/views/form/textarea.twig opt/app/resources/views/import/bank/form.twig +opt/app/resources/views/import/bunq/accounts.twig opt/app/resources/views/import/bunq/prerequisites.twig opt/app/resources/views/import/file/initial.twig opt/app/resources/views/import/file/map.twig @@ -1411,6 +1447,7 @@ opt/app/resources/views/import/spectre/prerequisites.twig opt/app/resources/views/import/spectre/redirect.twig opt/app/resources/views/import/status.twig opt/app/resources/views/index.twig +opt/app/resources/views/install/index.twig opt/app/resources/views/javascript/accounts.twig opt/app/resources/views/javascript/currencies.twig opt/app/resources/views/javascript/variables.twig @@ -1418,6 +1455,7 @@ opt/app/resources/views/json/piggy-banks.twig opt/app/resources/views/layout/default.twig opt/app/resources/views/layout/empty.twig opt/app/resources/views/layout/guest.twig +opt/app/resources/views/layout/install.twig opt/app/resources/views/list/accounts.twig opt/app/resources/views/list/bills.twig opt/app/resources/views/list/categories.twig @@ -1451,10 +1489,10 @@ opt/app/resources/views/popup/report/budget-spent-amount.twig opt/app/resources/views/popup/report/category-entry.twig opt/app/resources/views/popup/report/expense-entry.twig opt/app/resources/views/popup/report/income-entry.twig -opt/app/resources/views/preferences/code.twig opt/app/resources/views/preferences/index.twig opt/app/resources/views/profile/change-email.twig opt/app/resources/views/profile/change-password.twig +opt/app/resources/views/profile/code.twig opt/app/resources/views/profile/delete-account.twig opt/app/resources/views/profile/index.twig opt/app/resources/views/reports/account/report.twig @@ -1523,6 +1561,7 @@ opt/app/routes/breadcrumbs.php opt/app/routes/channels.php opt/app/routes/console.php opt/app/routes/web.php +opt/app/security.txt opt/app/server.php opt/app/storage opt/app/vendor/autoload.php @@ -1801,6 +1840,7 @@ opt/app/vendor/doctrine/dbal/lib/Doctrine/DBAL/Cache/ArrayStatement.php opt/app/vendor/doctrine/dbal/lib/Doctrine/DBAL/Cache/CacheException.php opt/app/vendor/doctrine/dbal/lib/Doctrine/DBAL/Cache/QueryCacheProfile.php opt/app/vendor/doctrine/dbal/lib/Doctrine/DBAL/Cache/ResultCacheStatement.php +opt/app/vendor/doctrine/dbal/lib/Doctrine/DBAL/ColumnCase.php opt/app/vendor/doctrine/dbal/lib/Doctrine/DBAL/Configuration.php opt/app/vendor/doctrine/dbal/lib/Doctrine/DBAL/Connection.php opt/app/vendor/doctrine/dbal/lib/Doctrine/DBAL/ConnectionException.php @@ -1856,6 +1896,7 @@ opt/app/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/SQLSrv/SQLSrvException.php opt/app/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/SQLSrv/SQLSrvStatement.php opt/app/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/ServerInfoAwareConnection.php opt/app/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/Statement.php +opt/app/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/StatementIterator.php opt/app/vendor/doctrine/dbal/lib/Doctrine/DBAL/DriverManager.php opt/app/vendor/doctrine/dbal/lib/Doctrine/DBAL/Event/ConnectionEventArgs.php opt/app/vendor/doctrine/dbal/lib/Doctrine/DBAL/Event/Listeners/MysqlSessionInit.php @@ -1892,6 +1933,7 @@ opt/app/vendor/doctrine/dbal/lib/Doctrine/DBAL/Exception/SyntaxErrorException.ph opt/app/vendor/doctrine/dbal/lib/Doctrine/DBAL/Exception/TableExistsException.php opt/app/vendor/doctrine/dbal/lib/Doctrine/DBAL/Exception/TableNotFoundException.php opt/app/vendor/doctrine/dbal/lib/Doctrine/DBAL/Exception/UniqueConstraintViolationException.php +opt/app/vendor/doctrine/dbal/lib/Doctrine/DBAL/FetchMode.php opt/app/vendor/doctrine/dbal/lib/Doctrine/DBAL/Id/TableGenerator.php opt/app/vendor/doctrine/dbal/lib/Doctrine/DBAL/Id/TableGeneratorSchemaVisitor.php opt/app/vendor/doctrine/dbal/lib/Doctrine/DBAL/LockMode.php @@ -1899,16 +1941,20 @@ opt/app/vendor/doctrine/dbal/lib/Doctrine/DBAL/Logging/DebugStack.php opt/app/vendor/doctrine/dbal/lib/Doctrine/DBAL/Logging/EchoSQLLogger.php opt/app/vendor/doctrine/dbal/lib/Doctrine/DBAL/Logging/LoggerChain.php opt/app/vendor/doctrine/dbal/lib/Doctrine/DBAL/Logging/SQLLogger.php +opt/app/vendor/doctrine/dbal/lib/Doctrine/DBAL/ParameterType.php opt/app/vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/AbstractPlatform.php opt/app/vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/DB2Platform.php +opt/app/vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/DateIntervalUnit.php opt/app/vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/DrizzlePlatform.php opt/app/vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/Keywords/DB2Keywords.php opt/app/vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/Keywords/DrizzleKeywords.php opt/app/vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/Keywords/KeywordList.php +opt/app/vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/Keywords/MariaDb102Keywords.php opt/app/vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/Keywords/MsSQLKeywords.php opt/app/vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/Keywords/MySQL57Keywords.php opt/app/vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/Keywords/MySQLKeywords.php opt/app/vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/Keywords/OracleKeywords.php +opt/app/vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/Keywords/PostgreSQL100Keywords.php opt/app/vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/Keywords/PostgreSQL91Keywords.php opt/app/vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/Keywords/PostgreSQL92Keywords.php opt/app/vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/Keywords/PostgreSQL94Keywords.php @@ -1923,9 +1969,11 @@ opt/app/vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/Keywords/SQLServer2008K opt/app/vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/Keywords/SQLServer2012Keywords.php opt/app/vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/Keywords/SQLServerKeywords.php opt/app/vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/Keywords/SQLiteKeywords.php +opt/app/vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/MariaDb1027Platform.php opt/app/vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/MySQL57Platform.php opt/app/vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/MySqlPlatform.php opt/app/vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/OraclePlatform.php +opt/app/vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/PostgreSQL100Platform.php opt/app/vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/PostgreSQL91Platform.php opt/app/vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/PostgreSQL92Platform.php opt/app/vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/PostgreSQL94Platform.php @@ -1940,6 +1988,7 @@ opt/app/vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/SQLServer2008Platform.p opt/app/vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/SQLServer2012Platform.php opt/app/vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/SQLServerPlatform.php opt/app/vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/SqlitePlatform.php +opt/app/vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/TrimMode.php opt/app/vendor/doctrine/dbal/lib/Doctrine/DBAL/Portability/Connection.php opt/app/vendor/doctrine/dbal/lib/Doctrine/DBAL/Portability/Statement.php opt/app/vendor/doctrine/dbal/lib/Doctrine/DBAL/Query/Expression/CompositeExpression.php @@ -2000,6 +2049,7 @@ opt/app/vendor/doctrine/dbal/lib/Doctrine/DBAL/Tools/Console/Command/ReservedWor opt/app/vendor/doctrine/dbal/lib/Doctrine/DBAL/Tools/Console/Command/RunSqlCommand.php opt/app/vendor/doctrine/dbal/lib/Doctrine/DBAL/Tools/Console/ConsoleRunner.php opt/app/vendor/doctrine/dbal/lib/Doctrine/DBAL/Tools/Console/Helper/ConnectionHelper.php +opt/app/vendor/doctrine/dbal/lib/Doctrine/DBAL/TransactionIsolationLevel.php opt/app/vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/ArrayType.php opt/app/vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/BigIntType.php opt/app/vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/BinaryType.php @@ -2020,6 +2070,8 @@ opt/app/vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/IntegerType.php opt/app/vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/JsonArrayType.php opt/app/vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/JsonType.php opt/app/vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/ObjectType.php +opt/app/vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/PhpDateTimeMappingType.php +opt/app/vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/PhpIntegerMappingType.php opt/app/vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/SimpleArrayType.php opt/app/vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/SmallIntType.php opt/app/vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/StringType.php @@ -2039,6 +2091,28 @@ opt/app/vendor/doctrine/lexer/LICENSE opt/app/vendor/doctrine/lexer/README.md opt/app/vendor/doctrine/lexer/composer.json opt/app/vendor/doctrine/lexer/lib/Doctrine/Common/Lexer/AbstractLexer.php +opt/app/vendor/dragonmantank/cron-expression/.editorconfig +opt/app/vendor/dragonmantank/cron-expression/CHANGELOG.md +opt/app/vendor/dragonmantank/cron-expression/LICENSE +opt/app/vendor/dragonmantank/cron-expression/README.md +opt/app/vendor/dragonmantank/cron-expression/composer.json +opt/app/vendor/dragonmantank/cron-expression/src/Cron/AbstractField.php +opt/app/vendor/dragonmantank/cron-expression/src/Cron/CronExpression.php +opt/app/vendor/dragonmantank/cron-expression/src/Cron/DayOfMonthField.php +opt/app/vendor/dragonmantank/cron-expression/src/Cron/DayOfWeekField.php +opt/app/vendor/dragonmantank/cron-expression/src/Cron/FieldFactory.php +opt/app/vendor/dragonmantank/cron-expression/src/Cron/FieldInterface.php +opt/app/vendor/dragonmantank/cron-expression/src/Cron/HoursField.php +opt/app/vendor/dragonmantank/cron-expression/src/Cron/MinutesField.php +opt/app/vendor/dragonmantank/cron-expression/src/Cron/MonthField.php +opt/app/vendor/dragonmantank/cron-expression/tests/Cron/AbstractFieldTest.php +opt/app/vendor/dragonmantank/cron-expression/tests/Cron/CronExpressionTest.php +opt/app/vendor/dragonmantank/cron-expression/tests/Cron/DayOfMonthFieldTest.php +opt/app/vendor/dragonmantank/cron-expression/tests/Cron/DayOfWeekFieldTest.php +opt/app/vendor/dragonmantank/cron-expression/tests/Cron/FieldFactoryTest.php +opt/app/vendor/dragonmantank/cron-expression/tests/Cron/HoursFieldTest.php +opt/app/vendor/dragonmantank/cron-expression/tests/Cron/MinutesFieldTest.php +opt/app/vendor/dragonmantank/cron-expression/tests/Cron/MonthFieldTest.php opt/app/vendor/egulias/email-validator/EmailValidator/EmailLexer.php opt/app/vendor/egulias/email-validator/EmailValidator/EmailParser.php opt/app/vendor/egulias/email-validator/EmailValidator/EmailValidator.php @@ -2323,15 +2397,17 @@ opt/app/vendor/laravel/framework/src/Illuminate/Console/Events/CommandStarting.p opt/app/vendor/laravel/framework/src/Illuminate/Console/GeneratorCommand.php opt/app/vendor/laravel/framework/src/Illuminate/Console/OutputStyle.php opt/app/vendor/laravel/framework/src/Illuminate/Console/Parser.php -opt/app/vendor/laravel/framework/src/Illuminate/Console/Scheduling/CacheMutex.php +opt/app/vendor/laravel/framework/src/Illuminate/Console/Scheduling/CacheEventMutex.php +opt/app/vendor/laravel/framework/src/Illuminate/Console/Scheduling/CacheSchedulingMutex.php opt/app/vendor/laravel/framework/src/Illuminate/Console/Scheduling/CallbackEvent.php opt/app/vendor/laravel/framework/src/Illuminate/Console/Scheduling/CommandBuilder.php opt/app/vendor/laravel/framework/src/Illuminate/Console/Scheduling/Event.php +opt/app/vendor/laravel/framework/src/Illuminate/Console/Scheduling/EventMutex.php opt/app/vendor/laravel/framework/src/Illuminate/Console/Scheduling/ManagesFrequencies.php -opt/app/vendor/laravel/framework/src/Illuminate/Console/Scheduling/Mutex.php opt/app/vendor/laravel/framework/src/Illuminate/Console/Scheduling/Schedule.php opt/app/vendor/laravel/framework/src/Illuminate/Console/Scheduling/ScheduleFinishCommand.php opt/app/vendor/laravel/framework/src/Illuminate/Console/Scheduling/ScheduleRunCommand.php +opt/app/vendor/laravel/framework/src/Illuminate/Console/Scheduling/SchedulingMutex.php opt/app/vendor/laravel/framework/src/Illuminate/Console/composer.json opt/app/vendor/laravel/framework/src/Illuminate/Container/BoundMethod.php opt/app/vendor/laravel/framework/src/Illuminate/Container/Container.php @@ -2382,7 +2458,6 @@ opt/app/vendor/laravel/framework/src/Illuminate/Contracts/Filesystem/Filesystem. opt/app/vendor/laravel/framework/src/Illuminate/Contracts/Foundation/Application.php opt/app/vendor/laravel/framework/src/Illuminate/Contracts/Hashing/Hasher.php opt/app/vendor/laravel/framework/src/Illuminate/Contracts/Http/Kernel.php -opt/app/vendor/laravel/framework/src/Illuminate/Contracts/Logging/Log.php opt/app/vendor/laravel/framework/src/Illuminate/Contracts/Mail/MailQueue.php opt/app/vendor/laravel/framework/src/Illuminate/Contracts/Mail/Mailable.php opt/app/vendor/laravel/framework/src/Illuminate/Contracts/Mail/Mailer.php @@ -2589,6 +2664,7 @@ opt/app/vendor/laravel/framework/src/Illuminate/Foundation/Bus/PendingChain.php opt/app/vendor/laravel/framework/src/Illuminate/Foundation/Bus/PendingDispatch.php opt/app/vendor/laravel/framework/src/Illuminate/Foundation/ComposerScripts.php opt/app/vendor/laravel/framework/src/Illuminate/Foundation/Console/AppNameCommand.php +opt/app/vendor/laravel/framework/src/Illuminate/Foundation/Console/ChannelMakeCommand.php opt/app/vendor/laravel/framework/src/Illuminate/Foundation/Console/ClearCompiledCommand.php opt/app/vendor/laravel/framework/src/Illuminate/Foundation/Console/ClosureCommand.php opt/app/vendor/laravel/framework/src/Illuminate/Foundation/Console/ConfigCacheCommand.php @@ -2606,7 +2682,6 @@ opt/app/vendor/laravel/framework/src/Illuminate/Foundation/Console/ListenerMakeC opt/app/vendor/laravel/framework/src/Illuminate/Foundation/Console/MailMakeCommand.php opt/app/vendor/laravel/framework/src/Illuminate/Foundation/Console/ModelMakeCommand.php opt/app/vendor/laravel/framework/src/Illuminate/Foundation/Console/NotificationMakeCommand.php -opt/app/vendor/laravel/framework/src/Illuminate/Foundation/Console/OptimizeCommand.php opt/app/vendor/laravel/framework/src/Illuminate/Foundation/Console/PackageDiscoverCommand.php opt/app/vendor/laravel/framework/src/Illuminate/Foundation/Console/PolicyMakeCommand.php opt/app/vendor/laravel/framework/src/Illuminate/Foundation/Console/PresetCommand.php @@ -2635,7 +2710,9 @@ opt/app/vendor/laravel/framework/src/Illuminate/Foundation/Console/StorageLinkCo opt/app/vendor/laravel/framework/src/Illuminate/Foundation/Console/TestMakeCommand.php opt/app/vendor/laravel/framework/src/Illuminate/Foundation/Console/UpCommand.php opt/app/vendor/laravel/framework/src/Illuminate/Foundation/Console/VendorPublishCommand.php +opt/app/vendor/laravel/framework/src/Illuminate/Foundation/Console/ViewCacheCommand.php opt/app/vendor/laravel/framework/src/Illuminate/Foundation/Console/ViewClearCommand.php +opt/app/vendor/laravel/framework/src/Illuminate/Foundation/Console/stubs/channel.stub opt/app/vendor/laravel/framework/src/Illuminate/Foundation/Console/stubs/console.stub opt/app/vendor/laravel/framework/src/Illuminate/Foundation/Console/stubs/event-handler-queued.stub opt/app/vendor/laravel/framework/src/Illuminate/Foundation/Console/stubs/event-handler.stub @@ -2671,6 +2748,7 @@ opt/app/vendor/laravel/framework/src/Illuminate/Foundation/EnvironmentDetector.p opt/app/vendor/laravel/framework/src/Illuminate/Foundation/Events/Dispatchable.php opt/app/vendor/laravel/framework/src/Illuminate/Foundation/Events/LocaleUpdated.php opt/app/vendor/laravel/framework/src/Illuminate/Foundation/Exceptions/Handler.php +opt/app/vendor/laravel/framework/src/Illuminate/Foundation/Exceptions/WhoopsHandler.php opt/app/vendor/laravel/framework/src/Illuminate/Foundation/Exceptions/views/404.blade.php opt/app/vendor/laravel/framework/src/Illuminate/Foundation/Exceptions/views/419.blade.php opt/app/vendor/laravel/framework/src/Illuminate/Foundation/Exceptions/views/429.blade.php @@ -2708,6 +2786,7 @@ opt/app/vendor/laravel/framework/src/Illuminate/Foundation/Testing/Concerns/Inte opt/app/vendor/laravel/framework/src/Illuminate/Foundation/Testing/Concerns/MakesHttpRequests.php opt/app/vendor/laravel/framework/src/Illuminate/Foundation/Testing/Concerns/MocksApplicationServices.php opt/app/vendor/laravel/framework/src/Illuminate/Foundation/Testing/Constraints/HasInDatabase.php +opt/app/vendor/laravel/framework/src/Illuminate/Foundation/Testing/Constraints/SeeInOrder.php opt/app/vendor/laravel/framework/src/Illuminate/Foundation/Testing/Constraints/SoftDeletedInDatabase.php opt/app/vendor/laravel/framework/src/Illuminate/Foundation/Testing/DatabaseMigrations.php opt/app/vendor/laravel/framework/src/Illuminate/Foundation/Testing/DatabaseTransactions.php @@ -2722,7 +2801,9 @@ opt/app/vendor/laravel/framework/src/Illuminate/Foundation/Testing/WithoutMiddle opt/app/vendor/laravel/framework/src/Illuminate/Foundation/Validation/ValidatesRequests.php opt/app/vendor/laravel/framework/src/Illuminate/Foundation/helpers.php opt/app/vendor/laravel/framework/src/Illuminate/Foundation/stubs/facade.stub +opt/app/vendor/laravel/framework/src/Illuminate/Hashing/ArgonHasher.php opt/app/vendor/laravel/framework/src/Illuminate/Hashing/BcryptHasher.php +opt/app/vendor/laravel/framework/src/Illuminate/Hashing/HashManager.php opt/app/vendor/laravel/framework/src/Illuminate/Hashing/HashServiceProvider.php opt/app/vendor/laravel/framework/src/Illuminate/Hashing/composer.json opt/app/vendor/laravel/framework/src/Illuminate/Http/Concerns/InteractsWithContentTypes.php @@ -2730,17 +2811,20 @@ opt/app/vendor/laravel/framework/src/Illuminate/Http/Concerns/InteractsWithFlash opt/app/vendor/laravel/framework/src/Illuminate/Http/Concerns/InteractsWithInput.php opt/app/vendor/laravel/framework/src/Illuminate/Http/Exceptions/HttpResponseException.php opt/app/vendor/laravel/framework/src/Illuminate/Http/Exceptions/PostTooLargeException.php +opt/app/vendor/laravel/framework/src/Illuminate/Http/Exceptions/ThrottleRequestsException.php opt/app/vendor/laravel/framework/src/Illuminate/Http/File.php opt/app/vendor/laravel/framework/src/Illuminate/Http/FileHelpers.php opt/app/vendor/laravel/framework/src/Illuminate/Http/JsonResponse.php opt/app/vendor/laravel/framework/src/Illuminate/Http/Middleware/CheckResponseForModifications.php opt/app/vendor/laravel/framework/src/Illuminate/Http/Middleware/FrameGuard.php +opt/app/vendor/laravel/framework/src/Illuminate/Http/Middleware/SetCacheHeaders.php opt/app/vendor/laravel/framework/src/Illuminate/Http/RedirectResponse.php opt/app/vendor/laravel/framework/src/Illuminate/Http/Request.php opt/app/vendor/laravel/framework/src/Illuminate/Http/Resources/CollectsResources.php opt/app/vendor/laravel/framework/src/Illuminate/Http/Resources/ConditionallyLoadsAttributes.php opt/app/vendor/laravel/framework/src/Illuminate/Http/Resources/DelegatesToResource.php opt/app/vendor/laravel/framework/src/Illuminate/Http/Resources/Json/AnonymousResourceCollection.php +opt/app/vendor/laravel/framework/src/Illuminate/Http/Resources/Json/JsonResource.php opt/app/vendor/laravel/framework/src/Illuminate/Http/Resources/Json/PaginatedResourceResponse.php opt/app/vendor/laravel/framework/src/Illuminate/Http/Resources/Json/Resource.php opt/app/vendor/laravel/framework/src/Illuminate/Http/Resources/Json/ResourceCollection.php @@ -2756,8 +2840,9 @@ opt/app/vendor/laravel/framework/src/Illuminate/Http/Testing/MimeType.php opt/app/vendor/laravel/framework/src/Illuminate/Http/UploadedFile.php opt/app/vendor/laravel/framework/src/Illuminate/Http/composer.json opt/app/vendor/laravel/framework/src/Illuminate/Log/Events/MessageLogged.php +opt/app/vendor/laravel/framework/src/Illuminate/Log/LogManager.php opt/app/vendor/laravel/framework/src/Illuminate/Log/LogServiceProvider.php -opt/app/vendor/laravel/framework/src/Illuminate/Log/Writer.php +opt/app/vendor/laravel/framework/src/Illuminate/Log/Logger.php opt/app/vendor/laravel/framework/src/Illuminate/Log/composer.json opt/app/vendor/laravel/framework/src/Illuminate/Mail/Events/MessageSending.php opt/app/vendor/laravel/framework/src/Illuminate/Mail/Events/MessageSent.php @@ -2922,7 +3007,10 @@ opt/app/vendor/laravel/framework/src/Illuminate/Redis/RedisServiceProvider.php opt/app/vendor/laravel/framework/src/Illuminate/Redis/composer.json opt/app/vendor/laravel/framework/src/Illuminate/Routing/Console/ControllerMakeCommand.php opt/app/vendor/laravel/framework/src/Illuminate/Routing/Console/MiddlewareMakeCommand.php +opt/app/vendor/laravel/framework/src/Illuminate/Routing/Console/stubs/controller.api.stub +opt/app/vendor/laravel/framework/src/Illuminate/Routing/Console/stubs/controller.model.api.stub opt/app/vendor/laravel/framework/src/Illuminate/Routing/Console/stubs/controller.model.stub +opt/app/vendor/laravel/framework/src/Illuminate/Routing/Console/stubs/controller.nested.api.stub opt/app/vendor/laravel/framework/src/Illuminate/Routing/Console/stubs/controller.nested.stub opt/app/vendor/laravel/framework/src/Illuminate/Routing/Console/stubs/controller.plain.stub opt/app/vendor/laravel/framework/src/Illuminate/Routing/Console/stubs/controller.stub @@ -2932,6 +3020,7 @@ opt/app/vendor/laravel/framework/src/Illuminate/Routing/Controller.php opt/app/vendor/laravel/framework/src/Illuminate/Routing/ControllerDispatcher.php opt/app/vendor/laravel/framework/src/Illuminate/Routing/ControllerMiddlewareOptions.php opt/app/vendor/laravel/framework/src/Illuminate/Routing/Events/RouteMatched.php +opt/app/vendor/laravel/framework/src/Illuminate/Routing/Exceptions/InvalidSignatureException.php opt/app/vendor/laravel/framework/src/Illuminate/Routing/Exceptions/UrlGenerationException.php opt/app/vendor/laravel/framework/src/Illuminate/Routing/ImplicitRouteBinding.php opt/app/vendor/laravel/framework/src/Illuminate/Routing/Matching/HostValidator.php @@ -2942,6 +3031,7 @@ opt/app/vendor/laravel/framework/src/Illuminate/Routing/Matching/ValidatorInterf opt/app/vendor/laravel/framework/src/Illuminate/Routing/Middleware/SubstituteBindings.php opt/app/vendor/laravel/framework/src/Illuminate/Routing/Middleware/ThrottleRequests.php opt/app/vendor/laravel/framework/src/Illuminate/Routing/Middleware/ThrottleRequestsWithRedis.php +opt/app/vendor/laravel/framework/src/Illuminate/Routing/Middleware/ValidateSignature.php opt/app/vendor/laravel/framework/src/Illuminate/Routing/MiddlewareNameResolver.php opt/app/vendor/laravel/framework/src/Illuminate/Routing/PendingResourceRegistration.php opt/app/vendor/laravel/framework/src/Illuminate/Routing/Pipeline.php @@ -3043,6 +3133,7 @@ opt/app/vendor/laravel/framework/src/Illuminate/Support/Testing/Fakes/Notificati opt/app/vendor/laravel/framework/src/Illuminate/Support/Testing/Fakes/PendingMailFake.php opt/app/vendor/laravel/framework/src/Illuminate/Support/Testing/Fakes/QueueFake.php opt/app/vendor/laravel/framework/src/Illuminate/Support/Traits/CapsuleManagerTrait.php +opt/app/vendor/laravel/framework/src/Illuminate/Support/Traits/Localizable.php opt/app/vendor/laravel/framework/src/Illuminate/Support/Traits/Macroable.php opt/app/vendor/laravel/framework/src/Illuminate/Support/ViewErrorBag.php opt/app/vendor/laravel/framework/src/Illuminate/Support/composer.json @@ -3083,6 +3174,7 @@ opt/app/vendor/laravel/framework/src/Illuminate/View/Compilers/Concerns/Compiles opt/app/vendor/laravel/framework/src/Illuminate/View/Compilers/Concerns/CompilesComponents.php opt/app/vendor/laravel/framework/src/Illuminate/View/Compilers/Concerns/CompilesConditionals.php opt/app/vendor/laravel/framework/src/Illuminate/View/Compilers/Concerns/CompilesEchos.php +opt/app/vendor/laravel/framework/src/Illuminate/View/Compilers/Concerns/CompilesHelpers.php opt/app/vendor/laravel/framework/src/Illuminate/View/Compilers/Concerns/CompilesIncludes.php opt/app/vendor/laravel/framework/src/Illuminate/View/Compilers/Concerns/CompilesInjections.php opt/app/vendor/laravel/framework/src/Illuminate/View/Compilers/Concerns/CompilesJson.php @@ -3265,7 +3357,7 @@ opt/app/vendor/lcobucci/jwt/test/unit/TokenTest.php opt/app/vendor/lcobucci/jwt/test/unit/ValidationDataTest.php opt/app/vendor/league/commonmark/.styleci.yml opt/app/vendor/league/commonmark/CHANGELOG.md -opt/app/vendor/league/commonmark/CONDUCT.md +opt/app/vendor/league/commonmark/CODE_OF_CONDUCT.md opt/app/vendor/league/commonmark/CONTRIBUTING.md opt/app/vendor/league/commonmark/LICENSE opt/app/vendor/league/commonmark/README.md @@ -3378,6 +3470,7 @@ opt/app/vendor/league/commonmark/src/Util/LinkParserHelper.php opt/app/vendor/league/commonmark/src/Util/RegexHelper.php opt/app/vendor/league/commonmark/src/Util/UrlEncoder.php opt/app/vendor/league/commonmark/src/Util/Xml.php +opt/app/vendor/league/csv/CHANGELOG.md opt/app/vendor/league/csv/LICENSE opt/app/vendor/league/csv/autoload.php opt/app/vendor/league/csv/composer.json @@ -3721,32 +3814,9 @@ opt/app/vendor/monolog/monolog/tests/Monolog/Processor/WebProcessorTest.php opt/app/vendor/monolog/monolog/tests/Monolog/PsrLogCompatTest.php opt/app/vendor/monolog/monolog/tests/Monolog/RegistryTest.php opt/app/vendor/monolog/monolog/tests/Monolog/TestCase.php -opt/app/vendor/mtdowling/cron-expression/.editorconfig -opt/app/vendor/mtdowling/cron-expression/CHANGELOG.md -opt/app/vendor/mtdowling/cron-expression/LICENSE -opt/app/vendor/mtdowling/cron-expression/README.md -opt/app/vendor/mtdowling/cron-expression/composer.json -opt/app/vendor/mtdowling/cron-expression/src/Cron/AbstractField.php -opt/app/vendor/mtdowling/cron-expression/src/Cron/CronExpression.php -opt/app/vendor/mtdowling/cron-expression/src/Cron/DayOfMonthField.php -opt/app/vendor/mtdowling/cron-expression/src/Cron/DayOfWeekField.php -opt/app/vendor/mtdowling/cron-expression/src/Cron/FieldFactory.php -opt/app/vendor/mtdowling/cron-expression/src/Cron/FieldInterface.php -opt/app/vendor/mtdowling/cron-expression/src/Cron/HoursField.php -opt/app/vendor/mtdowling/cron-expression/src/Cron/MinutesField.php -opt/app/vendor/mtdowling/cron-expression/src/Cron/MonthField.php -opt/app/vendor/mtdowling/cron-expression/src/Cron/YearField.php -opt/app/vendor/mtdowling/cron-expression/tests/Cron/AbstractFieldTest.php -opt/app/vendor/mtdowling/cron-expression/tests/Cron/CronExpressionTest.php -opt/app/vendor/mtdowling/cron-expression/tests/Cron/DayOfMonthFieldTest.php -opt/app/vendor/mtdowling/cron-expression/tests/Cron/DayOfWeekFieldTest.php -opt/app/vendor/mtdowling/cron-expression/tests/Cron/FieldFactoryTest.php -opt/app/vendor/mtdowling/cron-expression/tests/Cron/HoursFieldTest.php -opt/app/vendor/mtdowling/cron-expression/tests/Cron/MinutesFieldTest.php -opt/app/vendor/mtdowling/cron-expression/tests/Cron/MonthFieldTest.php -opt/app/vendor/mtdowling/cron-expression/tests/Cron/YearFieldTest.php opt/app/vendor/nesbot/carbon/.php_cs.dist opt/app/vendor/nesbot/carbon/LICENSE +opt/app/vendor/nesbot/carbon/build.php opt/app/vendor/nesbot/carbon/composer.json opt/app/vendor/nesbot/carbon/readme.md opt/app/vendor/nesbot/carbon/src/Carbon/Carbon.php @@ -3774,6 +3844,7 @@ opt/app/vendor/nesbot/carbon/src/Carbon/Lang/fi.php opt/app/vendor/nesbot/carbon/src/Carbon/Lang/fo.php opt/app/vendor/nesbot/carbon/src/Carbon/Lang/fr.php opt/app/vendor/nesbot/carbon/src/Carbon/Lang/gl.php +opt/app/vendor/nesbot/carbon/src/Carbon/Lang/gu.php opt/app/vendor/nesbot/carbon/src/Carbon/Lang/he.php opt/app/vendor/nesbot/carbon/src/Carbon/Lang/hr.php opt/app/vendor/nesbot/carbon/src/Carbon/Lang/hu.php @@ -3815,7 +3886,7 @@ opt/app/vendor/nesbot/carbon/src/Carbon/Lang/uz.php opt/app/vendor/nesbot/carbon/src/Carbon/Lang/vi.php opt/app/vendor/nesbot/carbon/src/Carbon/Lang/zh.php opt/app/vendor/nesbot/carbon/src/Carbon/Lang/zh_TW.php -opt/app/vendor/nesbot/carbon/trigger +opt/app/vendor/nesbot/carbon/src/Carbon/Translator.php opt/app/vendor/paragonie/constant_time_encoding/LICENSE.txt opt/app/vendor/paragonie/constant_time_encoding/README.md opt/app/vendor/paragonie/constant_time_encoding/composer.json @@ -3889,16 +3960,23 @@ opt/app/vendor/phpseclib/phpseclib/phpseclib/System/SSH/Agent.php opt/app/vendor/phpseclib/phpseclib/phpseclib/System/SSH/Agent/Identity.php opt/app/vendor/phpseclib/phpseclib/phpseclib/bootstrap.php opt/app/vendor/phpseclib/phpseclib/phpseclib/openssl.cnf +opt/app/vendor/pragmarx/google2fa-laravel/CHANGELOG.md opt/app/vendor/pragmarx/google2fa-laravel/LICENSE -opt/app/vendor/pragmarx/google2fa-laravel/changelog.md +opt/app/vendor/pragmarx/google2fa-laravel/README.md opt/app/vendor/pragmarx/google2fa-laravel/composer.json opt/app/vendor/pragmarx/google2fa-laravel/docs/middleware.jpg opt/app/vendor/pragmarx/google2fa-laravel/phpspec.yml -opt/app/vendor/pragmarx/google2fa-laravel/readme.md +opt/app/vendor/pragmarx/google2fa-laravel/src/Events/EmptyOneTimePasswordReceived.php +opt/app/vendor/pragmarx/google2fa-laravel/src/Events/LoggedOut.php +opt/app/vendor/pragmarx/google2fa-laravel/src/Events/LoginFailed.php +opt/app/vendor/pragmarx/google2fa-laravel/src/Events/LoginSucceeded.php +opt/app/vendor/pragmarx/google2fa-laravel/src/Events/OneTimePasswordExpired.php opt/app/vendor/pragmarx/google2fa-laravel/src/Events/OneTimePasswordRequested.php +opt/app/vendor/pragmarx/google2fa-laravel/src/Events/OneTimePasswordRequested53.php opt/app/vendor/pragmarx/google2fa-laravel/src/Exceptions/InvalidOneTimePassword.php opt/app/vendor/pragmarx/google2fa-laravel/src/Exceptions/InvalidSecretKey.php opt/app/vendor/pragmarx/google2fa-laravel/src/Facade.php +opt/app/vendor/pragmarx/google2fa-laravel/src/Google2FA.php opt/app/vendor/pragmarx/google2fa-laravel/src/Middleware.php opt/app/vendor/pragmarx/google2fa-laravel/src/ServiceProvider.php opt/app/vendor/pragmarx/google2fa-laravel/src/Support/Auth.php @@ -3911,14 +3989,21 @@ opt/app/vendor/pragmarx/google2fa-laravel/src/Support/Request.php opt/app/vendor/pragmarx/google2fa-laravel/src/Support/Response.php opt/app/vendor/pragmarx/google2fa-laravel/src/Support/Session.php opt/app/vendor/pragmarx/google2fa-laravel/src/config/config.php -opt/app/vendor/pragmarx/google2fa-laravel/tests/spec/Support/AuthenticatorSpec.php +opt/app/vendor/pragmarx/google2fa-laravel/tests/Google2FaLaravelTest.php +opt/app/vendor/pragmarx/google2fa-laravel/tests/Support/User.php +opt/app/vendor/pragmarx/google2fa-laravel/tests/TestCase.php +opt/app/vendor/pragmarx/google2fa-laravel/tests/bootstrap.php +opt/app/vendor/pragmarx/google2fa-laravel/tests/views/google2fa/index.blade.php opt/app/vendor/pragmarx/google2fa-laravel/upgrading.md -opt/app/vendor/pragmarx/google2fa/LICENSE +opt/app/vendor/pragmarx/google2fa/LICENSE.md opt/app/vendor/pragmarx/google2fa/README.md +opt/app/vendor/pragmarx/google2fa/RELICENSED.md opt/app/vendor/pragmarx/google2fa/changelog.md opt/app/vendor/pragmarx/google2fa/composer.json +opt/app/vendor/pragmarx/google2fa/composer.lock opt/app/vendor/pragmarx/google2fa/docs/playground.jpg opt/app/vendor/pragmarx/google2fa/src/Exceptions/IncompatibleWithGoogleAuthenticatorException.php +opt/app/vendor/pragmarx/google2fa/src/Exceptions/InsecureCallException.php opt/app/vendor/pragmarx/google2fa/src/Exceptions/InvalidCharactersException.php opt/app/vendor/pragmarx/google2fa/src/Exceptions/SecretKeyTooShortException.php opt/app/vendor/pragmarx/google2fa/src/Google2FA.php @@ -4503,7 +4588,6 @@ opt/app/vendor/symfony/console/Descriptor/XmlDescriptor.php opt/app/vendor/symfony/console/Event/ConsoleCommandEvent.php opt/app/vendor/symfony/console/Event/ConsoleErrorEvent.php opt/app/vendor/symfony/console/Event/ConsoleEvent.php -opt/app/vendor/symfony/console/Event/ConsoleExceptionEvent.php opt/app/vendor/symfony/console/Event/ConsoleTerminateEvent.php opt/app/vendor/symfony/console/EventListener/ErrorListener.php opt/app/vendor/symfony/console/Exception/CommandNotFoundException.php @@ -4877,7 +4961,6 @@ opt/app/vendor/symfony/debug/Debug.php opt/app/vendor/symfony/debug/DebugClassLoader.php opt/app/vendor/symfony/debug/ErrorHandler.php opt/app/vendor/symfony/debug/Exception/ClassNotFoundException.php -opt/app/vendor/symfony/debug/Exception/ContextErrorException.php opt/app/vendor/symfony/debug/Exception/FatalErrorException.php opt/app/vendor/symfony/debug/Exception/FatalThrowableError.php opt/app/vendor/symfony/debug/Exception/FlattenException.php @@ -4892,15 +4975,6 @@ opt/app/vendor/symfony/debug/FatalErrorHandler/UndefinedFunctionFatalErrorHandle opt/app/vendor/symfony/debug/FatalErrorHandler/UndefinedMethodFatalErrorHandler.php opt/app/vendor/symfony/debug/LICENSE opt/app/vendor/symfony/debug/README.md -opt/app/vendor/symfony/debug/Resources/ext/README.md -opt/app/vendor/symfony/debug/Resources/ext/config.m4 -opt/app/vendor/symfony/debug/Resources/ext/config.w32 -opt/app/vendor/symfony/debug/Resources/ext/php_symfony_debug.h -opt/app/vendor/symfony/debug/Resources/ext/symfony_debug.c -opt/app/vendor/symfony/debug/Resources/ext/tests/001.phpt -opt/app/vendor/symfony/debug/Resources/ext/tests/002.phpt -opt/app/vendor/symfony/debug/Resources/ext/tests/002_1.phpt -opt/app/vendor/symfony/debug/Resources/ext/tests/003.phpt opt/app/vendor/symfony/debug/Tests/DebugClassLoaderTest.php opt/app/vendor/symfony/debug/Tests/ErrorHandlerTest.php opt/app/vendor/symfony/debug/Tests/Exception/FlattenExceptionTest.php @@ -4963,7 +5037,6 @@ opt/app/vendor/symfony/finder/Comparator/Comparator.php opt/app/vendor/symfony/finder/Comparator/DateComparator.php opt/app/vendor/symfony/finder/Comparator/NumberComparator.php opt/app/vendor/symfony/finder/Exception/AccessDeniedException.php -opt/app/vendor/symfony/finder/Exception/ExceptionInterface.php opt/app/vendor/symfony/finder/Finder.php opt/app/vendor/symfony/finder/Glob.php opt/app/vendor/symfony/finder/Iterator/CustomFilterIterator.php @@ -4973,7 +5046,6 @@ opt/app/vendor/symfony/finder/Iterator/ExcludeDirectoryFilterIterator.php opt/app/vendor/symfony/finder/Iterator/FileTypeFilterIterator.php opt/app/vendor/symfony/finder/Iterator/FilecontentFilterIterator.php opt/app/vendor/symfony/finder/Iterator/FilenameFilterIterator.php -opt/app/vendor/symfony/finder/Iterator/FilterIterator.php opt/app/vendor/symfony/finder/Iterator/MultiplePcreFilterIterator.php opt/app/vendor/symfony/finder/Iterator/PathFilterIterator.php opt/app/vendor/symfony/finder/Iterator/RecursiveDirectoryIterator.php @@ -5012,7 +5084,6 @@ opt/app/vendor/symfony/finder/Tests/Iterator/ExcludeDirectoryFilterIteratorTest. opt/app/vendor/symfony/finder/Tests/Iterator/FileTypeFilterIteratorTest.php opt/app/vendor/symfony/finder/Tests/Iterator/FilecontentFilterIteratorTest.php opt/app/vendor/symfony/finder/Tests/Iterator/FilenameFilterIteratorTest.php -opt/app/vendor/symfony/finder/Tests/Iterator/FilterIteratorTest.php opt/app/vendor/symfony/finder/Tests/Iterator/Iterator.php opt/app/vendor/symfony/finder/Tests/Iterator/IteratorTestCase.php opt/app/vendor/symfony/finder/Tests/Iterator/MockFileListIterator.php @@ -5076,22 +5147,18 @@ opt/app/vendor/symfony/http-foundation/Session/SessionBagInterface.php opt/app/vendor/symfony/http-foundation/Session/SessionBagProxy.php opt/app/vendor/symfony/http-foundation/Session/SessionInterface.php opt/app/vendor/symfony/http-foundation/Session/Storage/Handler/AbstractSessionHandler.php -opt/app/vendor/symfony/http-foundation/Session/Storage/Handler/MemcacheSessionHandler.php opt/app/vendor/symfony/http-foundation/Session/Storage/Handler/MemcachedSessionHandler.php opt/app/vendor/symfony/http-foundation/Session/Storage/Handler/MongoDbSessionHandler.php opt/app/vendor/symfony/http-foundation/Session/Storage/Handler/NativeFileSessionHandler.php -opt/app/vendor/symfony/http-foundation/Session/Storage/Handler/NativeSessionHandler.php opt/app/vendor/symfony/http-foundation/Session/Storage/Handler/NullSessionHandler.php opt/app/vendor/symfony/http-foundation/Session/Storage/Handler/PdoSessionHandler.php opt/app/vendor/symfony/http-foundation/Session/Storage/Handler/StrictSessionHandler.php -opt/app/vendor/symfony/http-foundation/Session/Storage/Handler/WriteCheckSessionHandler.php opt/app/vendor/symfony/http-foundation/Session/Storage/MetadataBag.php opt/app/vendor/symfony/http-foundation/Session/Storage/MockArraySessionStorage.php opt/app/vendor/symfony/http-foundation/Session/Storage/MockFileSessionStorage.php opt/app/vendor/symfony/http-foundation/Session/Storage/NativeSessionStorage.php opt/app/vendor/symfony/http-foundation/Session/Storage/PhpBridgeSessionStorage.php opt/app/vendor/symfony/http-foundation/Session/Storage/Proxy/AbstractProxy.php -opt/app/vendor/symfony/http-foundation/Session/Storage/Proxy/NativeProxy.php opt/app/vendor/symfony/http-foundation/Session/Storage/Proxy/SessionHandlerProxy.php opt/app/vendor/symfony/http-foundation/Session/Storage/SessionStorageInterface.php opt/app/vendor/symfony/http-foundation/StreamedResponse.php @@ -5142,22 +5209,18 @@ opt/app/vendor/symfony/http-foundation/Tests/Session/Storage/Handler/Fixtures/wi opt/app/vendor/symfony/http-foundation/Tests/Session/Storage/Handler/Fixtures/with_cookie.php opt/app/vendor/symfony/http-foundation/Tests/Session/Storage/Handler/Fixtures/with_cookie_and_session.expected opt/app/vendor/symfony/http-foundation/Tests/Session/Storage/Handler/Fixtures/with_cookie_and_session.php -opt/app/vendor/symfony/http-foundation/Tests/Session/Storage/Handler/MemcacheSessionHandlerTest.php opt/app/vendor/symfony/http-foundation/Tests/Session/Storage/Handler/MemcachedSessionHandlerTest.php opt/app/vendor/symfony/http-foundation/Tests/Session/Storage/Handler/MongoDbSessionHandlerTest.php opt/app/vendor/symfony/http-foundation/Tests/Session/Storage/Handler/NativeFileSessionHandlerTest.php -opt/app/vendor/symfony/http-foundation/Tests/Session/Storage/Handler/NativeSessionHandlerTest.php opt/app/vendor/symfony/http-foundation/Tests/Session/Storage/Handler/NullSessionHandlerTest.php opt/app/vendor/symfony/http-foundation/Tests/Session/Storage/Handler/PdoSessionHandlerTest.php opt/app/vendor/symfony/http-foundation/Tests/Session/Storage/Handler/StrictSessionHandlerTest.php -opt/app/vendor/symfony/http-foundation/Tests/Session/Storage/Handler/WriteCheckSessionHandlerTest.php opt/app/vendor/symfony/http-foundation/Tests/Session/Storage/MetadataBagTest.php opt/app/vendor/symfony/http-foundation/Tests/Session/Storage/MockArraySessionStorageTest.php opt/app/vendor/symfony/http-foundation/Tests/Session/Storage/MockFileSessionStorageTest.php opt/app/vendor/symfony/http-foundation/Tests/Session/Storage/NativeSessionStorageTest.php opt/app/vendor/symfony/http-foundation/Tests/Session/Storage/PhpBridgeSessionStorageTest.php opt/app/vendor/symfony/http-foundation/Tests/Session/Storage/Proxy/AbstractProxyTest.php -opt/app/vendor/symfony/http-foundation/Tests/Session/Storage/Proxy/NativeProxyTest.php opt/app/vendor/symfony/http-foundation/Tests/Session/Storage/Proxy/SessionHandlerProxyTest.php opt/app/vendor/symfony/http-foundation/Tests/StreamedResponseTest.php opt/app/vendor/symfony/http-foundation/Tests/schema/http-status-codes.rng @@ -5175,7 +5238,6 @@ opt/app/vendor/symfony/http-kernel/CacheWarmer/CacheWarmerAggregate.php opt/app/vendor/symfony/http-kernel/CacheWarmer/CacheWarmerInterface.php opt/app/vendor/symfony/http-kernel/CacheWarmer/WarmableInterface.php opt/app/vendor/symfony/http-kernel/Client.php -opt/app/vendor/symfony/http-kernel/Config/EnvParametersResource.php opt/app/vendor/symfony/http-kernel/Config/FileLocator.php opt/app/vendor/symfony/http-kernel/Controller/ArgumentResolver.php opt/app/vendor/symfony/http-kernel/Controller/ArgumentResolver/DefaultValueResolver.php @@ -5208,11 +5270,9 @@ opt/app/vendor/symfony/http-kernel/DataCollector/MemoryDataCollector.php opt/app/vendor/symfony/http-kernel/DataCollector/RequestDataCollector.php opt/app/vendor/symfony/http-kernel/DataCollector/RouterDataCollector.php opt/app/vendor/symfony/http-kernel/DataCollector/TimeDataCollector.php -opt/app/vendor/symfony/http-kernel/DataCollector/Util/ValueExporter.php opt/app/vendor/symfony/http-kernel/Debug/FileLinkFormatter.php opt/app/vendor/symfony/http-kernel/Debug/TraceableEventDispatcher.php opt/app/vendor/symfony/http-kernel/DependencyInjection/AddAnnotatedClassesToCachePass.php -opt/app/vendor/symfony/http-kernel/DependencyInjection/AddClassesToCachePass.php opt/app/vendor/symfony/http-kernel/DependencyInjection/ConfigurableExtension.php opt/app/vendor/symfony/http-kernel/DependencyInjection/ControllerArgumentValueResolverPass.php opt/app/vendor/symfony/http-kernel/DependencyInjection/Extension.php @@ -5307,7 +5367,6 @@ opt/app/vendor/symfony/http-kernel/Tests/CacheClearer/Psr6CacheClearerTest.php opt/app/vendor/symfony/http-kernel/Tests/CacheWarmer/CacheWarmerAggregateTest.php opt/app/vendor/symfony/http-kernel/Tests/CacheWarmer/CacheWarmerTest.php opt/app/vendor/symfony/http-kernel/Tests/ClientTest.php -opt/app/vendor/symfony/http-kernel/Tests/Config/EnvParametersResourceTest.php opt/app/vendor/symfony/http-kernel/Tests/Config/FileLocatorTest.php opt/app/vendor/symfony/http-kernel/Tests/Controller/ArgumentResolver/ServiceValueResolverTest.php opt/app/vendor/symfony/http-kernel/Tests/Controller/ArgumentResolverTest.php @@ -5324,7 +5383,6 @@ opt/app/vendor/symfony/http-kernel/Tests/DataCollector/LoggerDataCollectorTest.p opt/app/vendor/symfony/http-kernel/Tests/DataCollector/MemoryDataCollectorTest.php opt/app/vendor/symfony/http-kernel/Tests/DataCollector/RequestDataCollectorTest.php opt/app/vendor/symfony/http-kernel/Tests/DataCollector/TimeDataCollectorTest.php -opt/app/vendor/symfony/http-kernel/Tests/DataCollector/Util/ValueExporterTest.php opt/app/vendor/symfony/http-kernel/Tests/Debug/FileLinkFormatterTest.php opt/app/vendor/symfony/http-kernel/Tests/Debug/TraceableEventDispatcherTest.php opt/app/vendor/symfony/http-kernel/Tests/DependencyInjection/AddAnnotatedClassesToCachePassTest.php @@ -5442,18 +5500,11 @@ opt/app/vendor/symfony/polyfill-php56/Php56.php opt/app/vendor/symfony/polyfill-php56/README.md opt/app/vendor/symfony/polyfill-php56/bootstrap.php opt/app/vendor/symfony/polyfill-php56/composer.json -opt/app/vendor/symfony/polyfill-php70/LICENSE -opt/app/vendor/symfony/polyfill-php70/Php70.php -opt/app/vendor/symfony/polyfill-php70/README.md -opt/app/vendor/symfony/polyfill-php70/Resources/stubs/ArithmeticError.php -opt/app/vendor/symfony/polyfill-php70/Resources/stubs/AssertionError.php -opt/app/vendor/symfony/polyfill-php70/Resources/stubs/DivisionByZeroError.php -opt/app/vendor/symfony/polyfill-php70/Resources/stubs/Error.php -opt/app/vendor/symfony/polyfill-php70/Resources/stubs/ParseError.php -opt/app/vendor/symfony/polyfill-php70/Resources/stubs/SessionUpdateTimestampHandlerInterface.php -opt/app/vendor/symfony/polyfill-php70/Resources/stubs/TypeError.php -opt/app/vendor/symfony/polyfill-php70/bootstrap.php -opt/app/vendor/symfony/polyfill-php70/composer.json +opt/app/vendor/symfony/polyfill-php72/LICENSE +opt/app/vendor/symfony/polyfill-php72/Php72.php +opt/app/vendor/symfony/polyfill-php72/README.md +opt/app/vendor/symfony/polyfill-php72/bootstrap.php +opt/app/vendor/symfony/polyfill-php72/composer.json opt/app/vendor/symfony/polyfill-util/Binary.php opt/app/vendor/symfony/polyfill-util/BinaryNoFuncOverload.php opt/app/vendor/symfony/polyfill-util/BinaryOnFuncOverload.php @@ -5480,7 +5531,6 @@ opt/app/vendor/symfony/process/Pipes/PipesInterface.php opt/app/vendor/symfony/process/Pipes/UnixPipes.php opt/app/vendor/symfony/process/Pipes/WindowsPipes.php opt/app/vendor/symfony/process/Process.php -opt/app/vendor/symfony/process/ProcessBuilder.php opt/app/vendor/symfony/process/ProcessUtils.php opt/app/vendor/symfony/process/README.md opt/app/vendor/symfony/process/Tests/ExecutableFinderTest.php @@ -5488,10 +5538,8 @@ opt/app/vendor/symfony/process/Tests/NonStopableProcess.php opt/app/vendor/symfony/process/Tests/PhpExecutableFinderTest.php opt/app/vendor/symfony/process/Tests/PhpProcessTest.php opt/app/vendor/symfony/process/Tests/PipeStdinInStdoutStdErrStreamSelect.php -opt/app/vendor/symfony/process/Tests/ProcessBuilderTest.php opt/app/vendor/symfony/process/Tests/ProcessFailedExceptionTest.php opt/app/vendor/symfony/process/Tests/ProcessTest.php -opt/app/vendor/symfony/process/Tests/ProcessUtilsTest.php opt/app/vendor/symfony/process/Tests/SignalListener.php opt/app/vendor/symfony/process/composer.json opt/app/vendor/symfony/process/phpunit.xml.dist @@ -5614,6 +5662,17 @@ opt/app/vendor/symfony/routing/Tests/Fixtures/empty.yml opt/app/vendor/symfony/routing/Tests/Fixtures/file_resource.yml opt/app/vendor/symfony/routing/Tests/Fixtures/foo.xml opt/app/vendor/symfony/routing/Tests/Fixtures/foo1.xml +opt/app/vendor/symfony/routing/Tests/Fixtures/glob/bar.xml +opt/app/vendor/symfony/routing/Tests/Fixtures/glob/bar.yml +opt/app/vendor/symfony/routing/Tests/Fixtures/glob/baz.xml +opt/app/vendor/symfony/routing/Tests/Fixtures/glob/baz.yml +opt/app/vendor/symfony/routing/Tests/Fixtures/glob/import_multiple.xml +opt/app/vendor/symfony/routing/Tests/Fixtures/glob/import_multiple.yml +opt/app/vendor/symfony/routing/Tests/Fixtures/glob/import_single.xml +opt/app/vendor/symfony/routing/Tests/Fixtures/glob/import_single.yml +opt/app/vendor/symfony/routing/Tests/Fixtures/glob/php_dsl.php +opt/app/vendor/symfony/routing/Tests/Fixtures/glob/php_dsl_bar.php +opt/app/vendor/symfony/routing/Tests/Fixtures/glob/php_dsl_baz.php opt/app/vendor/symfony/routing/Tests/Fixtures/incomplete.yml opt/app/vendor/symfony/routing/Tests/Fixtures/list_defaults.xml opt/app/vendor/symfony/routing/Tests/Fixtures/list_in_list_defaults.xml @@ -5863,7 +5922,6 @@ opt/app/vendor/symfony/var-dumper/Caster/EnumStub.php opt/app/vendor/symfony/var-dumper/Caster/ExceptionCaster.php opt/app/vendor/symfony/var-dumper/Caster/FrameStub.php opt/app/vendor/symfony/var-dumper/Caster/LinkStub.php -opt/app/vendor/symfony/var-dumper/Caster/MongoCaster.php opt/app/vendor/symfony/var-dumper/Caster/PdoCaster.php opt/app/vendor/symfony/var-dumper/Caster/PgSqlCaster.php opt/app/vendor/symfony/var-dumper/Caster/RedisCaster.php @@ -6538,6 +6596,7 @@ opt/app/vendor/twig/twig/test/Twig/Tests/Fixtures/macros/simple.test opt/app/vendor/twig/twig/test/Twig/Tests/Fixtures/macros/varargs.test opt/app/vendor/twig/twig/test/Twig/Tests/Fixtures/macros/varargs_argument.test opt/app/vendor/twig/twig/test/Twig/Tests/Fixtures/macros/with_filters.test +opt/app/vendor/twig/twig/test/Twig/Tests/Fixtures/regression/block_names_unicity.test opt/app/vendor/twig/twig/test/Twig/Tests/Fixtures/regression/combined_debug_info.test opt/app/vendor/twig/twig/test/Twig/Tests/Fixtures/regression/empty_token.test opt/app/vendor/twig/twig/test/Twig/Tests/Fixtures/regression/issue_1143.test @@ -6776,16 +6835,6 @@ opt/app/vendor/vlucas/phpdotenv/src/Exception/InvalidPathException.php opt/app/vendor/vlucas/phpdotenv/src/Exception/ValidationException.php opt/app/vendor/vlucas/phpdotenv/src/Loader.php opt/app/vendor/vlucas/phpdotenv/src/Validator.php -opt/app/vendor/watson/validating/LICENSE.txt -opt/app/vendor/watson/validating/README.md -opt/app/vendor/watson/validating/composer.json -opt/app/vendor/watson/validating/src/Injectors/UniqueInjector.php -opt/app/vendor/watson/validating/src/Injectors/UniqueWithInjector.php -opt/app/vendor/watson/validating/src/ValidatingInterface.php -opt/app/vendor/watson/validating/src/ValidatingModel.php -opt/app/vendor/watson/validating/src/ValidatingObserver.php -opt/app/vendor/watson/validating/src/ValidatingTrait.php -opt/app/vendor/watson/validating/src/ValidationException.php opt/app/vendor/zendframework/zend-diactoros/.coveralls.yml opt/app/vendor/zendframework/zend-diactoros/CHANGELOG.md opt/app/vendor/zendframework/zend-diactoros/CONDUCT.md diff --git a/.sandstorm/sandstorm-pkgdef.capnp b/.sandstorm/sandstorm-pkgdef.capnp index a08db02187..f2366ef0e2 100644 --- a/.sandstorm/sandstorm-pkgdef.capnp +++ b/.sandstorm/sandstorm-pkgdef.capnp @@ -16,7 +16,7 @@ const pkgdef :Spk.PackageDefinition = ( manifest = ( appTitle = (defaultText = "Firefly III"), appVersion = 10, - appMarketingVersion = (defaultText = "4.7.2"), + appMarketingVersion = (defaultText = "4.7.2.2"), actions = [ # Define your "new document" handlers here. From 6583d0f69bf1d684b629593ef0b996b9fbfbe451 Mon Sep 17 00:00:00 2001 From: James Cole Date: Sat, 7 Apr 2018 05:30:29 +0200 Subject: [PATCH 007/117] Fix JS in installer. --- public/js/ff/install/index.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/public/js/ff/install/index.js b/public/js/ff/install/index.js index dca7ec945e..d42eb1f647 100644 --- a/public/js/ff/install/index.js +++ b/public/js/ff/install/index.js @@ -45,7 +45,7 @@ function startMigration() { */ function startPassport() { $('#status-box').html(' Setting up OAuth2...'); - $.post(keysUri, {_token: token}).done(function () { + $.post(keysUri, {_token: token}).done(function (data) { if(data.error === false) { startUpgrade(); } else { @@ -62,7 +62,7 @@ function startPassport() { */ function startUpgrade() { $('#status-box').html(' Upgrading database...'); - $.post(upgradeUri, {_token: token}).done(function () { + $.post(upgradeUri, {_token: token}).done(function (data) { if(data.error === false) { startVerify(); } else { @@ -78,7 +78,7 @@ function startUpgrade() { */ function startVerify() { $('#status-box').html(' Verify database integrity...'); - $.post(verifyUri, {_token: token}).done(function () { + $.post(verifyUri, {_token: token}).done(function (data) { if(data.error === false) { completeDone(); } else { From b1ad0668cc5b8dd12f10fcb1ee8ecb4fca9412f2 Mon Sep 17 00:00:00 2001 From: James Cole Date: Sat, 7 Apr 2018 05:58:59 +0200 Subject: [PATCH 008/117] Clean overview for bills. --- app/Http/Controllers/BillController.php | 9 +++++-- resources/views/list/bills.twig | 34 ++++++------------------- 2 files changed, 15 insertions(+), 28 deletions(-) diff --git a/app/Http/Controllers/BillController.php b/app/Http/Controllers/BillController.php index 1aeeb7b8bb..0ce8312fcd 100644 --- a/app/Http/Controllers/BillController.php +++ b/app/Http/Controllers/BillController.php @@ -80,7 +80,7 @@ class BillController extends Controller { $periods = []; foreach (config('firefly.bill_periods') as $current) { - $periods[$current] = trans('firefly.' . $current); + $periods[$current] = strtolower((string)trans('firefly.repeat_freq_' . $current)); } $subTitle = trans('firefly.create_new_bill'); @@ -186,6 +186,11 @@ class BillController extends Controller return $transformer->transform($bill); } ); + $bills = $bills->sortBy( + function (array $bill) { + return (int)!$bill['active'] . strtolower($bill['name']); + } + ); $paginator->setPath(route('bills.index')); @@ -238,7 +243,7 @@ class BillController extends Controller $overallAverage = $repository->getOverallAverage($bill); $manager = new Manager(); $manager->setSerializer(new DataArraySerializer()); - $manager->parseIncludes(['attachments','notes']); + $manager->parseIncludes(['attachments', 'notes']); // Make a resource out of the data and $parameters = new ParameterBag(); diff --git a/resources/views/list/bills.twig b/resources/views/list/bills.twig index 0d37fddde7..128476957b 100644 --- a/resources/views/list/bills.twig +++ b/resources/views/list/bills.twig @@ -7,11 +7,9 @@   {{ trans('list.name') }} {{ trans('list.matchesOn') }} - {{ trans('list.matchingAmount') }} + {{ trans('list.matchingAmount') }} {{ trans('list.paid_current_period') }} {{ trans('list.next_expected_match') }} - {{ trans('list.active') }} - {{ trans('list.automatch') }} {{ trans('list.repeat_freq') }} @@ -34,6 +32,9 @@ class="fa fa-fw fa-trash-o"> + {% if not entry.active %} + + {% endif %} {{ entry.name }} {# count attachments #} {% if entry.attachments_count > 0 %} @@ -47,13 +48,8 @@ {% endfor %} - - {{ entry.amount_min|formatAmount }} - - - - - {{ entry.amount_max|formatAmount }} + + ~ {{ ((entry.amount_max+ entry.amount_min)/2)|formatAmount }} @@ -108,22 +104,8 @@ ~ {% endif %} - - {% if entry.active %} - - {% else %} - - {% endif %} - - - {% if entry.automatch %} - - {% else %} - - {% endif %} - - {{ entry.repeat_freq|_ }} + {{ ('repeat_freq_'~entry.repeat_freq)|_ }} {% if entry.skip > 0 %} {{ 'skips_over'|_ }} {{ entry.skip }} {% endif %} @@ -174,7 +156,7 @@ {{ 'expected_total'|_ }} ({{ 'active_bills_only'|_ }}) - {{ expected_total|formatAmount }} + ~ {{ expected_total|formatAmount }}   From b54e99642b0e78293d8d6fc2fb81dc4f3403be35 Mon Sep 17 00:00:00 2001 From: James Cole Date: Sat, 7 Apr 2018 06:19:40 +0200 Subject: [PATCH 009/117] Refactor some auto complete routes. --- .../Json/AutoCompleteController.php | 79 +++++++++++++++++++ app/Http/Controllers/JsonController.php | 58 -------------- routes/web.php | 19 +++-- 3 files changed, 91 insertions(+), 65 deletions(-) diff --git a/app/Http/Controllers/Json/AutoCompleteController.php b/app/Http/Controllers/Json/AutoCompleteController.php index 2a0b712545..ef8dbb2b76 100644 --- a/app/Http/Controllers/Json/AutoCompleteController.php +++ b/app/Http/Controllers/Json/AutoCompleteController.php @@ -28,6 +28,11 @@ use FireflyIII\Models\Account; use FireflyIII\Models\AccountType; use FireflyIII\Models\TransactionJournal; use FireflyIII\Repositories\Account\AccountRepositoryInterface; +use FireflyIII\Repositories\Bill\BillRepositoryInterface; +use FireflyIII\Repositories\Budget\BudgetRepositoryInterface; +use FireflyIII\Repositories\Category\CategoryRepositoryInterface; +use FireflyIII\Repositories\Journal\JournalRepositoryInterface; +use FireflyIII\Repositories\Tag\TagRepositoryInterface; use FireflyIII\Support\CacheProperties; /** @@ -35,6 +40,7 @@ use FireflyIII\Support\CacheProperties; */ class AutoCompleteController extends Controller { + /** * Returns a JSON list of all accounts. * @@ -68,6 +74,51 @@ class AutoCompleteController extends Controller return response()->json($return); } + /** + * Returns a JSON list of all bills. + * + * @param BillRepositoryInterface $repository + * + * @return \Illuminate\Http\JsonResponse + */ + public function bills(BillRepositoryInterface $repository) + { + $return = array_unique( + $repository->getActiveBills()->pluck('name')->toArray() + ); + sort($return); + + return response()->json($return); + } + + /** + * @param BudgetRepositoryInterface $repository + * + * @return \Illuminate\Http\JsonResponse + */ + public function budgets(BudgetRepositoryInterface $repository) + { + $return = array_unique($repository->getBudgets()->pluck('name')->toArray()); + sort($return); + + return response()->json($return); + } + + /** + * Returns a list of categories. + * + * @param CategoryRepositoryInterface $repository + * + * @return \Illuminate\Http\JsonResponse + */ + public function categories(CategoryRepositoryInterface $repository) + { + $return = array_unique($repository->getCategories()->pluck('name')->toArray()); + sort($return); + + return response()->json($return); + } + /** * Returns a JSON list of all beneficiaries. * @@ -150,6 +201,21 @@ class AutoCompleteController extends Controller return response()->json($return); } + /** + * Returns a JSON list of all beneficiaries. + * + * @param TagRepositoryInterface $tagRepository + * + * @return \Illuminate\Http\JsonResponse + */ + public function tags(TagRepositoryInterface $tagRepository) + { + $return = array_unique($tagRepository->get()->pluck('tag')->toArray()); + sort($return); + + return response()->json($return); + } + /** * @param JournalCollectorInterface $collector * @param string $what @@ -167,4 +233,17 @@ class AutoCompleteController extends Controller return response()->json($return); } + + /** + * @param JournalRepositoryInterface $repository + * + * @return \Illuminate\Http\JsonResponse + */ + public function transactionTypes(JournalRepositoryInterface $repository) + { + $return = array_unique($repository->getTransactionTypes()->pluck('type')->toArray()); + sort($return); + + return response()->json($return); + } } diff --git a/app/Http/Controllers/JsonController.php b/app/Http/Controllers/JsonController.php index 199d342d48..1ab9a93808 100644 --- a/app/Http/Controllers/JsonController.php +++ b/app/Http/Controllers/JsonController.php @@ -53,68 +53,10 @@ class JsonController extends Controller return response()->json(['html' => $view]); } - /** - * @param BudgetRepositoryInterface $repository - * - * @return \Illuminate\Http\JsonResponse - */ - public function budgets(BudgetRepositoryInterface $repository) - { - $return = array_unique($repository->getBudgets()->pluck('name')->toArray()); - sort($return); - - return response()->json($return); - } - - /** - * Returns a list of categories. - * - * @param CategoryRepositoryInterface $repository - * - * @return \Illuminate\Http\JsonResponse - */ - public function categories(CategoryRepositoryInterface $repository) - { - $return = array_unique($repository->getCategories()->pluck('name')->toArray()); - sort($return); - - return response()->json($return); - } - - /** - * Returns a JSON list of all beneficiaries. - * - * @param TagRepositoryInterface $tagRepository - * - * @return \Illuminate\Http\JsonResponse - */ - public function tags(TagRepositoryInterface $tagRepository) - { - $return = array_unique($tagRepository->get()->pluck('tag')->toArray()); - sort($return); - - return response()->json($return); - } - - /** - * @param JournalRepositoryInterface $repository - * - * @return \Illuminate\Http\JsonResponse - */ - public function transactionTypes(JournalRepositoryInterface $repository) - { - $return = array_unique($repository->getTransactionTypes()->pluck('type')->toArray()); - sort($return); - - return response()->json($return); - } - /** * @param Request $request * * @return \Illuminate\Http\JsonResponse - * - */ public function trigger(Request $request) { diff --git a/routes/web.php b/routes/web.php index 5f251b5b73..9c156f7e6a 100755 --- a/routes/web.php +++ b/routes/web.php @@ -492,22 +492,27 @@ Route::group( */ Route::group( ['middleware' => 'user-full-auth', 'namespace' => 'FireflyIII\Http\Controllers', 'prefix' => 'json', 'as' => 'json.'], function () { + + // for auto complete Route::get('expense-accounts', ['uses' => 'Json\AutoCompleteController@expenseAccounts', 'as' => 'expense-accounts']); Route::get('all-accounts', ['uses' => 'Json\AutoCompleteController@allAccounts', 'as' => 'all-accounts']); Route::get('revenue-accounts', ['uses' => 'Json\AutoCompleteController@revenueAccounts', 'as' => 'revenue-accounts']); - Route::get('categories', ['uses' => 'JsonController@categories', 'as' => 'categories']); - Route::get('budgets', ['uses' => 'JsonController@budgets', 'as' => 'budgets']); - Route::get('tags', ['uses' => 'JsonController@tags', 'as' => 'tags']); + Route::get('categories', ['uses' => 'Json\AutoCompleteController@categories', 'as' => 'categories']); + Route::get('budgets', ['uses' => 'Json\AutoCompleteController@budgets', 'as' => 'budgets']); + Route::get('tags', ['uses' => 'Json\AutoCompleteController@tags', 'as' => 'tags']); + Route::get('bills', ['uses' => 'Json\AutoCompleteController@bills', 'as' => 'bills']); + Route::get('transaction-journals/all', ['uses' => 'Json\AutoCompleteController@allTransactionJournals', 'as' => 'all-transaction-journals']); + Route::get('transaction-journals/with-id/{tj}', ['uses' => 'Json\AutoCompleteController@journalsWithId', 'as' => 'journals-with-id']); + Route::get('transaction-journals/{what}', ['uses' => 'Json\AutoCompleteController@transactionJournals', 'as' => 'transaction-journals']); + Route::get('transaction-types', ['uses' => 'Json\AutoCompleteController@transactionTypes', 'as' => 'transaction-types']); + // boxes Route::get('box/balance', ['uses' => 'Json\BoxController@balance', 'as' => 'box.balance']); Route::get('box/bills', ['uses' => 'Json\BoxController@bills', 'as' => 'box.bills']); Route::get('box/available', ['uses' => 'Json\BoxController@available', 'as' => 'box.available']); Route::get('box/net-worth', ['uses' => 'Json\BoxController@netWorth', 'as' => 'box.net-worth']); - Route::get('transaction-journals/all', ['uses' => 'Json\AutoCompleteController@allTransactionJournals', 'as' => 'all-transaction-journals']); - Route::get('transaction-journals/with-id/{tj}', ['uses' => 'Json\AutoCompleteController@journalsWithId', 'as' => 'journals-with-id']); - Route::get('transaction-journals/{what}', ['uses' => 'Json\AutoCompleteController@transactionJournals', 'as' => 'transaction-journals']); - Route::get('transaction-types', ['uses' => 'JsonController@transactionTypes', 'as' => 'transaction-types']); + // rules Route::get('trigger', ['uses' => 'JsonController@trigger', 'as' => 'trigger']); Route::get('action', ['uses' => 'JsonController@action', 'as' => 'action']); From 7af10aca9ef0783dcb576a5670995aa2bcca6581 Mon Sep 17 00:00:00 2001 From: James Cole Date: Sat, 7 Apr 2018 06:20:45 +0200 Subject: [PATCH 010/117] Add new action to link a transaction to a bill. --- app/TransactionRules/Actions/LinkToBill.php | 76 +++++++++++++++++++++ app/Validation/FireflyValidator.php | 9 ++- config/firefly.php | 2 + public/js/ff/rules/create-edit.js | 3 + resources/lang/en_US/firefly.php | 2 + 5 files changed, 91 insertions(+), 1 deletion(-) create mode 100644 app/TransactionRules/Actions/LinkToBill.php diff --git a/app/TransactionRules/Actions/LinkToBill.php b/app/TransactionRules/Actions/LinkToBill.php new file mode 100644 index 0000000000..192c01c352 --- /dev/null +++ b/app/TransactionRules/Actions/LinkToBill.php @@ -0,0 +1,76 @@ +. + */ +declare(strict_types=1); + +namespace FireflyIII\TransactionRules\Actions; + +use FireflyIII\Models\RuleAction; +use FireflyIII\Models\TransactionJournal; +use FireflyIII\Models\TransactionType; +use FireflyIII\Repositories\Bill\BillRepositoryInterface; +use Log; + +/** + * Class LinkToBill. + */ +class LinkToBill implements ActionInterface +{ + /** @var RuleAction The rule action */ + private $action; + + /** + * TriggerInterface constructor. + * + * @param RuleAction $action + */ + public function __construct(RuleAction $action) + { + $this->action = $action; + } + + /** + * Set bill to be X. + * + * @param TransactionJournal $journal + * + * @return bool + */ + public function act(TransactionJournal $journal): bool + { + /** @var BillRepositoryInterface $repository */ + $repository = app(BillRepositoryInterface::class); + $billName = (string)$this->action->action_value; + $bill = $repository->findByName($billName); + + if (null !== $bill && $journal->transactionType->type === TransactionType::WITHDRAWAL) { + $journal->bill()->associate($bill); + $journal->save(); + Log::debug(sprintf('RuleAction LinkToBill set the bill of journal #%d to bill #%d ("%s").', $journal->id, $bill->id, $bill->name)); + } + + if (null === $bill) { + Log::error(sprintf('RuleAction LinkToBill could not set the bill of journal #%d to bill "%s": no such bill found!', $journal->id, $billName)); + } + + + return true; + } +} diff --git a/app/Validation/FireflyValidator.php b/app/Validation/FireflyValidator.php index e72472c99d..79b7ced902 100644 --- a/app/Validation/FireflyValidator.php +++ b/app/Validation/FireflyValidator.php @@ -31,6 +31,7 @@ use FireflyIII\Models\AccountType; use FireflyIII\Models\Budget; use FireflyIII\Models\PiggyBank; use FireflyIII\Models\TransactionType; +use FireflyIII\Repositories\Bill\BillRepositoryInterface; use FireflyIII\Repositories\Budget\BudgetRepositoryInterface; use FireflyIII\Services\Password\Verifier; use FireflyIII\TransactionRules\Triggers\TriggerInterface; @@ -254,6 +255,12 @@ class FireflyValidator extends Validator )->count(); return 1 === $count; + case 'link_to_bill': + /** @var BillRepositoryInterface $repository */ + $repository = app(BillRepositoryInterface::class); + $bill = $repository->findByName((string)$value); + + return null !== $bill; case 'invalid': return false; } @@ -275,7 +282,7 @@ class FireflyValidator extends Validator // loop all rule-triggers. // check if rule-value matches the thing. - if (is_array($this->data['rule-trigger'])) { + if (\is_array($this->data['rule-trigger'])) { $name = $this->getRuleTriggerName($index); $value = $this->getRuleTriggerValue($index); diff --git a/config/firefly.php b/config/firefly.php index ccc426ecbd..c23585c017 100644 --- a/config/firefly.php +++ b/config/firefly.php @@ -9,6 +9,7 @@ use FireflyIII\TransactionRules\Actions\AppendNotes; use FireflyIII\TransactionRules\Actions\ClearBudget; use FireflyIII\TransactionRules\Actions\ClearCategory; use FireflyIII\TransactionRules\Actions\ClearNotes; +use FireflyIII\TransactionRules\Actions\LinkToBill; use FireflyIII\TransactionRules\Actions\PrependDescription; use FireflyIII\TransactionRules\Actions\PrependNotes; use FireflyIII\TransactionRules\Actions\RemoveAllTags; @@ -354,6 +355,7 @@ return [ 'append_notes' => AppendNotes::class, 'prepend_notes' => PrependNotes::class, 'clear_notes' => ClearNotes::class, + 'link_to_bill' => LinkToBill::class, ], 'rule-actions-text' => [ 'set_category', diff --git a/public/js/ff/rules/create-edit.js b/public/js/ff/rules/create-edit.js index 50e6a7db88..a9b5ed0e86 100644 --- a/public/js/ff/rules/create-edit.js +++ b/public/js/ff/rules/create-edit.js @@ -224,6 +224,9 @@ function updateActionInput(selectList) { case 'set_destination_account': createAutoComplete(input, 'json/all-accounts'); break; + case 'link_to_bill': + createAutoComplete(input, 'json/bills'); + break; default: input.typeahead('destroy'); break; diff --git a/resources/lang/en_US/firefly.php b/resources/lang/en_US/firefly.php index 17db817fc3..1113f9e9d1 100644 --- a/resources/lang/en_US/firefly.php +++ b/resources/lang/en_US/firefly.php @@ -404,6 +404,8 @@ return [ 'rule_action_clear_notes_choice' => 'Remove any notes', 'rule_action_clear_notes' => 'Remove any notes', 'rule_action_set_notes_choice' => 'Set notes to..', + 'rule_action_link_to_bill_choice' => 'Link to a bill..', + 'rule_action_link_to_bill' => 'Link to bill ":action_value"', 'rule_action_set_notes' => 'Set notes to ":action_value"', 'rules_have_read_warning' => 'Have you read the warning?', From d3701837e3d8b8d5b6dfd661cf3a6844109f0d59 Mon Sep 17 00:00:00 2001 From: James Cole Date: Sat, 7 Apr 2018 18:00:09 +0200 Subject: [PATCH 011/117] Possible fix for #1325 --- app/Http/Controllers/TagController.php | 1 + app/Repositories/Tag/TagRepository.php | 87 ++++++++++++++++---------- resources/views/tags/index.twig | 4 +- 3 files changed, 57 insertions(+), 35 deletions(-) diff --git a/app/Http/Controllers/TagController.php b/app/Http/Controllers/TagController.php index 0957c6db62..53652a00cc 100644 --- a/app/Http/Controllers/TagController.php +++ b/app/Http/Controllers/TagController.php @@ -171,6 +171,7 @@ class TagController extends Controller $now = new Carbon; $clouds = []; $clouds['no-date'] = $repository->tagCloud(null); + while ($now > $start) { $year = $now->year; $clouds[$year] = $repository->tagCloud($year); diff --git a/app/Repositories/Tag/TagRepository.php b/app/Repositories/Tag/TagRepository.php index 49b6da7e3f..0bca55405a 100644 --- a/app/Repositories/Tag/TagRepository.php +++ b/app/Repositories/Tag/TagRepository.php @@ -30,6 +30,7 @@ use FireflyIII\Models\Tag; use FireflyIII\Models\TransactionJournal; use FireflyIII\Models\TransactionType; use FireflyIII\User; +use Illuminate\Database\Eloquent\Builder; use Illuminate\Support\Collection; use Log; @@ -323,44 +324,42 @@ class TagRepository implements TagRepositoryInterface $min = null; $max = '0'; $return = []; - // get all tags - $allTags = $this->user->tags(); - // get tags with a certain amount (in this range): - $query = $this->user->tags() - ->leftJoin('tag_transaction_journal', 'tag_transaction_journal.tag_id', '=', 'tags.id') - ->leftJoin('transaction_journals', 'tag_transaction_journal.transaction_journal_id', '=', 'transaction_journals.id') - ->leftJoin('transactions', 'transaction_journals.id', '=', 'transactions.transaction_journal_id') - ->where('transactions.amount', '>', 0) - ->groupBy(['tags.id', 'tags.tag']); + // get all tags in the year (if present): + $tagQuery = $this->user->tags() + ->leftJoin('tag_transaction_journal', 'tag_transaction_journal.tag_id', '=', 'tags.id') + ->leftJoin('transaction_journals', 'tag_transaction_journal.transaction_journal_id', '=', 'transaction_journals.id') + ->leftJoin('transactions', 'transaction_journals.id', '=', 'transactions.transaction_journal_id') + ->where( + function (Builder $query) { + $query->where('transactions.amount', '>', 0); + $query->orWhereNull('transactions.amount'); + } + ) + ->groupBy(['tags.id', 'tags.tag']); // add date range (or not): if (null === $year) { - $query->whereNull('tags.date'); - $allTags->whereNull('tags.date'); + Log::debug('Get tags without a date.'); + $tagQuery->whereNull('tags.date'); } if (null !== $year) { - $start = $year . '-01-01'; - $end = $year . '-12-31'; - $query->where('tags.date', '>=', $start)->where('tags.date', '<=', $end); - $allTags->where('tags.date', '>=', $start)->where('tags.date', '<=', $end); - } - $set = $query->get(['tags.id', DB::raw('SUM(transactions.amount) as amount_sum')]); - $tagsWithAmounts = []; - /** @var Tag $tag */ - foreach ($set as $tag) { - $tagsWithAmounts[$tag->id] = (string)$tag->amount_sum; + Log::debug(sprintf('Get tags with year %s.', $year)); + $start = $year . '-01-01 00:00:00'; + $end = $year . '-12-31 23:59:59'; + $tagQuery->where('tags.date', '>=', $start)->where('tags.date', '<=', $end); } - $tags = $allTags->orderBy('tags.id', 'desc')->get(['tags.id', 'tags.tag']); - $temporary = []; + $result = $tagQuery->get(['tags.id', 'tags.tag', DB::raw('SUM(transactions.amount) as amount_sum')]); + /** @var Tag $tag */ - foreach ($tags as $tag) { - $amount = $tagsWithAmounts[$tag->id] ?? '0'; + foreach ($result as $tag) { + $tagsWithAmounts[$tag->id] = (string)$tag->amount_sum; + $amount = strlen($tagsWithAmounts[$tag->id]) ? $tagsWithAmounts[$tag->id] : '0'; if (null === $min) { $min = $amount; } $max = 1 === bccomp($amount, $max) ? $amount : $max; - $min = bccomp($amount, $min) === -1 ? $amount : $min; + $min = -1 === bccomp($amount, $min) ? $amount : $min; $temporary[] = [ 'amount' => $amount, @@ -369,16 +368,38 @@ class TagRepository implements TagRepositoryInterface 'tag' => $tag->tag, ], ]; + Log::debug(sprintf('After tag "%s", max is %s and min is %s.', $tag->tag, $max, $min)); } + $min = $min ?? '0'; + Log::debug(sprintf('FINAL max is %s, FINAL min is %s', $max, $min)); + // the difference between max and min: + $range = bcsub($max, $min); + Log::debug(sprintf('The range is: %s', $range)); - /** @var array $entry */ - foreach ($temporary as $entry) { - $scale = $this->cloudScale([12, 20], (float)$entry['amount'], (float)$min, (float)$max); - $tagId = $entry['tag']['id']; - $return[$tagId] = [ - 'scale' => $scale, - 'tag' => $entry['tag'], + // each euro difference is this step in the scale: + $step = (float)$range !== 0.0 ? 8 / (float)$range : 0; + Log::debug(sprintf('The step is: %f', $step)); + $return = []; + + + foreach ($result as $tag) { + if ($step === 0) { + // easy: size is 12: + $size = 12; + } + if ($step !== 0) { + $amount = bcsub((string)$tag->amount_sum, $min); + Log::debug(sprintf('Work with amount %s for tag %s', $amount, $tag->tag)); + $size = ((int)(float)$amount * $step) + 12; + } + + $return[$tag->id] = [ + 'size' => $size, + 'tag' => $tag->tag, + 'id' => $tag->id, ]; + + Log::debug(sprintf('Size is %d', $size)); } return $return; diff --git a/resources/views/tags/index.twig b/resources/views/tags/index.twig index f25a58614b..1b6c8bf6fb 100644 --- a/resources/views/tags/index.twig +++ b/resources/views/tags/index.twig @@ -28,8 +28,8 @@

{% for tagInfo in entries %} - {{ tagInfo.tag.tag }} + {{ tagInfo.tag }} {% endfor %}

From 7b715925cf88d793d0b9d26fea7bdb856703e824 Mon Sep 17 00:00:00 2001 From: James Cole Date: Sat, 7 Apr 2018 22:23:16 +0200 Subject: [PATCH 012/117] Code for #1324 --- app/Console/Commands/UpgradeDatabase.php | 121 +++++++++++++++++- app/Factory/BillFactory.php | 11 +- app/Factory/TagFactory.php | 2 +- app/Http/Controllers/BillController.php | 35 +++-- app/Http/Controllers/RuleController.php | 60 ++++++++- app/Http/Requests/BillFormRequest.php | 48 +++---- app/Models/Bill.php | 2 +- app/Models/Rule.php | 2 + app/Models/RuleAction.php | 3 + app/Models/RuleTrigger.php | 3 + .../RuleGroup/RuleGroupRepository.php | 2 - .../Internal/Support/JournalServiceTrait.php | 2 +- app/Support/ExpandedForm.php | 28 ++++ config/intro.php | 3 +- config/twigbridge.php | 2 +- .../2018_04_07_210913_changes_for_v473.php | 36 ++++++ resources/lang/en_US/firefly.php | 8 ++ resources/lang/en_US/intro.php | 6 +- resources/views/bills/create.twig | 8 +- resources/views/form/amount-no-currency.twig | 7 + resources/views/list/bills.twig | 10 +- resources/views/rules/rule/create.twig | 16 +++ 22 files changed, 343 insertions(+), 72 deletions(-) create mode 100644 database/migrations/2018_04_07_210913_changes_for_v473.php create mode 100644 resources/views/form/amount-no-currency.twig diff --git a/app/Console/Commands/UpgradeDatabase.php b/app/Console/Commands/UpgradeDatabase.php index 61f6e2ed99..2da1ff57ed 100644 --- a/app/Console/Commands/UpgradeDatabase.php +++ b/app/Console/Commands/UpgradeDatabase.php @@ -28,13 +28,20 @@ use FireflyIII\Models\Account; use FireflyIII\Models\AccountMeta; use FireflyIII\Models\AccountType; use FireflyIII\Models\Attachment; +use FireflyIII\Models\Bill; use FireflyIII\Models\Note; +use FireflyIII\Models\Preference; +use FireflyIII\Models\Rule; +use FireflyIII\Models\RuleAction; +use FireflyIII\Models\RuleGroup; +use FireflyIII\Models\RuleTrigger; use FireflyIII\Models\Transaction; use FireflyIII\Models\TransactionCurrency; use FireflyIII\Models\TransactionJournal; use FireflyIII\Models\TransactionJournalMeta; use FireflyIII\Models\TransactionType; use FireflyIII\Repositories\Currency\CurrencyRepositoryInterface; +use FireflyIII\User; use Illuminate\Console\Command; use Illuminate\Database\QueryException; use Illuminate\Support\Collection; @@ -70,6 +77,7 @@ class UpgradeDatabase extends Command */ public function handle() { + $this->migrateBillsToRules(); $this->setTransactionIdentifier(); $this->updateAccountCurrencies(); $this->createNewTypes(); @@ -79,9 +87,118 @@ class UpgradeDatabase extends Command $this->line('Done updating currency information..'); $this->migrateNotes(); $this->migrateAttachmentData(); - $this->info('Firefly III database is up to date.'); - return; + $this->info('Firefly III database is up to date.'); + } + + public function migrateBillsToRules() + { + foreach (User::get() as $user) { + /** @var Preference $lang */ + $lang = Preferences::getForUser($user, 'language', 'en_US'); + $groupName = (string)trans('firefly.rulegroup_for_bills_title', [], $lang->data); + $ruleGroup = $user->ruleGroups()->where('title', $groupName)->first(); + $currencyPreference = Preferences::getForUser($user, 'currencyPreference', config('firefly.default_currency', 'EUR')); + $currency = TransactionCurrency::where('code', $currencyPreference->data)->first(); + + if ($ruleGroup === null) { + $array = RuleGroup::get(['order'])->pluck('order')->toArray(); + $order = count($array) > 0 ? max($array) + 1 : 1; + $ruleGroup = RuleGroup::create( + [ + 'user_id' => $user->id, + 'title' => (string)trans('firefly.rulegroup_for_bills_title', [], $lang->data), + 'description' => (string)trans('firefly.rulegroup_for_bills_description', [], $lang->data), + 'order' => $order, + 'active' => 1, + ] + ); + } + + // loop bills. + $order = 1; + /** @var Bill $bill */ + foreach ($user->bills()->get() as $bill) { + if ($bill->match !== 'MIGRATED_TO_RULES') { + $rule = Rule::create( + [ + 'user_id' => $user->id, + 'rule_group_id' => $ruleGroup->id, + 'title' => (string)trans('firefly.rule_for_bill_title', ['name' => $bill->name], $lang->data), + 'description' => (string)trans('firefly.rule_for_bill_description', ['name' => $bill->name], $lang->data), + 'order' => $order, + 'active' => 1, + 'stop_processing' => 1, + ] + ); + // add default trigger + RuleTrigger::create( + [ + 'rule_id' => $rule->id, + 'trigger_type' => 'user_action', + 'trigger_value' => 'store-journal', + 'active' => 1, + 'stop_processing' => 0, + 'order' => 1, + ] + ); + // add trigger for description + $match = implode(' ', explode(',', $bill->match)); + RuleTrigger::create( + [ + 'rule_id' => $rule->id, + 'trigger_type' => 'description_is', + 'trigger_value' => $match, + 'active' => 1, + 'stop_processing' => 0, + 'order' => 2, + ] + ); + + // add triggers for amounts: + RuleTrigger::create( + [ + 'rule_id' => $rule->id, + 'trigger_type' => 'amount_less', + 'trigger_value' => round($bill->amount_max, $currency->decimal_places), + 'active' => 1, + 'stop_processing' => 0, + 'order' => 3, + ] + ); + RuleTrigger::create( + [ + 'rule_id' => $rule->id, + 'trigger_type' => 'amount_more', + 'trigger_value' => round($bill->amount_min, $currency->decimal_places), + 'active' => 1, + 'stop_processing' => 0, + 'order' => 4, + ] + ); + + // create action + RuleAction::create( + [ + 'rule_id' => $rule->id, + 'action_type' => 'link_to_bill', + 'action_value' => $bill->name, + 'order' => 1, + 'active' => 1, + 'stop_processing' => 0, + ] + ); + + $order++; + //$bill->match = 'MIGRATED_TO_RULES'; + $bill->save(); + $this->line(sprintf('Updated bill #%d ("%s") so it will use rules.', $bill->id, $bill->name)); + } + } + + $this->line('Exit'); + exit; + } } /** diff --git a/app/Factory/BillFactory.php b/app/Factory/BillFactory.php index 552c53eb5e..e8522f6842 100644 --- a/app/Factory/BillFactory.php +++ b/app/Factory/BillFactory.php @@ -45,22 +45,19 @@ class BillFactory */ public function create(array $data): ?Bill { - $matchArray = explode(',', $data['match']); - $matchArray = array_unique($matchArray); - $match = implode(',', $matchArray); - /** @var Bill $bill */ $bill = Bill::create( [ 'name' => $data['name'], - 'match' => $match, + 'match' => 'MIGRATED_TO_RULES', 'amount_min' => $data['amount_min'], 'user_id' => $this->user->id, + 'currency_id' => $data['currency_id'], 'amount_max' => $data['amount_max'], 'date' => $data['date'], 'repeat_freq' => $data['repeat_freq'], 'skip' => $data['skip'], - 'automatch' => $data['automatch'], + 'automatch' => true, 'active' => $data['active'], ] ); @@ -94,7 +91,7 @@ class BillFactory } // then find by name: - if (strlen($billName) > 0) { + if (\strlen($billName) > 0) { $bill = $this->findByName($billName); if (null !== $bill) { return $bill; diff --git a/app/Factory/TagFactory.php b/app/Factory/TagFactory.php index 483255f246..09e9212a27 100644 --- a/app/Factory/TagFactory.php +++ b/app/Factory/TagFactory.php @@ -71,7 +71,7 @@ class TagFactory /** @var Tag $object */ foreach ($this->tags as $object) { - if ($object->tag === $tag) { + if (strtolower($object->tag) === strtolower($tag)) { return $object; } } diff --git a/app/Http/Controllers/BillController.php b/app/Http/Controllers/BillController.php index 0ce8312fcd..45e4a6293d 100644 --- a/app/Http/Controllers/BillController.php +++ b/app/Http/Controllers/BillController.php @@ -22,6 +22,7 @@ declare(strict_types=1); namespace FireflyIII\Http\Controllers; +use ExpandedForm; use FireflyIII\Helpers\Attachments\AttachmentHelperInterface; use FireflyIII\Helpers\Collector\JournalCollectorInterface; use FireflyIII\Http\Requests\BillFormRequest; @@ -29,6 +30,8 @@ use FireflyIII\Models\Bill; use FireflyIII\Models\Note; use FireflyIII\Models\TransactionJournal; use FireflyIII\Repositories\Bill\BillRepositoryInterface; +use FireflyIII\Repositories\Currency\CurrencyRepositoryInterface; +use FireflyIII\Repositories\RuleGroup\RuleGroupRepositoryInterface; use FireflyIII\Transformers\BillTransformer; use Illuminate\Http\Request; use Illuminate\Support\Collection; @@ -76,13 +79,15 @@ class BillController extends Controller * * @return View */ - public function create(Request $request) + public function create(Request $request, CurrencyRepositoryInterface $repository) { $periods = []; foreach (config('firefly.bill_periods') as $current) { $periods[$current] = strtolower((string)trans('firefly.repeat_freq_' . $current)); } - $subTitle = trans('firefly.create_new_bill'); + $subTitle = trans('firefly.create_new_bill'); + $defaultCurrency = app('amount')->getDefaultCurrency(); + $currencies = ExpandedForm::makeSelectList($repository->get()); // put previous url in session if not redirect from store (not "create another"). if (true !== session('bills.create.fromStore')) { @@ -90,7 +95,7 @@ class BillController extends Controller } $request->session()->forget('bills.create.fromStore'); - return view('bills.create', compact('periods', 'subTitle')); + return view('bills.create', compact('periods', 'subTitle', 'currencies', 'defaultCurrency')); } /** @@ -270,7 +275,7 @@ class BillController extends Controller * * @return \Illuminate\Http\RedirectResponse */ - public function store(BillFormRequest $request, BillRepositoryInterface $repository) + public function store(BillFormRequest $request, BillRepositoryInterface $repository, RuleGroupRepositoryInterface $ruleGroupRepository) { $billData = $request->getBillData(); $bill = $repository->store($billData); @@ -291,16 +296,22 @@ class BillController extends Controller $request->session()->flash('info', $this->attachments->getMessages()->get('attachments')); // @codeCoverageIgnore } - if (1 === (int)$request->get('create_another')) { - // @codeCoverageIgnoreStart - $request->session()->put('bills.create.fromStore', true); - - return redirect(route('bills.create'))->withInput(); - // @codeCoverageIgnoreEnd + // find first rule group, or create one: + $count = $ruleGroupRepository->count(); + if ($count === 0) { + $data = [ + 'title' => (string)trans('firefly.rulegroup_for_bills_title'), + 'description' => (string)trans('firefly.rulegroup_for_bills_description'), + ]; + $group = $ruleGroupRepository->store($data); + } + if ($count > 0) { + $group = $ruleGroupRepository->getActiveGroups(auth()->user())->first(); } - // redirect to previous URL. - return redirect($this->getPreviousUri('bills.create.uri')); + + // redirect to page that will create a new rule. + return redirect(route('rules.create', [$group->id]) . '?fromBill=' . $bill->id); } /** diff --git a/app/Http/Controllers/RuleController.php b/app/Http/Controllers/RuleController.php index c6b550967f..21c0ae694c 100644 --- a/app/Http/Controllers/RuleController.php +++ b/app/Http/Controllers/RuleController.php @@ -34,6 +34,7 @@ use FireflyIII\Models\RuleAction; use FireflyIII\Models\RuleGroup; use FireflyIII\Models\RuleTrigger; use FireflyIII\Repositories\Account\AccountRepositoryInterface; +use FireflyIII\Repositories\Bill\BillRepositoryInterface; use FireflyIII\Repositories\Rule\RuleRepositoryInterface; use FireflyIII\Repositories\RuleGroup\RuleGroupRepositoryInterface; use FireflyIII\TransactionRules\TransactionMatcher; @@ -75,8 +76,11 @@ class RuleController extends Controller */ - public function create(Request $request, RuleGroup $ruleGroup) + public function create(Request $request, RuleGroupRepositoryInterface $ruleGroupRepository, BillRepositoryInterface $billRepository, RuleGroup $ruleGroup) { + $bill = null; + $billId = (int)$request->get('fromBill'); + $preFilled = []; // count for possible present previous entered triggers/actions. $triggerCount = 0; $actionCount = 0; @@ -89,12 +93,60 @@ class RuleController extends Controller if ($request->old()) { // process old triggers. $oldTriggers = $this->getPreviousTriggers($request); - $triggerCount = count($oldTriggers); + $triggerCount = \count($oldTriggers); // process old actions $oldActions = $this->getPreviousActions($request); - $actionCount = count($oldActions); + $actionCount = \count($oldActions); } + if ($billId > 0) { + $bill = $billRepository->find($billId); + // create some sensible defaults: + $preFilled['title'] = trans('firefly.new_rule_for_bill_title', ['name' => $bill->name]); + $preFilled['description'] = trans('firefly.new_rule_for_bill_description', ['name' => $bill->name]); + $request->session()->flash('preFilled', $preFilled); + + // pretend there are old triggers, so the page will fill them in: + $oldTriggers[] = view( + 'rules.partials.trigger', + [ + 'oldTrigger' => 'amount_more', + 'oldValue' => round($bill->amount_min,12), + 'oldChecked' => false, + 'count' => 1, + ] + )->render(); + $oldTriggers[] = view( + 'rules.partials.trigger', + [ + 'oldTrigger' => 'amount_less', + 'oldValue' => round($bill->amount_max,12), + 'oldChecked' => false, + 'count' => 2, + ] + )->render(); + $oldTriggers[] = view( + 'rules.partials.trigger', + [ + 'oldTrigger' => 'description_contains', + 'oldValue' => $bill->name,12, + 'oldChecked' => false, + 'count' => 3, + ] + )->render(); + + $oldActions[] = view( + 'rules.partials.action', + [ + 'oldAction' => 'link_to_bill', + 'oldValue' => $bill->name, + 'oldChecked' => false, + 'count' => 1, + ] + )->render(); + + } + $subTitleIcon = 'fa-clone'; $subTitle = trans('firefly.make_new_rule', ['title' => $ruleGroup->title]); @@ -107,7 +159,7 @@ class RuleController extends Controller return view( 'rules.rule.create', - compact('subTitleIcon', 'oldTriggers', 'oldActions', 'triggerCount', 'actionCount', 'ruleGroup', 'subTitle') + compact('subTitleIcon', 'oldTriggers', 'preFilled', 'bill', 'oldActions', 'triggerCount', 'actionCount', 'ruleGroup', 'subTitle') ); } diff --git a/app/Http/Requests/BillFormRequest.php b/app/Http/Requests/BillFormRequest.php index 0012197b44..e8e3677e41 100644 --- a/app/Http/Requests/BillFormRequest.php +++ b/app/Http/Requests/BillFormRequest.php @@ -42,18 +42,15 @@ class BillFormRequest extends Request public function getBillData() { return [ - 'name' => $this->string('name'), - 'match' => $this->string('match'), - 'amount_min' => $this->string('amount_min'), - 'amount_currency_id_amount_min' => $this->integer('amount_currency_id_amount_min'), - 'amount_currency_id_amount_max' => $this->integer('amount_currency_id_amount_max'), - 'amount_max' => $this->string('amount_max'), - 'date' => $this->date('date'), - 'repeat_freq' => $this->string('repeat_freq'), - 'skip' => $this->integer('skip'), - 'automatch' => $this->boolean('automatch'), - 'active' => $this->boolean('active'), - 'notes' => $this->string('notes'), + 'name' => $this->string('name'), + 'amount_min' => $this->string('amount_min'), + 'currency_id' => $this->integer('currency_id'), + 'amount_max' => $this->string('amount_max'), + 'date' => $this->date('date'), + 'repeat_freq' => $this->string('repeat_freq'), + 'skip' => $this->integer('skip'), + 'active' => $this->boolean('active'), + 'notes' => $this->string('notes'), ]; } @@ -62,25 +59,22 @@ class BillFormRequest extends Request */ public function rules() { - $nameRule = 'required|between:1,255|uniqueObjectForUser:bills,name'; - $matchRule = 'required|between:1,255|uniqueObjectForUser:bills,match'; + $nameRule = 'required|between:1,255|uniqueObjectForUser:bills,name'; if ($this->integer('id') > 0) { - $nameRule .= ',' . $this->integer('id'); - $matchRule .= ',' . $this->integer('id'); + // todo is a fix to do this better. + $nameRule .= ',' . $this->integer('id'); } // is OK $rules = [ - 'name' => $nameRule, - 'match' => $matchRule, - 'amount_min' => 'required|numeric|more:0', - 'amount_max' => 'required|numeric|more:0', - 'amount_currency_id_amount_min' => 'required|exists:transaction_currencies,id', - 'amount_currency_id_amount_max' => 'required|exists:transaction_currencies,id', - 'date' => 'required|date', - 'repeat_freq' => 'required|in:weekly,monthly,quarterly,half-year,yearly', - 'skip' => 'required|between:0,31', - 'automatch' => 'in:1', - 'active' => 'in:1', + 'name' => $nameRule, + 'amount_min' => 'required|numeric|more:0', + 'amount_max' => 'required|numeric|more:0', + 'currency_id' => 'required|exists:transaction_currencies,id', + 'date' => 'required|date', + 'repeat_freq' => 'required|in:weekly,monthly,quarterly,half-year,yearly', + 'skip' => 'required|between:0,31', + 'automatch' => 'in:1', + 'active' => 'in:1', ]; return $rules; diff --git a/app/Models/Bill.php b/app/Models/Bill.php index 10b240f9c8..d8513b60d6 100644 --- a/app/Models/Bill.php +++ b/app/Models/Bill.php @@ -57,7 +57,7 @@ class Bill extends Model */ protected $fillable = ['name', 'match', 'amount_min', 'match_encrypted', 'name_encrypted', 'user_id', 'amount_max', 'date', 'repeat_freq', 'skip', - 'automatch', 'active',]; + 'automatch', 'active','currency_id']; /** * @var array */ diff --git a/app/Models/Rule.php b/app/Models/Rule.php index 17879ad461..db514c8609 100644 --- a/app/Models/Rule.php +++ b/app/Models/Rule.php @@ -47,6 +47,8 @@ class Rule extends Model 'order' => 'int', 'stop_processing' => 'boolean', ]; + /** @var array */ + protected $fillable = ['rule_group_id', 'order', 'active', 'title', 'description', 'user_id']; /** * @param string $value diff --git a/app/Models/RuleAction.php b/app/Models/RuleAction.php index 2bb86141fd..6586610f67 100644 --- a/app/Models/RuleAction.php +++ b/app/Models/RuleAction.php @@ -43,6 +43,9 @@ class RuleAction extends Model 'stop_processing' => 'boolean', ]; + /** @var array */ + protected $fillable = ['rule_id', 'action_type', 'action_value', 'order', 'active', 'stop_processing']; + /** * @codeCoverageIgnore * @return \Illuminate\Database\Eloquent\Relations\BelongsTo diff --git a/app/Models/RuleTrigger.php b/app/Models/RuleTrigger.php index 842be11e52..e52fd4340c 100644 --- a/app/Models/RuleTrigger.php +++ b/app/Models/RuleTrigger.php @@ -43,6 +43,9 @@ class RuleTrigger extends Model 'stop_processing' => 'boolean', ]; + /** @var array */ + protected $fillable = ['rule_id', 'trigger_type', 'trigger_value', 'order', 'active', 'stop_processing']; + /** * @codeCoverageIgnore * @return \Illuminate\Database\Eloquent\Relations\BelongsTo diff --git a/app/Repositories/RuleGroup/RuleGroupRepository.php b/app/Repositories/RuleGroup/RuleGroupRepository.php index dd90b86cc9..a693894aab 100644 --- a/app/Repositories/RuleGroup/RuleGroupRepository.php +++ b/app/Repositories/RuleGroup/RuleGroupRepository.php @@ -50,8 +50,6 @@ class RuleGroupRepository implements RuleGroupRepositoryInterface * * @return bool * - - */ public function destroy(RuleGroup $ruleGroup, ?RuleGroup $moveTo): bool { diff --git a/app/Services/Internal/Support/JournalServiceTrait.php b/app/Services/Internal/Support/JournalServiceTrait.php index 4ce551ecde..f87e8dcf68 100644 --- a/app/Services/Internal/Support/JournalServiceTrait.php +++ b/app/Services/Internal/Support/JournalServiceTrait.php @@ -51,7 +51,7 @@ trait JournalServiceTrait return; // @codeCoverageIgnore } foreach ($data['tags'] as $string) { - if (strlen($string) > 0) { + if (\strlen($string) > 0) { $tag = $factory->findOrCreate($string); $set[] = $tag->id; } diff --git a/app/Support/ExpandedForm.php b/app/Support/ExpandedForm.php index a1707ed1d0..0662f811bc 100644 --- a/app/Support/ExpandedForm.php +++ b/app/Support/ExpandedForm.php @@ -52,6 +52,34 @@ class ExpandedForm return $this->currencyField($name, 'amount', $value, $options); } + /** + * @param string $name + * @param null $value + * @param array $options + * + * @return string + * @throws \FireflyIII\Exceptions\FireflyException + * @throws \Throwable + */ + public function amountNoCurrency(string $name, $value = null, array $options = []): string + { + $label = $this->label($name, $options); + $options = $this->expandOptionArray($name, $label, $options); + $classes = $this->getHolderClasses($name); + $value = $this->fillFieldValue($name, $value); + $options['step'] = 'any'; + unset($options['currency'], $options['placeholder']); + + // make sure value is formatted nicely: + if (null !== $value && '' !== $value) { + $value = round($value, 8); + } + + $html = view('form.amount-no-currency', compact('classes', 'name', 'label', 'value', 'options'))->render(); + + return $html; + } + /** * @param string $name * @param null $value diff --git a/config/intro.php b/config/intro.php index 29fccb7fa0..7dcdac2289 100644 --- a/config/intro.php +++ b/config/intro.php @@ -128,8 +128,9 @@ return [ 'expected_in_period' => ['element' => '.expected_in_period'], ], 'bills_create' => [ + 'intro' => [], 'name' => ['element' => '#name_holder'], - 'match' => ['element' => '#match_holder'], + //'match' => ['element' => '#match_holder'], 'amount_min_holder' => ['element' => '#amount_min_holder'], 'repeat_freq_holder' => ['element' => '#repeat_freq_holder'], 'skip_holder' => ['element' => '#skip_holder'], diff --git a/config/twigbridge.php b/config/twigbridge.php index 60f2d36c79..2ae6c1ddab 100644 --- a/config/twigbridge.php +++ b/config/twigbridge.php @@ -188,7 +188,7 @@ return [ 'is_safe' => [ 'date', 'text', 'select', 'balance', 'optionsList', 'checkbox', 'amount', 'tags', 'integer', 'textarea', 'location', 'multiRadio', 'file', 'multiCheckbox', 'staticText', 'amountSmall', 'password', 'nonSelectableBalance', 'nonSelectableAmount', - 'number', 'assetAccountList', + 'number', 'assetAccountList','amountNoCurrency' ], ], 'Form' => [ diff --git a/database/migrations/2018_04_07_210913_changes_for_v473.php b/database/migrations/2018_04_07_210913_changes_for_v473.php new file mode 100644 index 0000000000..02ff124d53 --- /dev/null +++ b/database/migrations/2018_04_07_210913_changes_for_v473.php @@ -0,0 +1,36 @@ +integer('currency_id', false, true)->nullable()->after('user_id'); + $table->foreign('currency_id')->references('id')->on('transaction_currencies')->onDelete('set null'); + } + ); + } +} diff --git a/resources/lang/en_US/firefly.php b/resources/lang/en_US/firefly.php index 1113f9e9d1..eff5ccca08 100644 --- a/resources/lang/en_US/firefly.php +++ b/resources/lang/en_US/firefly.php @@ -410,6 +410,14 @@ return [ 'rules_have_read_warning' => 'Have you read the warning?', 'apply_rule_warning' => 'Warning: running a rule(group) on a large selection of transactions could take ages, and it could time-out. If it does, the rule(group) will only be applied to an unknown subset of your transactions. This might leave your financial administration in tatters. Please be careful.', + 'rulegroup_for_bills_title' => 'Rule group for bills', + 'rulegroup_for_bills_description' => 'A special rule group for all the rules that involve bills.', + 'rule_for_bill_title' => 'Auto-generated rule for bill ":name"', + 'rule_for_bill_description' => 'This rule is auto-generated to try to match bill ":name".', + 'create_rule_for_bill' => 'Create a new rule for bill ":name"', + 'create_rule_for_bill_txt' => 'You have just created a new bill called ":name", congratulations! Firefly III can automagically match new withdrawals to this bill. For example, whenever you pay your rent, the bill "rent" will be linked to the expense. This way, Firefly III can accurately show you which bills are due and which ones aren\'t. In order to do so, a new rule must be created. Firefly III has filled in some sensible defaults for you. Please make sure these are correct. If these values are correct, Firefly III will automatically link the correct withdrawal to the correct bill. Please check out the triggers to see if they are correct, and add some if they\'re wrong.', + 'new_rule_for_bill_title' => 'Rule for bill ":name"', + 'new_rule_for_bill_description' => 'This rule marks transactions for bill ":name".', // tags 'store_new_tag' => 'Store new tag', diff --git a/resources/lang/en_US/intro.php b/resources/lang/en_US/intro.php index 8dba87a7cc..f5f1201be2 100644 --- a/resources/lang/en_US/intro.php +++ b/resources/lang/en_US/intro.php @@ -1,5 +1,6 @@ 'This chart shows the transactions linked to this bill.', // create bill + 'bills_create_intro' => 'Use bills to track the amount of money you\'re due every period. Think about expenses like rent, insurance or mortgage payments.', 'bills_create_name' => 'Use a descriptive name such as "Rent" or "Health insurance".', - 'bills_create_match' => 'To match transactions, use terms from those transactions or the expense account involved. All words must match.', + //'bills_create_match' => 'To match transactions, use terms from those transactions or the expense account involved. All words must match.', 'bills_create_amount_min_holder' => 'Select a minimum and maximum amount for this bill.', 'bills_create_repeat_freq_holder' => 'Most bills repeat monthly, but you can set another frequency here.', - 'bills_create_skip_holder' => 'If a bill repeats every 2 weeks for example, the "skip"-field should be set to "1" to skip every other week.', + 'bills_create_skip_holder' => 'If a bill repeats every 2 weeks, the "skip"-field should be set to "1" to skip every other week.', // rules index 'rules_index_intro' => 'Firefly III allows you to manage rules, that will automagically be applied to any transaction you create or edit.', diff --git a/resources/views/bills/create.twig b/resources/views/bills/create.twig index c7e485ef5b..4c32042a39 100644 --- a/resources/views/bills/create.twig +++ b/resources/views/bills/create.twig @@ -17,9 +17,9 @@
{{ ExpandedForm.text('name') }} - {{ ExpandedForm.tags('match') }} - {{ ExpandedForm.amount('amount_min') }} - {{ ExpandedForm.amount('amount_max') }} + {{ ExpandedForm.select('currency_id',currencies, defaultCurrency.id) }} + {{ ExpandedForm.amountNoCurrency('amount_min') }} + {{ ExpandedForm.amountNoCurrency('amount_max') }} {{ ExpandedForm.date('date',phpdate('Y-m-d')) }} {{ ExpandedForm.select('repeat_freq',periods,'monthly') }}
@@ -35,9 +35,7 @@ {{ ExpandedForm.textarea('notes',null,{helpText: trans('firefly.field_supports_markdown')}) }} {{ ExpandedForm.file('attachments[]', {'multiple': 'multiple','helpText': trans('firefly.upload_max_file_size', {'size': uploadSize|filesize}) }) }} {{ ExpandedForm.integer('skip',0) }} - {{ ExpandedForm.checkbox('automatch',1,true) }} {{ ExpandedForm.checkbox('active',1,true) }} - diff --git a/resources/views/form/amount-no-currency.twig b/resources/views/form/amount-no-currency.twig new file mode 100644 index 0000000000..005be0f54a --- /dev/null +++ b/resources/views/form/amount-no-currency.twig @@ -0,0 +1,7 @@ +
+ +
+ {{ Form.input('number', name, value, options) }} + {% include 'form/feedback' %} +
+
diff --git a/resources/views/list/bills.twig b/resources/views/list/bills.twig index 128476957b..aa1759cd3b 100644 --- a/resources/views/list/bills.twig +++ b/resources/views/list/bills.twig @@ -5,8 +5,8 @@   - {{ trans('list.name') }} - {{ trans('list.matchesOn') }} + {{ trans('list.name') }} + {{ trans('list.linked_to_rules') }} {{ trans('list.matchingAmount') }} {{ trans('list.paid_current_period') }} {{ trans('list.next_expected_match') }} @@ -42,10 +42,8 @@ {% endif %} - - {% for match in entry.match %} - {{ match }} - {% endfor %} + + (rules) diff --git a/resources/views/rules/rule/create.twig b/resources/views/rules/rule/create.twig index 5c1f3b998d..b27c2411a2 100644 --- a/resources/views/rules/rule/create.twig +++ b/resources/views/rules/rule/create.twig @@ -10,6 +10,22 @@ + {% if bill %} +
+
+
+
+

{{ trans('firefly.create_rule_for_bill', {name: bill.name}) }}

+
+
+

+ {{ trans('firefly.create_rule_for_bill_txt', {name: bill.name}) }} +

+
+
+
+
+ {% endif %}
From e597f04b0d039eeac9743f80d1fc143a73701f54 Mon Sep 17 00:00:00 2001 From: James Cole Date: Sun, 8 Apr 2018 16:17:29 +0200 Subject: [PATCH 013/117] Add debug logging. --- app/Http/Controllers/Chart/AccountController.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/Http/Controllers/Chart/AccountController.php b/app/Http/Controllers/Chart/AccountController.php index 8e417dfe58..67c81408c4 100644 --- a/app/Http/Controllers/Chart/AccountController.php +++ b/app/Http/Controllers/Chart/AccountController.php @@ -439,15 +439,17 @@ class AccountController extends Controller /** @var CurrencyRepositoryInterface $repository */ $repository = app(CurrencyRepositoryInterface::class); - $chartData = []; foreach ($accounts as $account) { + Log::debug(sprintf('Now at account #%d', $account->id)); $currency = $repository->findNull((int)$account->getMeta('currency_id')); + Log::debug(sprintf('Currency is null? %s', var_export($currency === null, true))); $currentSet = [ 'label' => $account->name, 'currency_symbol' => $currency->symbol, 'entries' => [], ]; + $currentStart = clone $start; $range = app('steam')->balanceInRange($account, $start, clone $end); $previous = array_values($range)[0]; From 5850ad06b13c498364e6ccc3bd974ccf784679ff Mon Sep 17 00:00:00 2001 From: James Cole Date: Sun, 8 Apr 2018 16:18:35 +0200 Subject: [PATCH 014/117] More debug [skip ci] --- app/Http/Controllers/Chart/AccountController.php | 1 + 1 file changed, 1 insertion(+) diff --git a/app/Http/Controllers/Chart/AccountController.php b/app/Http/Controllers/Chart/AccountController.php index 67c81408c4..cca8691431 100644 --- a/app/Http/Controllers/Chart/AccountController.php +++ b/app/Http/Controllers/Chart/AccountController.php @@ -442,6 +442,7 @@ class AccountController extends Controller $chartData = []; foreach ($accounts as $account) { Log::debug(sprintf('Now at account #%d', $account->id)); + Log::debug(sprintf('Currency preference is: %d', (int)$account->getMeta('currency_id'))); $currency = $repository->findNull((int)$account->getMeta('currency_id')); Log::debug(sprintf('Currency is null? %s', var_export($currency === null, true))); $currentSet = [ From b561e79a6c7e862fc7e20891576625cb6ac92bf2 Mon Sep 17 00:00:00 2001 From: James Cole Date: Sun, 8 Apr 2018 16:21:17 +0200 Subject: [PATCH 015/117] Catch null in currency pref. [skip ci] --- app/Http/Controllers/Chart/AccountController.php | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/app/Http/Controllers/Chart/AccountController.php b/app/Http/Controllers/Chart/AccountController.php index cca8691431..2ecbddb591 100644 --- a/app/Http/Controllers/Chart/AccountController.php +++ b/app/Http/Controllers/Chart/AccountController.php @@ -439,13 +439,14 @@ class AccountController extends Controller /** @var CurrencyRepositoryInterface $repository */ $repository = app(CurrencyRepositoryInterface::class); - $chartData = []; + $default = app('amount')->getDefaultCurrency(); + $chartData = []; foreach ($accounts as $account) { - Log::debug(sprintf('Now at account #%d', $account->id)); - Log::debug(sprintf('Currency preference is: %d', (int)$account->getMeta('currency_id'))); - $currency = $repository->findNull((int)$account->getMeta('currency_id')); - Log::debug(sprintf('Currency is null? %s', var_export($currency === null, true))); - $currentSet = [ + $currency = $repository->findNull((int)$account->getMeta('currency_id')); + if (null === $currency) { + $currency = $default; + } + $currentSet = [ 'label' => $account->name, 'currency_symbol' => $currency->symbol, 'entries' => [], From 7583698ee58aa0dd83ded6a06521d1ca91789efe Mon Sep 17 00:00:00 2001 From: James Cole Date: Sun, 8 Apr 2018 16:26:26 +0200 Subject: [PATCH 016/117] Remove hard exit from upgrade routine. --- app/Console/Commands/UpgradeDatabase.php | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/app/Console/Commands/UpgradeDatabase.php b/app/Console/Commands/UpgradeDatabase.php index 2da1ff57ed..7f437cbf47 100644 --- a/app/Console/Commands/UpgradeDatabase.php +++ b/app/Console/Commands/UpgradeDatabase.php @@ -77,7 +77,6 @@ class UpgradeDatabase extends Command */ public function handle() { - $this->migrateBillsToRules(); $this->setTransactionIdentifier(); $this->updateAccountCurrencies(); $this->createNewTypes(); @@ -87,6 +86,7 @@ class UpgradeDatabase extends Command $this->line('Done updating currency information..'); $this->migrateNotes(); $this->migrateAttachmentData(); + $this->migrateBillsToRules(); $this->info('Firefly III database is up to date.'); } @@ -100,6 +100,9 @@ class UpgradeDatabase extends Command $ruleGroup = $user->ruleGroups()->where('title', $groupName)->first(); $currencyPreference = Preferences::getForUser($user, 'currencyPreference', config('firefly.default_currency', 'EUR')); $currency = TransactionCurrency::where('code', $currencyPreference->data)->first(); + if (null === $currency) { + $currency = app('amount')->getDefaultCurrency(); + } if ($ruleGroup === null) { $array = RuleGroup::get(['order'])->pluck('order')->toArray(); @@ -190,14 +193,18 @@ class UpgradeDatabase extends Command ); $order++; - //$bill->match = 'MIGRATED_TO_RULES'; + $bill->match = 'MIGRATED_TO_RULES'; $bill->save(); $this->line(sprintf('Updated bill #%d ("%s") so it will use rules.', $bill->id, $bill->name)); } - } - $this->line('Exit'); - exit; + // give bills a currency when they dont have one. + if (null === $bill->transaction_currency_id) { + $this->line(sprintf('Gave bill #%d ("%s") a currency (%s).', $bill->id, $bill->name, $currency->name)); + $bill->transactionCurrency()->associate($currency); + $bill->save(); + } + } } } From 8f0e36a8e4e545ca7bbb4e81905c18b498c22019 Mon Sep 17 00:00:00 2001 From: James Cole Date: Sun, 8 Apr 2018 16:27:52 +0200 Subject: [PATCH 017/117] Code for #1324 --- app/Factory/BillFactory.php | 22 +- app/Http/Controllers/BillController.php | 17 +- .../Json/AutoCompleteController.php | 14 + app/Http/Controllers/RuleController.php | 287 +++++++++++------- app/Http/Requests/BillFormRequest.php | 36 +-- app/Models/Bill.php | 16 +- .../Internal/Update/BillUpdateService.php | 23 +- app/TransactionRules/Triggers/CurrencyIs.php | 92 ++++++ config/firefly.php | 5 +- config/upgrade.php | 1 + .../2018_04_07_210913_changes_for_v473.php | 4 +- public/js/ff/rules/create-edit.js | 3 + resources/lang/en_US/firefly.php | 2 + resources/lang/en_US/form.php | 2 + resources/views/bills/create.twig | 2 +- resources/views/bills/edit.twig | 7 +- resources/views/rules/rule/create.twig | 6 +- routes/web.php | 3 +- 18 files changed, 377 insertions(+), 165 deletions(-) create mode 100644 app/TransactionRules/Triggers/CurrencyIs.php diff --git a/app/Factory/BillFactory.php b/app/Factory/BillFactory.php index e8522f6842..28b4a3544d 100644 --- a/app/Factory/BillFactory.php +++ b/app/Factory/BillFactory.php @@ -48,17 +48,17 @@ class BillFactory /** @var Bill $bill */ $bill = Bill::create( [ - 'name' => $data['name'], - 'match' => 'MIGRATED_TO_RULES', - 'amount_min' => $data['amount_min'], - 'user_id' => $this->user->id, - 'currency_id' => $data['currency_id'], - 'amount_max' => $data['amount_max'], - 'date' => $data['date'], - 'repeat_freq' => $data['repeat_freq'], - 'skip' => $data['skip'], - 'automatch' => true, - 'active' => $data['active'], + 'name' => $data['name'], + 'match' => 'MIGRATED_TO_RULES', + 'amount_min' => $data['amount_min'], + 'user_id' => $this->user->id, + 'transaction_currency_id' => $data['transaction_currency_id'], + 'amount_max' => $data['amount_max'], + 'date' => $data['date'], + 'repeat_freq' => $data['repeat_freq'], + 'skip' => $data['skip'], + 'automatch' => true, + 'active' => $data['active'], ] ); diff --git a/app/Http/Controllers/BillController.php b/app/Http/Controllers/BillController.php index 45e4a6293d..29b4770bdb 100644 --- a/app/Http/Controllers/BillController.php +++ b/app/Http/Controllers/BillController.php @@ -136,7 +136,7 @@ class BillController extends Controller * * @return View */ - public function edit(Request $request, Bill $bill) + public function edit(Request $request, CurrencyRepositoryInterface $repository, Bill $bill) { $periods = []; foreach (config('firefly.bill_periods') as $current) { @@ -152,6 +152,8 @@ class BillController extends Controller $currency = app('amount')->getDefaultCurrency(); $bill->amount_min = round($bill->amount_min, $currency->decimal_places); $bill->amount_max = round($bill->amount_max, $currency->decimal_places); + $defaultCurrency = app('amount')->getDefaultCurrency(); + $currencies = ExpandedForm::makeSelectList($repository->get()); $preFilled = [ 'notes' => '', @@ -167,7 +169,7 @@ class BillController extends Controller $request->session()->forget('bills.edit.fromUpdate'); - return view('bills.edit', compact('subTitle', 'periods', 'bill')); + return view('bills.edit', compact('subTitle', 'periods', 'bill', 'defaultCurrency', 'currencies')); } /** @@ -296,6 +298,12 @@ class BillController extends Controller $request->session()->flash('info', $this->attachments->getMessages()->get('attachments')); // @codeCoverageIgnore } + // do return to original bill form? + $return = 'false'; + if (1 === (int)$request->get('create_another')) { + $return = 'true'; + } + // find first rule group, or create one: $count = $ruleGroupRepository->count(); if ($count === 0) { @@ -309,9 +317,10 @@ class BillController extends Controller $group = $ruleGroupRepository->getActiveGroups(auth()->user())->first(); } - // redirect to page that will create a new rule. - return redirect(route('rules.create', [$group->id]) . '?fromBill=' . $bill->id); + $params = http_build_query(['fromBill' => $bill->id, 'return' => $return]); + + return redirect(route('rules.create', [$group->id]) . '?' . $params); } /** diff --git a/app/Http/Controllers/Json/AutoCompleteController.php b/app/Http/Controllers/Json/AutoCompleteController.php index ef8dbb2b76..b01069520e 100644 --- a/app/Http/Controllers/Json/AutoCompleteController.php +++ b/app/Http/Controllers/Json/AutoCompleteController.php @@ -31,6 +31,7 @@ use FireflyIII\Repositories\Account\AccountRepositoryInterface; use FireflyIII\Repositories\Bill\BillRepositoryInterface; use FireflyIII\Repositories\Budget\BudgetRepositoryInterface; use FireflyIII\Repositories\Category\CategoryRepositoryInterface; +use FireflyIII\Repositories\Currency\CurrencyRepositoryInterface; use FireflyIII\Repositories\Journal\JournalRepositoryInterface; use FireflyIII\Repositories\Tag\TagRepositoryInterface; use FireflyIII\Support\CacheProperties; @@ -119,6 +120,19 @@ class AutoCompleteController extends Controller return response()->json($return); } + /** + * @param CurrencyRepositoryInterface $repository + * + * @return \Illuminate\Http\JsonResponse + */ + public function currencyNames(CurrencyRepositoryInterface $repository) + { + $return = $repository->get()->pluck('name')->toArray(); + sort($return); + + return response()->json($return); + } + /** * Returns a JSON list of all beneficiaries. * diff --git a/app/Http/Controllers/RuleController.php b/app/Http/Controllers/RuleController.php index 21c0ae694c..f4be740679 100644 --- a/app/Http/Controllers/RuleController.php +++ b/app/Http/Controllers/RuleController.php @@ -29,6 +29,7 @@ use FireflyIII\Http\Requests\SelectTransactionsRequest; use FireflyIII\Http\Requests\TestRuleFormRequest; use FireflyIII\Jobs\ExecuteRuleOnExistingTransactions; use FireflyIII\Models\AccountType; +use FireflyIII\Models\Bill; use FireflyIII\Models\Rule; use FireflyIII\Models\RuleAction; use FireflyIII\Models\RuleGroup; @@ -39,8 +40,10 @@ use FireflyIII\Repositories\Rule\RuleRepositoryInterface; use FireflyIII\Repositories\RuleGroup\RuleGroupRepositoryInterface; use FireflyIII\TransactionRules\TransactionMatcher; use Illuminate\Http\Request; +use Log; use Preferences; use Session; +use Throwable; use View; /** @@ -73,81 +76,47 @@ class RuleController extends Controller * * @return View * - - */ public function create(Request $request, RuleGroupRepositoryInterface $ruleGroupRepository, BillRepositoryInterface $billRepository, RuleGroup $ruleGroup) { - $bill = null; - $billId = (int)$request->get('fromBill'); - $preFilled = []; - // count for possible present previous entered triggers/actions. - $triggerCount = 0; - $actionCount = 0; + $bill = null; + $billId = (int)$request->get('fromBill'); + $preFilled = []; + $groups = ExpandedForm::makeSelectList($ruleGroupRepository->get()); + $oldTriggers = []; + $oldActions = []; + $returnToBill = false; - // collection of those triggers/actions. - $oldTriggers = []; - $oldActions = []; + if ($request->get('return') === 'true') { + $returnToBill = true; + } + + // has bill? + if ($billId > 0) { + $bill = $billRepository->find($billId); + } // has old input? if ($request->old()) { - // process old triggers. - $oldTriggers = $this->getPreviousTriggers($request); - $triggerCount = \count($oldTriggers); - - // process old actions + $oldTriggers = $this->getPreviousTriggers($request); $oldActions = $this->getPreviousActions($request); - $actionCount = \count($oldActions); + } - if ($billId > 0) { - $bill = $billRepository->find($billId); + // has existing bill refered to in URI? + if (null !== $bill && !$request->old()) { + // create some sensible defaults: $preFilled['title'] = trans('firefly.new_rule_for_bill_title', ['name' => $bill->name]); $preFilled['description'] = trans('firefly.new_rule_for_bill_description', ['name' => $bill->name]); $request->session()->flash('preFilled', $preFilled); - // pretend there are old triggers, so the page will fill them in: - $oldTriggers[] = view( - 'rules.partials.trigger', - [ - 'oldTrigger' => 'amount_more', - 'oldValue' => round($bill->amount_min,12), - 'oldChecked' => false, - 'count' => 1, - ] - )->render(); - $oldTriggers[] = view( - 'rules.partials.trigger', - [ - 'oldTrigger' => 'amount_less', - 'oldValue' => round($bill->amount_max,12), - 'oldChecked' => false, - 'count' => 2, - ] - )->render(); - $oldTriggers[] = view( - 'rules.partials.trigger', - [ - 'oldTrigger' => 'description_contains', - 'oldValue' => $bill->name,12, - 'oldChecked' => false, - 'count' => 3, - ] - )->render(); - - $oldActions[] = view( - 'rules.partials.action', - [ - 'oldAction' => 'link_to_bill', - 'oldValue' => $bill->name, - 'oldChecked' => false, - 'count' => 1, - ] - )->render(); - + // get triggers and actions for bill: + $oldTriggers = $this->getTriggersForBill($bill); + $oldActions = $this->getActionsForBill($bill); } - + $triggerCount = \count($oldTriggers); + $actionCount = \count($oldActions); $subTitleIcon = 'fa-clone'; $subTitle = trans('firefly.make_new_rule', ['title' => $ruleGroup->title]); @@ -159,7 +128,10 @@ class RuleController extends Controller return view( 'rules.rule.create', - compact('subTitleIcon', 'oldTriggers', 'preFilled', 'bill', 'oldActions', 'triggerCount', 'actionCount', 'ruleGroup', 'subTitle') + compact( + 'subTitleIcon', 'oldTriggers', 'returnToBill', 'groups', 'preFilled', 'bill', 'oldActions', 'triggerCount', 'actionCount', 'ruleGroup', + 'subTitle' + ) ); } @@ -380,24 +352,32 @@ class RuleController extends Controller /** * @param RuleFormRequest $request * @param RuleRepositoryInterface $repository - * @param RuleGroup $ruleGroup * * @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector */ - public function store(RuleFormRequest $request, RuleRepositoryInterface $repository, RuleGroup $ruleGroup) + public function store(RuleFormRequest $request, RuleRepositoryInterface $repository) { - $data = $request->getRuleData(); - $data['rule_group_id'] = $ruleGroup->id; - + $data = $request->getRuleData(); $rule = $repository->store($data); - Session::flash('success', trans('firefly.stored_new_rule', ['title' => $rule->title])); + session()->flash('success', trans('firefly.stored_new_rule', ['title' => $rule->title])); Preferences::mark(); + // redirect to show bill. + if ($request->get('return_to_bill') === 'true' && (int)$request->get('bill_id') > 0) { + return redirect(route('bills.show', [(int)$request->get('bill_id')])); + } + + // redirect to new bill creation. + if ((int)$request->get('bill_id') > 0) { + return redirect(route('bills.create')); + } + + if (1 === (int)$request->get('create_another')) { // @codeCoverageIgnoreStart Session::put('rules.create.fromStore', true); - return redirect(route('rules.create', [$ruleGroup]))->withInput(); + return redirect(route('rules.create', [$data['rule_group_id']]))->withInput(); // @codeCoverageIgnoreEnd } @@ -416,7 +396,6 @@ class RuleController extends Controller * * @return \Illuminate\Http\JsonResponse * - */ public function testTriggers(TestRuleFormRequest $request) { @@ -586,6 +565,31 @@ class RuleController extends Controller } } + /** + * @param Bill $bill + * + * @return array + */ + private function getActionsForBill(Bill $bill): array + { + $actions = []; + try { + $actions[] = view( + 'rules.partials.action', + [ + 'oldAction' => 'link_to_bill', + 'oldValue' => $bill->name, + 'oldChecked' => false, + 'count' => 1, + ] + )->render(); + } catch (Throwable $e) { + Log::debug(sprintf('Throwable was thrown in getActionsForBill(): %s', $e->getMessage())); + } + + return $actions; + } + /** * @param Rule $rule * @@ -600,16 +604,20 @@ class RuleController extends Controller /** @var RuleAction $entry */ foreach ($rule->ruleActions as $entry) { - $count = ($index + 1); - $actions[] = view( - 'rules.partials.action', - [ - 'oldAction' => $entry->action_type, - 'oldValue' => $entry->action_value, - 'oldChecked' => $entry->stop_processing, - 'count' => $count, - ] - )->render(); + $count = ($index + 1); + try { + $actions[] = view( + 'rules.partials.action', + [ + 'oldAction' => $entry->action_type, + 'oldValue' => $entry->action_value, + 'oldChecked' => $entry->stop_processing, + 'count' => $count, + ] + )->render(); + } catch (Throwable $e) { + Log::debug(sprintf('Throwable was thrown in getCurrentActions(): %s', $e->getMessage())); + } ++$index; } @@ -631,16 +639,20 @@ class RuleController extends Controller /** @var RuleTrigger $entry */ foreach ($rule->ruleTriggers as $entry) { if ('user_action' !== $entry->trigger_type) { - $count = ($index + 1); - $triggers[] = view( - 'rules.partials.trigger', - [ - 'oldTrigger' => $entry->trigger_type, - 'oldValue' => $entry->trigger_value, - 'oldChecked' => $entry->stop_processing, - 'count' => $count, - ] - )->render(); + $count = ($index + 1); + try { + $triggers[] = view( + 'rules.partials.trigger', + [ + 'oldTrigger' => $entry->trigger_type, + 'oldValue' => $entry->trigger_value, + 'oldChecked' => $entry->stop_processing, + 'count' => $count, + ] + )->render(); + } catch (Throwable $e) { + Log::debug(sprintf('Throwable was thrown in getCurrentTriggers(): %s', $e->getMessage())); + } ++$index; } } @@ -662,17 +674,21 @@ class RuleController extends Controller /** @var array $oldActions */ $oldActions = is_array($request->old('rule-action')) ? $request->old('rule-action') : []; foreach ($oldActions as $index => $entry) { - $count = ($newIndex + 1); - $checked = isset($request->old('rule-action-stop')[$index]) ? true : false; - $actions[] = view( - 'rules.partials.action', - [ - 'oldAction' => $entry, - 'oldValue' => $request->old('rule-action-value')[$index], - 'oldChecked' => $checked, - 'count' => $count, - ] - )->render(); + $count = ($newIndex + 1); + $checked = isset($request->old('rule-action-stop')[$index]) ? true : false; + try { + $actions[] = view( + 'rules.partials.action', + [ + 'oldAction' => $entry, + 'oldValue' => $request->old('rule-action-value')[$index], + 'oldChecked' => $checked, + 'count' => $count, + ] + )->render(); + } catch (Throwable $e) { + Log::debug(sprintf('Throwable was thrown in getPreviousActions(): %s', $e->getMessage())); + } ++$newIndex; } @@ -695,16 +711,77 @@ class RuleController extends Controller foreach ($oldTriggers as $index => $entry) { $count = ($newIndex + 1); $oldChecked = isset($request->old('rule-trigger-stop')[$index]) ? true : false; + try { + $triggers[] = view( + 'rules.partials.trigger', + [ + 'oldTrigger' => $entry, + 'oldValue' => $request->old('rule-trigger-value')[$index], + 'oldChecked' => $oldChecked, + 'count' => $count, + ] + )->render(); + } catch (Throwable $e) { + Log::debug(sprintf('Throwable was thrown in getPreviousTriggers(): %s', $e->getMessage())); + } + ++$newIndex; + } + + return $triggers; + } + + /** + * Create fake triggers to match the bill's properties + * + * @param Bill $bill + * + * @return array + */ + private function getTriggersForBill(Bill $bill): array + { + $triggers = []; + try { $triggers[] = view( 'rules.partials.trigger', [ - 'oldTrigger' => $entry, - 'oldValue' => $request->old('rule-trigger-value')[$index], - 'oldChecked' => $oldChecked, - 'count' => $count, + 'oldTrigger' => 'currency_is', + 'oldValue' => $bill->transactionCurrency()->first()->name, + 'oldChecked' => false, + 'count' => 1, ] )->render(); - ++$newIndex; + + $triggers[] = view( + 'rules.partials.trigger', + [ + 'oldTrigger' => 'amount_more', + 'oldValue' => round($bill->amount_min, 12), + 'oldChecked' => false, + 'count' => 2, + ] + )->render(); + + $triggers[] = view( + 'rules.partials.trigger', + [ + 'oldTrigger' => 'amount_less', + 'oldValue' => round($bill->amount_max, 12), + 'oldChecked' => false, + 'count' => 3, + ] + )->render(); + $triggers[] = view( + 'rules.partials.trigger', + [ + 'oldTrigger' => 'description_contains', + 'oldValue' => $bill->name, 12, + 'oldChecked' => false, + 'count' => 4, + ] + )->render(); + } catch (Throwable $e) { + Log::debug(sprintf('Throwable was thrown in getTriggersForBill(): %s', $e->getMessage())); + Log::debug($e->getTraceAsString()); } return $triggers; @@ -723,7 +800,7 @@ class RuleController extends Controller 'rule-trigger-values' => $request->get('rule-trigger-value'), 'rule-trigger-stop' => $request->get('rule-trigger-stop'), ]; - if (is_array($data['rule-triggers'])) { + if (\is_array($data['rule-triggers'])) { foreach ($data['rule-triggers'] as $index => $triggerType) { $data['rule-trigger-stop'][$index] = (int)($data['rule-trigger-stop'][$index] ?? 0.0); $triggers[] = [ diff --git a/app/Http/Requests/BillFormRequest.php b/app/Http/Requests/BillFormRequest.php index e8e3677e41..7b0b54083f 100644 --- a/app/Http/Requests/BillFormRequest.php +++ b/app/Http/Requests/BillFormRequest.php @@ -42,15 +42,15 @@ class BillFormRequest extends Request public function getBillData() { return [ - 'name' => $this->string('name'), - 'amount_min' => $this->string('amount_min'), - 'currency_id' => $this->integer('currency_id'), - 'amount_max' => $this->string('amount_max'), - 'date' => $this->date('date'), - 'repeat_freq' => $this->string('repeat_freq'), - 'skip' => $this->integer('skip'), - 'active' => $this->boolean('active'), - 'notes' => $this->string('notes'), + 'name' => $this->string('name'), + 'amount_min' => $this->string('amount_min'), + 'transaction_currency_id' => $this->integer('transaction_currency_id'), + 'amount_max' => $this->string('amount_max'), + 'date' => $this->date('date'), + 'repeat_freq' => $this->string('repeat_freq'), + 'skip' => $this->integer('skip'), + 'active' => $this->boolean('active'), + 'notes' => $this->string('notes'), ]; } @@ -66,15 +66,15 @@ class BillFormRequest extends Request } // is OK $rules = [ - 'name' => $nameRule, - 'amount_min' => 'required|numeric|more:0', - 'amount_max' => 'required|numeric|more:0', - 'currency_id' => 'required|exists:transaction_currencies,id', - 'date' => 'required|date', - 'repeat_freq' => 'required|in:weekly,monthly,quarterly,half-year,yearly', - 'skip' => 'required|between:0,31', - 'automatch' => 'in:1', - 'active' => 'in:1', + 'name' => $nameRule, + 'amount_min' => 'required|numeric|more:0', + 'amount_max' => 'required|numeric|more:0', + 'transaction_currency_id' => 'required|exists:transaction_currencies,id', + 'date' => 'required|date', + 'repeat_freq' => 'required|in:weekly,monthly,quarterly,half-year,yearly', + 'skip' => 'required|between:0,31', + 'automatch' => 'in:1', + 'active' => 'in:1', ]; return $rules; diff --git a/app/Models/Bill.php b/app/Models/Bill.php index d8513b60d6..73e5d93b49 100644 --- a/app/Models/Bill.php +++ b/app/Models/Bill.php @@ -23,6 +23,7 @@ declare(strict_types=1); namespace FireflyIII\Models; use Crypt; +use FireflyIII\User; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Database\Eloquent\Relations\HasMany; @@ -57,7 +58,7 @@ class Bill extends Model */ protected $fillable = ['name', 'match', 'amount_min', 'match_encrypted', 'name_encrypted', 'user_id', 'amount_max', 'date', 'repeat_freq', 'skip', - 'automatch', 'active','currency_id']; + 'automatch', 'active', 'transaction_currency_id']; /** * @var array */ @@ -179,13 +180,22 @@ class Bill extends Model $this->attributes['name_encrypted'] = $encrypt; } + /** + * @codeCoverageIgnore + * @return BelongsTo + */ + public function transactionCurrency(): BelongsTo + { + return $this->belongsTo(TransactionCurrency::class); + } + /** * @codeCoverageIgnore * @return HasMany */ public function transactionJournals(): HasMany { - return $this->hasMany('FireflyIII\Models\TransactionJournal'); + return $this->hasMany(TransactionJournal::class); } /** @@ -194,6 +204,6 @@ class Bill extends Model */ public function user(): BelongsTo { - return $this->belongsTo('FireflyIII\User'); + return $this->belongsTo(User::class); } } diff --git a/app/Services/Internal/Update/BillUpdateService.php b/app/Services/Internal/Update/BillUpdateService.php index 69cf09f38d..34edc0c92f 100644 --- a/app/Services/Internal/Update/BillUpdateService.php +++ b/app/Services/Internal/Update/BillUpdateService.php @@ -42,20 +42,15 @@ class BillUpdateService */ public function update(Bill $bill, array $data): Bill { - - $matchArray = explode(',', $data['match']); - $matchArray = array_unique($matchArray); - $match = implode(',', $matchArray); - - $bill->name = $data['name']; - $bill->match = $match; - $bill->amount_min = $data['amount_min']; - $bill->amount_max = $data['amount_max']; - $bill->date = $data['date']; - $bill->repeat_freq = $data['repeat_freq']; - $bill->skip = $data['skip']; - $bill->automatch = $data['automatch']; - $bill->active = $data['active']; + $bill->name = $data['name']; + $bill->amount_min = $data['amount_min']; + $bill->amount_max = $data['amount_max']; + $bill->date = $data['date']; + $bill->transaction_currency_id = $data['transaction_currency_id']; + $bill->repeat_freq = $data['repeat_freq']; + $bill->skip = $data['skip']; + $bill->automatch = true; + $bill->active = $data['active']; $bill->save(); // update note: diff --git a/app/TransactionRules/Triggers/CurrencyIs.php b/app/TransactionRules/Triggers/CurrencyIs.php new file mode 100644 index 0000000000..120a938ea0 --- /dev/null +++ b/app/TransactionRules/Triggers/CurrencyIs.php @@ -0,0 +1,92 @@ +. + */ +declare(strict_types=1); + +namespace FireflyIII\TransactionRules\Triggers; + +use FireflyIII\Models\Transaction; +use FireflyIII\Models\TransactionJournal; +use FireflyIII\Repositories\Currency\CurrencyRepositoryInterface; +use Log; + +/** + * Class CurrencyIs. + */ +final class CurrencyIs extends AbstractTrigger implements TriggerInterface +{ + /** + * A trigger is said to "match anything", or match any given transaction, + * when the trigger value is very vague or has no restrictions. Easy examples + * are the "AmountMore"-trigger combined with an amount of 0: any given transaction + * has an amount of more than zero! Other examples are all the "Description"-triggers + * which have hard time handling empty trigger values such as "" or "*" (wild cards). + * + * If the user tries to create such a trigger, this method MUST return true so Firefly III + * can stop the storing / updating the trigger. If the trigger is in any way restrictive + * (even if it will still include 99.9% of the users transactions), this method MUST return + * false. + * + * @param null $value + * + * @return bool + */ + public static function willMatchEverything($value = null) + { + if (null !== $value) { + return false; + } + + Log::error(sprintf('Cannot use %s with a null value.', self::class)); + + return true; + } + + /** + * Returns true when description is X + * + * @param TransactionJournal $journal + * + * @return bool + */ + public function triggered(TransactionJournal $journal): bool + { + /** @var CurrencyRepositoryInterface $repository */ + $repository = app(CurrencyRepositoryInterface::class); + $currency = $repository->findByNameNull($this->triggerValue); + $hit = true; + if (null !== $currency) { + /** @var Transaction $transaction */ + foreach ($journal->transactions as $transaction) { + if ((int)$transaction->transaction_currency_id !== (int)$currency->id) { + Log::debug( + sprintf( + 'Trigger CurrencyIs: Transaction #%d in journal #%d uses currency %d instead of sought for #%d. No hit!', + $transaction->id, $journal->id, $transaction->transaction_currency_id, $currency->id + ) + ); + $hit = false; + } + } + } + + return $hit; + } +} diff --git a/config/firefly.php b/config/firefly.php index c23585c017..7d0f8c530d 100644 --- a/config/firefly.php +++ b/config/firefly.php @@ -25,6 +25,7 @@ use FireflyIII\TransactionRules\Triggers\AmountLess; use FireflyIII\TransactionRules\Triggers\AmountMore; use FireflyIII\TransactionRules\Triggers\BudgetIs; use FireflyIII\TransactionRules\Triggers\CategoryIs; +use FireflyIII\TransactionRules\Triggers\CurrencyIs; use FireflyIII\TransactionRules\Triggers\DescriptionContains; use FireflyIII\TransactionRules\Triggers\DescriptionEnds; use FireflyIII\TransactionRules\Triggers\DescriptionIs; @@ -89,7 +90,7 @@ return [ 'encryption' => null === env('USE_ENCRYPTION') || env('USE_ENCRYPTION') === true, 'version' => '4.7.2.2', 'api_version' => '0.1', - 'db_version' => 2, + 'db_version' => 3, 'maxUploadSize' => 15242880, 'allowedMimes' => [ /* plain files */ @@ -324,6 +325,7 @@ return [ 'category_is' => CategoryIs::class, 'budget_is' => BudgetIs::class, 'tag_is' => TagIs::class, + 'currency_is' => CurrencyIs::class, 'has_attachments' => HasAttachment::class, 'has_no_category' => HasNoCategory::class, 'has_any_category' => HasAnyCategory::class, @@ -362,6 +364,7 @@ return [ 'set_budget', 'add_tag', 'remove_tag', + 'link_to_bill', 'set_description', 'append_description', 'prepend_description', diff --git a/config/upgrade.php b/config/upgrade.php index 7164d9991d..afdc4a4f88 100644 --- a/config/upgrade.php +++ b/config/upgrade.php @@ -28,6 +28,7 @@ return [ '4.3' => 'Make sure you run the migrations and clear your cache. If you need more help, please check Github or the Firefly III website.', '4.6.3' => 'This will be the last version to require PHP7.0. Future versions will require PHP7.1 minimum.', '4.6.4' => 'This version of Firefly III requires PHP7.1.', + '4.7.3' => 'This version of Firefly III handles bills differently. See https://goo.gl/zkVdrF for more information.', ], 'install' => [ diff --git a/database/migrations/2018_04_07_210913_changes_for_v473.php b/database/migrations/2018_04_07_210913_changes_for_v473.php index 02ff124d53..abeee6eae6 100644 --- a/database/migrations/2018_04_07_210913_changes_for_v473.php +++ b/database/migrations/2018_04_07_210913_changes_for_v473.php @@ -28,8 +28,8 @@ class ChangesForV473 extends Migration Schema::table( 'bills', function (Blueprint $table) { - $table->integer('currency_id', false, true)->nullable()->after('user_id'); - $table->foreign('currency_id')->references('id')->on('transaction_currencies')->onDelete('set null'); + $table->integer('transaction_currency_id', false, true)->nullable()->after('user_id'); + $table->foreign('transaction_currency_id')->references('id')->on('transaction_currencies')->onDelete('set null'); } ); } diff --git a/public/js/ff/rules/create-edit.js b/public/js/ff/rules/create-edit.js index a9b5ed0e86..ef859e255c 100644 --- a/public/js/ff/rules/create-edit.js +++ b/public/js/ff/rules/create-edit.js @@ -285,6 +285,9 @@ function updateTriggerInput(selectList) { input.prop('disabled', true); input.typeahead('destroy'); break; + case 'currency_is': + createAutoComplete(input, 'json/currency-names'); + break; default: input.typeahead('destroy'); break; diff --git a/resources/lang/en_US/firefly.php b/resources/lang/en_US/firefly.php index eff5ccca08..162a18e399 100644 --- a/resources/lang/en_US/firefly.php +++ b/resources/lang/en_US/firefly.php @@ -345,6 +345,8 @@ return [ 'rule_trigger_budget_is' => 'Budget is ":trigger_value"', 'rule_trigger_tag_is_choice' => '(A) tag is..', 'rule_trigger_tag_is' => 'A tag is ":trigger_value"', + 'rule_trigger_currency_is_choice' => 'Transaction currency is..', + 'rule_trigger_currency_is' => 'Transaction currency is ":trigger_value"', 'rule_trigger_has_attachments_choice' => 'Has at least this many attachments', 'rule_trigger_has_attachments' => 'Has at least :trigger_value attachment(s)', 'rule_trigger_store_journal' => 'When a transaction is created', diff --git a/resources/lang/en_US/form.php b/resources/lang/en_US/form.php index 4c132ced51..23b88d81d6 100644 --- a/resources/lang/en_US/form.php +++ b/resources/lang/en_US/form.php @@ -1,5 +1,6 @@ 'Repeats', 'journal_currency_id' => 'Currency', 'currency_id' => 'Currency', + 'transaction_currency_id' => 'Currency', 'attachments' => 'Attachments', 'journal_amount' => 'Amount', 'journal_source_account_name' => 'Revenue account (source)', diff --git a/resources/views/bills/create.twig b/resources/views/bills/create.twig index 4c32042a39..a2663bff18 100644 --- a/resources/views/bills/create.twig +++ b/resources/views/bills/create.twig @@ -17,7 +17,7 @@
{{ ExpandedForm.text('name') }} - {{ ExpandedForm.select('currency_id',currencies, defaultCurrency.id) }} + {{ ExpandedForm.select('transaction_currency_id',currencies, defaultCurrency.id) }} {{ ExpandedForm.amountNoCurrency('amount_min') }} {{ ExpandedForm.amountNoCurrency('amount_max') }} {{ ExpandedForm.date('date',phpdate('Y-m-d')) }} diff --git a/resources/views/bills/edit.twig b/resources/views/bills/edit.twig index 583a7a2733..e64d063905 100644 --- a/resources/views/bills/edit.twig +++ b/resources/views/bills/edit.twig @@ -18,9 +18,9 @@
{{ ExpandedForm.text('name') }} - {{ ExpandedForm.tags('match') }} - {{ ExpandedForm.amount('amount_min') }} - {{ ExpandedForm.amount('amount_max') }} + {{ ExpandedForm.select('transaction_currency_id',currencies) }} + {{ ExpandedForm.amountNoCurrency('amount_min') }} + {{ ExpandedForm.amountNoCurrency('amount_max') }} {{ ExpandedForm.date('date',bill.date.format('Y-m-d')) }} {{ ExpandedForm.select('repeat_freq',periods) }}
@@ -37,7 +37,6 @@ {{ ExpandedForm.textarea('notes',null,{helpText: trans('firefly.field_supports_markdown')}) }} {{ ExpandedForm.file('attachments[]', {'multiple': 'multiple','helpText': trans('firefly.upload_max_file_size', {'size': uploadSize|filesize}) }) }} {{ ExpandedForm.integer('skip') }} - {{ ExpandedForm.checkbox('automatch',1) }} {{ ExpandedForm.checkbox('active',1) }}
diff --git a/resources/views/rules/rule/create.twig b/resources/views/rules/rule/create.twig index b27c2411a2..1fddf8f2af 100644 --- a/resources/views/rules/rule/create.twig +++ b/resources/views/rules/rule/create.twig @@ -6,9 +6,12 @@ {% block content %} -
+ + + + {% if bill %}
@@ -35,6 +38,7 @@
{{ ExpandedForm.text('title') }} {{ ExpandedForm.select('trigger',allJournalTriggers()) }} + {{ ExpandedForm.select('rule_group_id',groups, ruleGroup.id) }} {{ ExpandedForm.checkbox('stop_processing',1,null, {helpText: trans('firefly.rule_help_stop_processing')}) }}
diff --git a/routes/web.php b/routes/web.php index 9c156f7e6a..a7c91ce196 100755 --- a/routes/web.php +++ b/routes/web.php @@ -501,6 +501,7 @@ Route::group( Route::get('budgets', ['uses' => 'Json\AutoCompleteController@budgets', 'as' => 'budgets']); Route::get('tags', ['uses' => 'Json\AutoCompleteController@tags', 'as' => 'tags']); Route::get('bills', ['uses' => 'Json\AutoCompleteController@bills', 'as' => 'bills']); + Route::get('currency-names', ['uses' => 'Json\AutoCompleteController@currencyNames', 'as' => 'currency-names']); Route::get('transaction-journals/all', ['uses' => 'Json\AutoCompleteController@allTransactionJournals', 'as' => 'all-transaction-journals']); Route::get('transaction-journals/with-id/{tj}', ['uses' => 'Json\AutoCompleteController@journalsWithId', 'as' => 'journals-with-id']); Route::get('transaction-journals/{what}', ['uses' => 'Json\AutoCompleteController@transactionJournals', 'as' => 'transaction-journals']); @@ -723,7 +724,7 @@ Route::group( Route::post('trigger/order/{rule}', ['uses' => 'RuleController@reorderRuleTriggers', 'as' => 'reorder-triggers']); Route::post('action/order/{rule}', ['uses' => 'RuleController@reorderRuleActions', 'as' => 'reorder-actions']); - Route::post('store/{ruleGroup}', ['uses' => 'RuleController@store', 'as' => 'store']); + Route::post('store', ['uses' => 'RuleController@store', 'as' => 'store']); Route::post('update/{rule}', ['uses' => 'RuleController@update', 'as' => 'update']); Route::post('destroy/{rule}', ['uses' => 'RuleController@destroy', 'as' => 'destroy']); Route::post('execute/{rule}', ['uses' => 'RuleController@execute', 'as' => 'execute']); From 3fbd2f93c8521a1d7a06112158fa1c74febbb34a Mon Sep 17 00:00:00 2001 From: James Cole Date: Sun, 8 Apr 2018 17:36:37 +0200 Subject: [PATCH 018/117] Code for #1324 --- app/Console/Commands/UpgradeDatabase.php | 6 ++-- app/Http/Controllers/BillController.php | 10 +++++++ app/Http/Controllers/RuleController.php | 2 +- app/Repositories/Bill/BillRepository.php | 29 +++++++++++++++++++ .../Bill/BillRepositoryInterface.php | 12 ++++++++ resources/views/list/bills.twig | 14 ++++++--- 6 files changed, 66 insertions(+), 7 deletions(-) diff --git a/app/Console/Commands/UpgradeDatabase.php b/app/Console/Commands/UpgradeDatabase.php index 7f437cbf47..d842c27ce1 100644 --- a/app/Console/Commands/UpgradeDatabase.php +++ b/app/Console/Commands/UpgradeDatabase.php @@ -119,9 +119,11 @@ class UpgradeDatabase extends Command } // loop bills. - $order = 1; + $order = 1; + /** @var Collection $collection */ + $collection = $user->bills()->where('active', 1)->get(); /** @var Bill $bill */ - foreach ($user->bills()->get() as $bill) { + foreach ($collection as $bill) { if ($bill->match !== 'MIGRATED_TO_RULES') { $rule = Rule::create( [ diff --git a/app/Http/Controllers/BillController.php b/app/Http/Controllers/BillController.php index 29b4770bdb..3f020a4e27 100644 --- a/app/Http/Controllers/BillController.php +++ b/app/Http/Controllers/BillController.php @@ -199,6 +199,16 @@ class BillController extends Controller } ); + // add info about rules: + $rules = $repository->getRulesForBills($paginator->getCollection()); + $bills = $bills->map( + function (array $bill) use ($rules) { + $bill['rules'] = $rules[$bill['id']] ?? []; + + return $bill; + } + ); + $paginator->setPath(route('bills.index')); return view('bills.index', compact('bills', 'paginator')); diff --git a/app/Http/Controllers/RuleController.php b/app/Http/Controllers/RuleController.php index f4be740679..87be71d5d0 100644 --- a/app/Http/Controllers/RuleController.php +++ b/app/Http/Controllers/RuleController.php @@ -369,7 +369,7 @@ class RuleController extends Controller // redirect to new bill creation. if ((int)$request->get('bill_id') > 0) { - return redirect(route('bills.create')); + return redirect($this->getPreviousUri('bills.create.uri')); } diff --git a/app/Repositories/Bill/BillRepository.php b/app/Repositories/Bill/BillRepository.php index cba39e1599..14fb2f4bf8 100644 --- a/app/Repositories/Bill/BillRepository.php +++ b/app/Repositories/Bill/BillRepository.php @@ -367,6 +367,35 @@ class BillRepository implements BillRepositoryInterface return $journals; } + /** + * Return all rules related to the bills in the collection, in an associative array: + * 5= billid + * + * 5 => [['id' => 1, 'title' => 'Some rule'],['id' => 2, 'title' => 'Some other rule']] + * + * @param Collection $collection + * + * @return array + */ + public function getRulesForBills(Collection $collection): array + { + $rules = $this->user->rules() + ->leftJoin('rule_actions', 'rule_actions.rule_id', '=', 'rules.id') + ->where('rule_actions.action_type', 'link_to_bill') + ->get(['rules.id', 'rules.title', 'rule_actions.action_value']); + $array = []; + foreach ($rules as $rule) { + $array[$rule->action_value] = $array[$rule->action_value] ?? []; + $array[$rule->action_value][] = ['id' => $rule->id, 'title' => $rule->title]; + } + $return = []; + foreach ($collection as $bill) { + $return[$bill->id] = $array[$bill->name] ?? []; + } + + return $return; + } + /** * @param Bill $bill * @param Carbon $date diff --git a/app/Repositories/Bill/BillRepositoryInterface.php b/app/Repositories/Bill/BillRepositoryInterface.php index cd4bfe3cd7..19cd785ace 100644 --- a/app/Repositories/Bill/BillRepositoryInterface.php +++ b/app/Repositories/Bill/BillRepositoryInterface.php @@ -140,6 +140,18 @@ interface BillRepositoryInterface */ public function getPossiblyRelatedJournals(Bill $bill): Collection; + /** + * Return all rules related to the bills in the collection, in an associative array: + * 5= billid + * + * 5 => [['id' => 1, 'title' => 'Some rule'],['id' => 2, 'title' => 'Some other rule']] + * + * @param Collection $collection + * + * @return array + */ + public function getRulesForBills(Collection $collection): array; + /** * @param Bill $bill * @param Carbon $date diff --git a/resources/views/list/bills.twig b/resources/views/list/bills.twig index aa1759cd3b..cdb320ac7b 100644 --- a/resources/views/list/bills.twig +++ b/resources/views/list/bills.twig @@ -21,8 +21,8 @@ {% for entry in bills %} {% if entry.active %} {% set count = count + 1 %} - {% set sum_min = sum_min + entry.amount_min %} - {% set sum_max = sum_min + entry.amount_max %} + {% set sum_min = sum_min + entry.amount_min %} + {% set sum_max = sum_min + entry.amount_max %} {% set expected_total = expected_total + ((entry.amount_min + entry.amount_max) / 2) %} {% endif %} @@ -43,7 +43,13 @@ - (rules) + {% if entry.rules|length > 0 %} + + {% endif %} @@ -127,7 +133,7 @@   - {# calculate total#} + {# calculate total#} {% if count > 0 %} {% set avg_min = (sum_min / count) %} {% set avg_max = (sum_max / count) %} From 69b577048e80458f8f39e77b56031a7f002d9b29 Mon Sep 17 00:00:00 2001 From: James Cole Date: Sun, 8 Apr 2018 18:35:13 +0200 Subject: [PATCH 019/117] New string [skip ci] --- resources/lang/en_US/list.php | 1 + 1 file changed, 1 insertion(+) diff --git a/resources/lang/en_US/list.php b/resources/lang/en_US/list.php index d8da5cb39e..3c8a354b42 100644 --- a/resources/lang/en_US/list.php +++ b/resources/lang/en_US/list.php @@ -33,6 +33,7 @@ return [ 'name' => 'Name', 'role' => 'Role', 'currentBalance' => 'Current balance', + 'linked_to_rules' => 'Relevant rules', 'active' => 'Is active?', 'lastActivity' => 'Last activity', 'balanceDiff' => 'Balance difference', From 0847040017fa746b04a2bb56bea2a3680cef2bdc Mon Sep 17 00:00:00 2001 From: James Cole Date: Mon, 9 Apr 2018 18:59:06 +0200 Subject: [PATCH 020/117] Correct access rights #1320 --- .deploy/docker/entrypoint.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.deploy/docker/entrypoint.sh b/.deploy/docker/entrypoint.sh index c04a7d10ff..bfafaaf3b3 100755 --- a/.deploy/docker/entrypoint.sh +++ b/.deploy/docker/entrypoint.sh @@ -1,8 +1,8 @@ #!/bin/bash # make sure we own the volumes: -chown -R www-data:www-data -R $FIREFLY_PATH/storage/export $FIREFLY_PATH/storage/upload $FIREFLY_PATH/storage/logs -chmod -R 775 $FIREFLY_PATH/storage/export $FIREFLY_PATH/storage/upload $FIREFLY_PATH/storage/upload $FIREFLY_PATH/storage/logs +chown -R www-data:www-data -R $FIREFLY_PATH/storage/export $FIREFLY_PATH/storage/upload $FIREFLY_PATH/storage/logs $FIREFLY_PATH/storage/cache +chmod -R 775 $FIREFLY_PATH/storage/export $FIREFLY_PATH/storage/upload $FIREFLY_PATH/storage/upload $FIREFLY_PATH/storage/logs $FIREFLY_PATH/storage/cache # remove any lingering files that may break upgrades: rm -f $FIREFLY_PATH/storage/logs/laravel.log From 90cf7a3bf5f50dd2bd11f9ed09a826c4e0637571 Mon Sep 17 00:00:00 2001 From: James Cole Date: Tue, 10 Apr 2018 21:18:38 +0200 Subject: [PATCH 021/117] Fix several issues with bunq import #1330 --- .../Prerequisites/BunqPrerequisites.php | 76 +++++++++++++++---- app/Import/Routine/BunqRoutine.php | 64 ++++++++-------- app/Models/Preference.php | 2 +- app/Providers/FireflyServiceProvider.php | 5 ++ app/Services/Bunq/Id/BunqId.php | 1 + app/Services/Bunq/Object/Avatar.php | 6 +- app/Services/Bunq/Object/DeviceServer.php | 4 +- app/Services/Bunq/Object/Image.php | 8 +- .../Bunq/Object/LabelMonetaryAccount.php | 4 +- app/Services/Bunq/Object/LabelUser.php | 4 +- .../Bunq/Object/MonetaryAccountBank.php | 4 +- app/Services/Bunq/Object/Payment.php | 4 +- app/Services/Bunq/Object/ServerPublicKey.php | 4 +- app/Services/Bunq/Object/UserLight.php | 4 +- .../Bunq/Request/InstallationTokenRequest.php | 2 - app/Services/Bunq/Token/BunqToken.php | 2 - app/Services/IP/IPRetrievalInterface.php | 40 ++++++++++ app/Services/IP/IpifyOrg.php | 60 +++++++++++++++ app/Support/Preferences.php | 2 +- resources/lang/en_US/form.php | 1 + resources/lang/en_US/import.php | 1 + .../views/import/bunq/prerequisites.twig | 14 ++++ 22 files changed, 243 insertions(+), 69 deletions(-) create mode 100644 app/Services/IP/IPRetrievalInterface.php create mode 100644 app/Services/IP/IpifyOrg.php diff --git a/app/Import/Prerequisites/BunqPrerequisites.php b/app/Import/Prerequisites/BunqPrerequisites.php index 05246d701d..286268b919 100644 --- a/app/Import/Prerequisites/BunqPrerequisites.php +++ b/app/Import/Prerequisites/BunqPrerequisites.php @@ -22,6 +22,7 @@ declare(strict_types=1); namespace FireflyIII\Import\Prerequisites; +use FireflyIII\Services\IP\IPRetrievalInterface; use FireflyIII\User; use Illuminate\Http\Request; use Illuminate\Support\MessageBag; @@ -56,13 +57,23 @@ class BunqPrerequisites implements PrerequisitesInterface public function getViewParameters(): array { Log::debug('Now in BunqPrerequisites::getViewParameters()'); - $apiKey = Preferences::getForUser($this->user, 'bunq_api_key', null); - $string = ''; - if (null !== $apiKey) { - $string = $apiKey->data; + $key = ''; + $serverIP = ''; + if ($this->hasApiKey()) { + $key = Preferences::getForUser($this->user, 'bunq_api_key', null)->data; + } + if ($this->hasServerIP()) { + $serverIP = Preferences::getForUser($this->user, 'external_ip', null)->data; + } + if (!$this->hasServerIP()) { + /** @var IPRetrievalInterface $service */ + $service = app(IPRetrievalInterface::class); + $serverIP = (string)$service->getIP(); } - return ['key' => $string]; + + // get IP address + return ['key' => $key, 'ip' => $serverIP]; } /** @@ -74,15 +85,10 @@ class BunqPrerequisites implements PrerequisitesInterface */ public function hasPrerequisites(): bool { - Log::debug('Now in BunqPrerequisites::hasPrerequisites()'); - $apiKey = Preferences::getForUser($this->user, 'bunq_api_key', false); - $result = (false === $apiKey->data || null === $apiKey->data); + $hasApiKey = $this->hasApiKey(); + $hasServerIP = $this->hasServerIP(); - Log::debug(sprintf('Is apiKey->data false? %s', var_export(false === $apiKey->data, true))); - Log::debug(sprintf('Is apiKey->data NULL? %s', var_export(null === $apiKey->data, true))); - Log::debug(sprintf('Result is: %s', var_export($result, true))); - - return $result; + return !$hasApiKey || !$hasServerIP; } /** @@ -94,8 +100,6 @@ class BunqPrerequisites implements PrerequisitesInterface { Log::debug(sprintf('Now in setUser(#%d)', $user->id)); $this->user = $user; - - return; } /** @@ -108,10 +112,50 @@ class BunqPrerequisites implements PrerequisitesInterface */ public function storePrerequisites(Request $request): MessageBag { - $apiKey = $request->get('api_key'); + $apiKey = $request->get('api_key'); + $serverIP = $request->get('external_ip'); Log::debug('Storing bunq API key'); Preferences::setForUser($this->user, 'bunq_api_key', $apiKey); + Preferences::setForUser($this->user, 'external_ip', $serverIP); return new MessageBag; } + + /** + * @return bool + */ + private function hasApiKey(): bool + { + $apiKey = Preferences::getForUser($this->user, 'bunq_api_key', false); + if (null === $apiKey) { + return false; + } + if (null === $apiKey->data) { + return false; + } + if (\strlen((string)$apiKey->data) === 64) { + return true; + } + + return false; + } + + /** + * @return bool + */ + private function hasServerIP(): bool + { + $serverIP = Preferences::getForUser($this->user, 'external_ip', false); + if (null === $serverIP) { + return false; + } + if (null === $serverIP->data) { + return false; + } + if (\strlen((string)$serverIP->data) > 6) { + return true; + } + + return false; + } } diff --git a/app/Import/Routine/BunqRoutine.php b/app/Import/Routine/BunqRoutine.php index bff5cbfb6e..160eb4459e 100644 --- a/app/Import/Routine/BunqRoutine.php +++ b/app/Import/Routine/BunqRoutine.php @@ -25,7 +25,6 @@ namespace FireflyIII\Import\Routine; use Carbon\Carbon; use DB; -use Exception; use FireflyIII\Exceptions\FireflyException; use FireflyIII\Factory\AccountFactory; use FireflyIII\Factory\TransactionJournalFactory; @@ -53,10 +52,10 @@ use FireflyIII\Services\Bunq\Request\ListMonetaryAccountRequest; use FireflyIII\Services\Bunq\Request\ListPaymentRequest; use FireflyIII\Services\Bunq\Token\InstallationToken; use FireflyIII\Services\Bunq\Token\SessionToken; +use FireflyIII\Services\IP\IPRetrievalInterface; use Illuminate\Support\Collection; use Log; use Preferences; -use Requests; /** * Class BunqRoutine @@ -212,7 +211,7 @@ class BunqRoutine implements RoutineInterface /** * @throws FireflyException */ - protected function runStageInitial() + protected function runStageInitial(): void { $this->addStep(); Log::debug('In runStageInitial()'); @@ -237,8 +236,8 @@ class BunqRoutine implements RoutineInterface { $this->addStep(); Log::debug('Now in runStageRegistered()'); - $apiKey = Preferences::getForUser($this->job->user, 'bunq_api_key')->data; - $serverPublicKey = Preferences::getForUser($this->job->user, 'bunq_server_public_key')->data; + $apiKey = (string)Preferences::getForUser($this->job->user, 'bunq_api_key')->data; + $serverPublicKey = new ServerPublicKey(Preferences::getForUser($this->job->user, 'bunq_server_public_key', [])->data); $installationToken = $this->getInstallationToken(); $request = new DeviceSessionRequest; $request->setInstallationToken($installationToken); @@ -265,14 +264,12 @@ class BunqRoutine implements RoutineInterface $this->addStep(); Log::debug('Session stored in job.'); - - return; } /** * Shorthand method. */ - private function addStep() + private function addStep(): void { $this->addSteps(1); } @@ -282,17 +279,17 @@ class BunqRoutine implements RoutineInterface * * @param int $count */ - private function addSteps(int $count) + private function addSteps(int $count): void { $this->repository->addStepsDone($this->job, $count); } /** - * Shorthand + * Shorthand method * * @param int $steps */ - private function addTotalSteps(int $steps) + private function addTotalSteps(int $steps): void { $this->repository->addTotalSteps($this->job, $steps); } @@ -334,7 +331,7 @@ class BunqRoutine implements RoutineInterface // try to find asset account just in case: if ($expectedType !== AccountType::ASSET) { $result = $this->accountRepository->findByIbanNull($party->getIban(), [AccountType::ASSET]); - if (nul !== $result) { + if (null !== $result) { Log::debug(sprintf('Search for Asset "%s" resulted in account %s (#%d)', $party->getIban(), $result->name, $result->id)); return $result; @@ -403,6 +400,8 @@ class BunqRoutine implements RoutineInterface } /** + * Shorthand method. + * * @return array */ private function getConfig(): array @@ -466,7 +465,7 @@ class BunqRoutine implements RoutineInterface if (null !== $token) { Log::debug('Have installation token, return it.'); - return $token->data; + return new InstallationToken($token->data); } Log::debug('Have no installation token, request one.'); @@ -481,9 +480,12 @@ class BunqRoutine implements RoutineInterface $installationId = $request->getInstallationId(); $serverPublicKey = $request->getServerPublicKey(); - Preferences::setForUser($this->job->user, 'bunq_installation_token', $installationToken); - Preferences::setForUser($this->job->user, 'bunq_installation_id', $installationId); - Preferences::setForUser($this->job->user, 'bunq_server_public_key', $serverPublicKey); + Log::debug('Have all values from InstallationTokenRequest'); + + + Preferences::setForUser($this->job->user, 'bunq_installation_token', $installationToken->toArray()); + Preferences::setForUser($this->job->user, 'bunq_installation_id', $installationId->toArray()); + Preferences::setForUser($this->job->user, 'bunq_server_public_key', $serverPublicKey->toArray()); Log::debug('Stored token, ID and pub key.'); @@ -507,7 +509,7 @@ class BunqRoutine implements RoutineInterface $preference = Preferences::getForUser($this->job->user, 'bunq_private_key', null); Log::debug('Return private key for user'); - return $preference->data; + return (string)$preference->data; } /** @@ -527,7 +529,7 @@ class BunqRoutine implements RoutineInterface $preference = Preferences::getForUser($this->job->user, 'bunq_public_key', null); Log::debug('Return public key for user'); - return $preference->data; + return (string)$preference->data; } /** @@ -537,20 +539,18 @@ class BunqRoutine implements RoutineInterface * * @throws FireflyException */ - private function getRemoteIp(): string + private function getRemoteIp(): ?string { + $preference = Preferences::getForUser($this->job->user, 'external_ip', null); if (null === $preference) { - try { - $response = Requests::get('https://api.ipify.org'); - } catch (Exception $e) { - throw new FireflyException(sprintf('Could not retrieve external IP: %s', $e->getMessage())); + + /** @var IPRetrievalInterface $service */ + $service = app(IPRetrievalInterface::class); + $serverIp = $service->getIP(); + if (null !== $serverIp) { + Preferences::setForUser($this->job->user, 'external_ip', $serverIp); } - if (200 !== $response->status_code) { - throw new FireflyException(sprintf('Could not retrieve external IP: %d %s', $response->status_code, $response->body)); - } - $serverIp = $response->body; - Preferences::setForUser($this->job->user, 'external_ip', $serverIp); return $serverIp; } @@ -572,7 +572,7 @@ class BunqRoutine implements RoutineInterface throw new FireflyException('Cannot determine bunq server public key, but should have it at this point.'); } - return $pref; + return new ServerPublicKey($pref); } /** @@ -738,7 +738,7 @@ class BunqRoutine implements RoutineInterface if (null !== $deviceServerId) { Log::debug('Already have device server ID.'); - return $deviceServerId->data; + return new DeviceServerId($deviceServerId->data); } Log::debug('Device server ID is null, we have to find an existing one or register a new one.'); @@ -778,8 +778,8 @@ class BunqRoutine implements RoutineInterface throw new FireflyException('Was not able to register server with bunq. Please see the log files.'); } - Preferences::setForUser($this->job->user, 'bunq_device_server_id', $deviceServerId); - Log::debug(sprintf('Server ID: %s', serialize($deviceServerId))); + Preferences::setForUser($this->job->user, 'bunq_device_server_id', $deviceServerId->toArray()); + Log::debug(sprintf('Server ID: %s', json_encode($deviceServerId))); return $deviceServerId; } diff --git a/app/Models/Preference.php b/app/Models/Preference.php index 7c3cae0da9..38f86409ed 100644 --- a/app/Models/Preference.php +++ b/app/Models/Preference.php @@ -73,7 +73,7 @@ class Preference extends Model unserialize($data, ['allowed_classes' => false]); } catch (Exception $e) { $serialized = false; - Log::debug(sprintf('Could not unserialise preference #%d. This is good. %s', $this->id, $e->getMessage())); + Log::debug(sprintf('Could not unserialise preference #%d ("%s"). This is good. %s', $this->id, $this->name, $e->getMessage())); } if (!$serialized) { $result = json_decode($data, true); diff --git a/app/Providers/FireflyServiceProvider.php b/app/Providers/FireflyServiceProvider.php index 5a9c83b109..6bea0cca5b 100644 --- a/app/Providers/FireflyServiceProvider.php +++ b/app/Providers/FireflyServiceProvider.php @@ -48,6 +48,8 @@ use FireflyIII\Repositories\User\UserRepository; use FireflyIII\Repositories\User\UserRepositoryInterface; use FireflyIII\Services\Currency\ExchangeRateInterface; use FireflyIII\Services\Currency\FixerIOv2; +use FireflyIII\Services\IP\IpifyOrg; +use FireflyIII\Services\IP\IPRetrievalInterface; use FireflyIII\Services\Password\PwndVerifierV2; use FireflyIII\Services\Password\Verifier; use FireflyIII\Support\Amount; @@ -180,5 +182,8 @@ class FireflyServiceProvider extends ServiceProvider // password verifier thing $this->app->bind(Verifier::class, PwndVerifierV2::class); + + // IP thing: + $this->app->bind(IPRetrievalInterface::class, IpifyOrg::class); } } diff --git a/app/Services/Bunq/Id/BunqId.php b/app/Services/Bunq/Id/BunqId.php index 8c62a3d29a..1b657519f0 100644 --- a/app/Services/Bunq/Id/BunqId.php +++ b/app/Services/Bunq/Id/BunqId.php @@ -23,6 +23,7 @@ declare(strict_types=1); namespace FireflyIII\Services\Bunq\Id; +use Log; /** * Class BunqId. */ diff --git a/app/Services/Bunq/Object/Avatar.php b/app/Services/Bunq/Object/Avatar.php index 7231c763b3..91c7847527 100644 --- a/app/Services/Bunq/Object/Avatar.php +++ b/app/Services/Bunq/Object/Avatar.php @@ -51,6 +51,10 @@ class Avatar extends BunqObject */ public function toArray(): array { - die(sprintf('Cannot convert %s to array.', get_class($this))); + return [ + 'uuid' => $this->uuid, + 'anchor_uuid' => $this->anchorUuid, + 'image' => $this->image->toArray(), + ]; } } diff --git a/app/Services/Bunq/Object/DeviceServer.php b/app/Services/Bunq/Object/DeviceServer.php index 77dd6a02ef..486c2e74de 100644 --- a/app/Services/Bunq/Object/DeviceServer.php +++ b/app/Services/Bunq/Object/DeviceServer.php @@ -25,6 +25,8 @@ namespace FireflyIII\Services\Bunq\Object; use Carbon\Carbon; use FireflyIII\Services\Bunq\Id\DeviceServerId; +use FireflyIII\Exceptions\FireflyException; + /** * Class DeviceServer */ @@ -82,6 +84,6 @@ class DeviceServer extends BunqObject */ public function toArray(): array { - die(sprintf('Cannot convert %s to array.', get_class($this))); + throw new FireflyException(sprintf('Cannot convert %s to array.', \get_class($this))); } } diff --git a/app/Services/Bunq/Object/Image.php b/app/Services/Bunq/Object/Image.php index 11d83f9e5b..bfc36cdff4 100644 --- a/app/Services/Bunq/Object/Image.php +++ b/app/Services/Bunq/Object/Image.php @@ -23,7 +23,6 @@ declare(strict_types=1); namespace FireflyIII\Services\Bunq\Object; - /** * Class Image */ @@ -56,7 +55,12 @@ class Image extends BunqObject */ public function toArray(): array { - die(sprintf('Cannot convert %s to array.', get_class($this))); + return [ + 'attachment_public_uuid' => $this->attachmentPublicUuid, + 'height' => $this->height, + 'width' => $this->width, + 'content_type' => $this->contentType, + ]; } } diff --git a/app/Services/Bunq/Object/LabelMonetaryAccount.php b/app/Services/Bunq/Object/LabelMonetaryAccount.php index c652f959df..2e6198530c 100644 --- a/app/Services/Bunq/Object/LabelMonetaryAccount.php +++ b/app/Services/Bunq/Object/LabelMonetaryAccount.php @@ -23,7 +23,7 @@ declare(strict_types=1); namespace FireflyIII\Services\Bunq\Object; - +use FireflyIII\Exceptions\FireflyException; /** * Class LabelMonetaryAccount */ @@ -75,7 +75,7 @@ class LabelMonetaryAccount extends BunqObject */ public function toArray(): array { - die(sprintf('Cannot convert %s to array.', get_class($this))); + throw new FireflyException(sprintf('Cannot convert %s to array.', \get_class($this))); } } diff --git a/app/Services/Bunq/Object/LabelUser.php b/app/Services/Bunq/Object/LabelUser.php index 2d940851c7..d7820f9eb5 100644 --- a/app/Services/Bunq/Object/LabelUser.php +++ b/app/Services/Bunq/Object/LabelUser.php @@ -23,7 +23,7 @@ declare(strict_types=1); namespace FireflyIII\Services\Bunq\Object; - +use FireflyIII\Exceptions\FireflyException; /** * Class LabelUser */ @@ -83,6 +83,6 @@ class LabelUser extends BunqObject */ public function toArray(): array { - die(sprintf('Cannot convert %s to array.', get_class($this))); + throw new FireflyException(sprintf('Cannot convert %s to array.', \get_class($this))); } } diff --git a/app/Services/Bunq/Object/MonetaryAccountBank.php b/app/Services/Bunq/Object/MonetaryAccountBank.php index f38e88a53f..18264af185 100644 --- a/app/Services/Bunq/Object/MonetaryAccountBank.php +++ b/app/Services/Bunq/Object/MonetaryAccountBank.php @@ -94,8 +94,8 @@ class MonetaryAccountBank extends BunqObject $this->setting = new MonetaryAccountSetting($data['setting']); $this->overdraftLimit = new Amount($data['overdraft_limit']); $this->avatar = new Avatar($data['avatar']); - $this->reason = $data['reason']; - $this->reasonDescription = $data['reason_description']; + $this->reason = $data['reason'] ?? ''; + $this->reasonDescription = $data['reason_description'] ?? ''; // create aliases: foreach ($data['alias'] as $alias) { diff --git a/app/Services/Bunq/Object/Payment.php b/app/Services/Bunq/Object/Payment.php index 2e063897d0..98b91bcdb8 100644 --- a/app/Services/Bunq/Object/Payment.php +++ b/app/Services/Bunq/Object/Payment.php @@ -24,7 +24,7 @@ declare(strict_types=1); namespace FireflyIII\Services\Bunq\Object; use Carbon\Carbon; - +use FireflyIII\Exceptions\FireflyException; /** * Class Payment @@ -138,7 +138,7 @@ class Payment extends BunqObject */ public function toArray(): array { - die(sprintf('Cannot convert %s to array.', get_class($this))); + throw new FireflyException(sprintf('Cannot convert %s to array.', \get_class($this))); } } diff --git a/app/Services/Bunq/Object/ServerPublicKey.php b/app/Services/Bunq/Object/ServerPublicKey.php index a5fa808392..4a665fda99 100644 --- a/app/Services/Bunq/Object/ServerPublicKey.php +++ b/app/Services/Bunq/Object/ServerPublicKey.php @@ -61,6 +61,8 @@ class ServerPublicKey extends BunqObject */ public function toArray(): array { - die(sprintf('Cannot convert %s to array.', get_class($this))); + return [ + 'server_public_key' => $this->publicKey, + ]; } } diff --git a/app/Services/Bunq/Object/UserLight.php b/app/Services/Bunq/Object/UserLight.php index 3576c94d31..0de5bee797 100644 --- a/app/Services/Bunq/Object/UserLight.php +++ b/app/Services/Bunq/Object/UserLight.php @@ -23,7 +23,7 @@ declare(strict_types=1); namespace FireflyIII\Services\Bunq\Object; use Carbon\Carbon; - +use FireflyIII\Exceptions\FireflyException; /** * Class UserLight. */ @@ -81,6 +81,6 @@ class UserLight extends BunqObject */ public function toArray(): array { - die(sprintf('Cannot convert %s to array.', get_class($this))); + throw new FireflyException(sprintf('Cannot convert %s to array.', \get_class($this))); } } diff --git a/app/Services/Bunq/Request/InstallationTokenRequest.php b/app/Services/Bunq/Request/InstallationTokenRequest.php index 0558738218..b612a9aed2 100644 --- a/app/Services/Bunq/Request/InstallationTokenRequest.php +++ b/app/Services/Bunq/Request/InstallationTokenRequest.php @@ -58,8 +58,6 @@ class InstallationTokenRequest extends BunqRequest Log::debug(sprintf('Installation ID: %s', $this->installationId->getId())); Log::debug(sprintf('Installation token: %s', $this->installationToken->getToken())); Log::debug('Server public key: (not included)'); - - return; } /** diff --git a/app/Services/Bunq/Token/BunqToken.php b/app/Services/Bunq/Token/BunqToken.php index 161448a364..a83716408d 100644 --- a/app/Services/Bunq/Token/BunqToken.php +++ b/app/Services/Bunq/Token/BunqToken.php @@ -103,7 +103,5 @@ class BunqToken $this->created = Carbon::createFromFormat('Y-m-d H:i:s.u', $response['created']); $this->updated = Carbon::createFromFormat('Y-m-d H:i:s.u', $response['updated']); $this->token = $response['token']; - - return; } } diff --git a/app/Services/IP/IPRetrievalInterface.php b/app/Services/IP/IPRetrievalInterface.php new file mode 100644 index 0000000000..69ca1132a9 --- /dev/null +++ b/app/Services/IP/IPRetrievalInterface.php @@ -0,0 +1,40 @@ +. + */ + +declare(strict_types=1); + +namespace FireflyIII\Services\IP; + +/** + * Interface IPRetrievalInterface + * + * @package FireflyIII\Services\IP + */ +interface IPRetrievalInterface +{ + + /** + * Returns the user's IP address. + * + * @return null|string + */ + public function getIP(): ?string; +} \ No newline at end of file diff --git a/app/Services/IP/IpifyOrg.php b/app/Services/IP/IpifyOrg.php new file mode 100644 index 0000000000..89256e9024 --- /dev/null +++ b/app/Services/IP/IpifyOrg.php @@ -0,0 +1,60 @@ +. + */ + +declare(strict_types=1); + +namespace FireflyIII\Services\IP; + +use Exception; +use Log; +use Requests; + +/** + * Class IpifyOrg + */ +class IpifyOrg implements IPRetrievalInterface +{ + /** + * Returns the user's IP address. + * + * @noinspection MultipleReturnStatementsInspection + * @return null|string + */ + public function getIP(): ?string + { + $result = null; + try { + $response = Requests::get('https://api.ipify.org'); + } catch (Exception $e) { + Log::warning(sprintf('The ipify.org service could not retrieve external IP: %s', $e->getMessage())); + Log::warning($e->getTraceAsString()); + + return null; + } + if (200 !== $response->status_code) { + Log::warning(sprintf('Could not retrieve external IP: %d %s', $response->status_code, $response->body)); + + return null; + } + + return (string)$response->body; + } +} \ No newline at end of file diff --git a/app/Support/Preferences.php b/app/Support/Preferences.php index 9acd6163fc..932b534c6e 100644 --- a/app/Support/Preferences.php +++ b/app/Support/Preferences.php @@ -208,7 +208,7 @@ class Preferences /** * @param \FireflyIII\User $user * @param $name - * @param string $value + * @param mixed $value * * @return Preference */ diff --git a/resources/lang/en_US/form.php b/resources/lang/en_US/form.php index 23b88d81d6..af213d8bbc 100644 --- a/resources/lang/en_US/form.php +++ b/resources/lang/en_US/form.php @@ -38,6 +38,7 @@ return [ 'journal_currency_id' => 'Currency', 'currency_id' => 'Currency', 'transaction_currency_id' => 'Currency', + 'external_ip' => 'Your server\'s external IP', 'attachments' => 'Attachments', 'journal_amount' => 'Amount', 'journal_source_account_name' => 'Revenue account (source)', diff --git a/resources/lang/en_US/import.php b/resources/lang/en_US/import.php index 3130034c8b..716665edd7 100644 --- a/resources/lang/en_US/import.php +++ b/resources/lang/en_US/import.php @@ -164,6 +164,7 @@ return [ // bunq 'bunq_prerequisites_title' => 'Prerequisites for an import from bunq', 'bunq_prerequisites_text' => 'In order to import from bunq, you need to obtain an API key. You can do this through the app. Please note that the import function for bunq is in BETA. It has only been tested against the sandbox API.', + 'bunq_prerequisites_text_ip' => 'Bunq requires your externally facing IP address. Firefly III has tried to fill this in using the ipify service. Make sure this IP address is correct, or the import will fail.', 'bunq_do_import' => 'Yes, import from this account', 'bunq_accounts_title' => 'Bunq accounts', 'bunq_accounts_text' => 'These are the accounts associated with your bunq account. Please select the accounts from which you want to import, and in which account the transactions must be imported.', diff --git a/resources/views/import/bunq/prerequisites.twig b/resources/views/import/bunq/prerequisites.twig index 5ff2448bb7..0e45d3223f 100644 --- a/resources/views/import/bunq/prerequisites.twig +++ b/resources/views/import/bunq/prerequisites.twig @@ -26,6 +26,20 @@ {{ ExpandedForm.text('api_key', key) }}
+ +
+
+

+ {{ trans('import.bunq_prerequisites_text_ip')|raw }} +

+
+
+ +
+
+ {{ ExpandedForm.text('external_ip', ip) }} +
+
+
  • + + + + + +
  • diff --git a/resources/views/rules/rule/create.twig b/resources/views/rules/rule/create.twig index 1fddf8f2af..aadaff7a4e 100644 --- a/resources/views/rules/rule/create.twig +++ b/resources/views/rules/rule/create.twig @@ -82,7 +82,7 @@


    - {{ 'test_rule_triggers'|_ }} + {{ 'test_rule_triggers'|_ }}

    @@ -148,6 +148,7 @@ diff --git a/resources/views/rules/rule/edit.twig b/resources/views/rules/rule/edit.twig index 2b28a6e21e..e45e47e92f 100644 --- a/resources/views/rules/rule/edit.twig +++ b/resources/views/rules/rule/edit.twig @@ -128,6 +128,7 @@ diff --git a/routes/web.php b/routes/web.php index a7c91ce196..897e64e490 100755 --- a/routes/web.php +++ b/routes/web.php @@ -713,7 +713,7 @@ Route::group( ['middleware' => 'user-full-auth', 'namespace' => 'FireflyIII\Http\Controllers', 'prefix' => 'rules', 'as' => 'rules.'], function () { Route::get('', ['uses' => 'RuleController@index', 'as' => 'index']); - Route::get('create/{ruleGroup}', ['uses' => 'RuleController@create', 'as' => 'create']); + Route::get('create/{ruleGroup?}', ['uses' => 'RuleController@create', 'as' => 'create']); Route::get('up/{rule}', ['uses' => 'RuleController@up', 'as' => 'up']); Route::get('down/{rule}', ['uses' => 'RuleController@down', 'as' => 'down']); Route::get('edit/{rule}', ['uses' => 'RuleController@edit', 'as' => 'edit']); From 926c03986cf072b89d77c2bdac8123db02003208 Mon Sep 17 00:00:00 2001 From: James Cole Date: Sat, 14 Apr 2018 13:00:24 +0200 Subject: [PATCH 025/117] Remove references to bill scanning. --- .../Events/StoredJournalEventHandler.php | 15 ------ .../Events/UpdatedJournalEventHandler.php | 15 ------ app/Import/Configuration/BunqConfigurator.php | 1 - app/Import/Configuration/FileConfigurator.php | 1 - .../Configuration/SpectreConfigurator.php | 1 - app/Import/Storage/ImportStorage.php | 26 +--------- app/Import/Storage/ImportSupport.php | 40 ---------------- app/Providers/EventServiceProvider.php | 2 - app/Repositories/Bill/BillRepository.php | 46 ------------------ .../Bill/BillRepositoryInterface.php | 8 ---- app/Support/Events/BillScanner.php | 47 ------------------- .../Configuration/File/UploadConfig.php | 1 - .../views/import/file/upload-config.twig | 15 ------ 13 files changed, 1 insertion(+), 217 deletions(-) delete mode 100644 app/Support/Events/BillScanner.php diff --git a/app/Handlers/Events/StoredJournalEventHandler.php b/app/Handlers/Events/StoredJournalEventHandler.php index 6cfb5ad600..43ca29745b 100644 --- a/app/Handlers/Events/StoredJournalEventHandler.php +++ b/app/Handlers/Events/StoredJournalEventHandler.php @@ -28,7 +28,6 @@ use FireflyIII\Models\RuleGroup; use FireflyIII\Repositories\Journal\JournalRepositoryInterface as JRI; use FireflyIII\Repositories\PiggyBank\PiggyBankRepositoryInterface as PRI; use FireflyIII\Repositories\RuleGroup\RuleGroupRepositoryInterface as RGRI; -use FireflyIII\Support\Events\BillScanner; use FireflyIII\TransactionRules\Processor; /** @@ -91,18 +90,4 @@ class StoredJournalEventHandler return true; } - /** - * This method calls a special bill scanner that will check if the stored journal is part of a bill. - * - * @param StoredTransactionJournal $storedJournalEvent - * - * @return bool - */ - public function scanBills(StoredTransactionJournal $storedJournalEvent): bool - { - $journal = $storedJournalEvent->journal; - BillScanner::scan($journal); - - return true; - } } diff --git a/app/Handlers/Events/UpdatedJournalEventHandler.php b/app/Handlers/Events/UpdatedJournalEventHandler.php index 4b1ee5b3ff..ac06e95908 100644 --- a/app/Handlers/Events/UpdatedJournalEventHandler.php +++ b/app/Handlers/Events/UpdatedJournalEventHandler.php @@ -26,7 +26,6 @@ use FireflyIII\Events\UpdatedTransactionJournal; use FireflyIII\Models\Rule; use FireflyIII\Models\RuleGroup; use FireflyIII\Repositories\RuleGroup\RuleGroupRepositoryInterface; -use FireflyIII\Support\Events\BillScanner; use FireflyIII\TransactionRules\Processor; /** @@ -80,18 +79,4 @@ class UpdatedJournalEventHandler return true; } - /** - * This method calls a special bill scanner that will check if the updated journal is part of a bill. - * - * @param UpdatedTransactionJournal $updatedJournalEvent - * - * @return bool - */ - public function scanBills(UpdatedTransactionJournal $updatedJournalEvent): bool - { - $journal = $updatedJournalEvent->journal; - BillScanner::scan($journal); - - return true; - } } diff --git a/app/Import/Configuration/BunqConfigurator.php b/app/Import/Configuration/BunqConfigurator.php index f1bb96fe60..6dad1ea2ad 100644 --- a/app/Import/Configuration/BunqConfigurator.php +++ b/app/Import/Configuration/BunqConfigurator.php @@ -185,7 +185,6 @@ class BunqConfigurator implements ConfiguratorInterface 'stage' => 'initial', 'auto-start' => true, 'apply-rules' => true, - 'match-bills' => false, ]; $currentConfig = $this->repository->getConfiguration($job); $finalConfig = array_merge($defaultConfig, $currentConfig); diff --git a/app/Import/Configuration/FileConfigurator.php b/app/Import/Configuration/FileConfigurator.php index 0eae8d7d07..2151e0091c 100644 --- a/app/Import/Configuration/FileConfigurator.php +++ b/app/Import/Configuration/FileConfigurator.php @@ -53,7 +53,6 @@ class FileConfigurator implements ConfiguratorInterface 'file-type' => 'csv', // assume 'has-config-file' => true, 'apply-rules' => true, - 'match-bills' => false, 'auto-start' => false, ]; /** @var ImportJob */ diff --git a/app/Import/Configuration/SpectreConfigurator.php b/app/Import/Configuration/SpectreConfigurator.php index e09f7d17fb..a0b5a41915 100644 --- a/app/Import/Configuration/SpectreConfigurator.php +++ b/app/Import/Configuration/SpectreConfigurator.php @@ -206,7 +206,6 @@ class SpectreConfigurator implements ConfiguratorInterface 'accounts-mapped' => '', 'auto-start' => true, 'apply-rules' => true, - 'match-bills' => false, ]; $currentConfig = $this->repository->getConfiguration($job); $finalConfig = array_merge($defaultConfig, $currentConfig); diff --git a/app/Import/Storage/ImportStorage.php b/app/Import/Storage/ImportStorage.php index aee0bdbc6a..0e75e0fce1 100644 --- a/app/Import/Storage/ImportStorage.php +++ b/app/Import/Storage/ImportStorage.php @@ -28,7 +28,6 @@ use FireflyIII\Factory\TransactionJournalFactory; use FireflyIII\Import\Object\ImportJournal; use FireflyIII\Models\ImportJob; use FireflyIII\Models\TransactionType; -use FireflyIII\Repositories\Bill\BillRepositoryInterface; use FireflyIII\Repositories\ImportJob\ImportJobRepositoryInterface; use FireflyIII\Repositories\Journal\JournalRepositoryInterface; use Illuminate\Support\Collection; @@ -56,10 +55,6 @@ class ImportStorage public $errors; /** @var Collection */ public $journals; - /** @var BillRepositoryInterface */ - protected $billRepository; - /** @var Collection */ - protected $bills; /** @var int */ protected $defaultCurrencyId = 1; /** @var ImportJob */ @@ -76,8 +71,6 @@ class ImportStorage private $dateFormat = 'Ymd'; /** @var TransactionJournalFactory */ private $factory; - /** @var bool */ - private $matchBills = false; /** @var Collection */ private $objects; /** @var int */ @@ -122,20 +115,13 @@ class ImportStorage $this->job = $job; $this->transfers = $this->getTransfers(); $this->applyRules = $config['apply-rules'] ?? false; - $this->matchBills = $config['match-bills'] ?? false; if (true === $this->applyRules) { Log::debug('applyRules seems to be true, get the rules.'); $this->rules = $this->getRules(); } - if (true === $this->matchBills) { - Log::debug('matchBills seems to be true, get the bills'); - $this->bills = $this->getBills(); - $this->billRepository = app(BillRepositoryInterface::class); - $this->billRepository->setUser($job->user); - } + Log::debug(sprintf('Value of apply rules is %s', var_export($this->applyRules, true))); - Log::debug(sprintf('Value of match bills is %s', var_export($this->matchBills, true))); } /** @@ -301,16 +287,6 @@ class ImportStorage Log::info('Will NOT apply rules to this journal.'); } $this->addStep(); - - // match bills if config calls for it. - if (true === $this->matchBills) { - Log::info('Will match bills.'); - $this->matchBills($factoryJournal); - } - - if (!(true === $this->matchBills)) { - Log::info('Cannot match bills (yet), but do not have to.'); - } $this->addStep(); Log::info( diff --git a/app/Import/Storage/ImportSupport.php b/app/Import/Storage/ImportSupport.php index ddcb5fa1f6..f7544b516e 100644 --- a/app/Import/Storage/ImportSupport.php +++ b/app/Import/Storage/ImportSupport.php @@ -33,7 +33,6 @@ use FireflyIII\Models\Rule; use FireflyIII\Models\TransactionJournal; use FireflyIII\Models\TransactionJournalMeta; use FireflyIII\Models\TransactionType; -use FireflyIII\Repositories\Bill\BillRepositoryInterface; use FireflyIII\Repositories\Journal\JournalRepositoryInterface; use FireflyIII\TransactionRules\Processor; use Illuminate\Database\Query\JoinClause; @@ -45,10 +44,6 @@ use Log; */ trait ImportSupport { - /** @var BillRepositoryInterface */ - protected $billRepository; - /** @var Collection */ - protected $bills; /** @var int */ protected $defaultCurrencyId = 1; /** @var ImportJob */ @@ -84,41 +79,6 @@ trait ImportSupport return true; } - /** - * @param TransactionJournal $journal - * - * @return bool - */ - protected function matchBills(TransactionJournal $journal): bool - { - if (null !== $journal->bill_id) { - Log::debug('Journal is already linked to a bill, will not scan.'); - - return true; - } - if ($this->bills->count() > 0) { - $this->bills->each( - function (Bill $bill) use ($journal) { - Log::debug(sprintf('Going to match bill #%d to journal %d.', $bill->id, $journal->id)); - $this->billRepository->scan($bill, $journal); - } - ); - } - - return true; - } - - /** - * @return Collection - */ - private function getBills(): Collection - { - $set = Bill::where('user_id', $this->job->user->id)->where('active', 1)->where('automatch', 1)->get(['bills.*']); - Log::debug(sprintf('Found %d user bills.', $set->count())); - - return $set; - } - /** * This method finds out what the import journal's currency should be. The account itself * is favoured (and usually it stops there). If no preference is found, the journal has a say diff --git a/app/Providers/EventServiceProvider.php b/app/Providers/EventServiceProvider.php index 14a2965912..75b5dc0921 100644 --- a/app/Providers/EventServiceProvider.php +++ b/app/Providers/EventServiceProvider.php @@ -76,12 +76,10 @@ class EventServiceProvider extends ServiceProvider ], // is a Transaction Journal related event. StoredTransactionJournal::class => [ - 'FireflyIII\Handlers\Events\StoredJournalEventHandler@scanBills', 'FireflyIII\Handlers\Events\StoredJournalEventHandler@processRules', ], // is a Transaction Journal related event. UpdatedTransactionJournal::class => [ - 'FireflyIII\Handlers\Events\UpdatedJournalEventHandler@scanBills', 'FireflyIII\Handlers\Events\UpdatedJournalEventHandler@processRules', ], ]; diff --git a/app/Repositories/Bill/BillRepository.php b/app/Repositories/Bill/BillRepository.php index 6401d05819..ddc7e0b358 100644 --- a/app/Repositories/Bill/BillRepository.php +++ b/app/Repositories/Bill/BillRepository.php @@ -541,52 +541,6 @@ class BillRepository implements BillRepositoryInterface return $start; } - /** - * @param Bill $bill - * @param TransactionJournal $journal - * - * @deprecated - * @return bool - */ - public function scan(Bill $bill, TransactionJournal $journal): bool - { - // Can only support withdrawals. - if (false === $journal->isWithdrawal()) { - return false; - } - - /** @var JournalRepositoryInterface $repos */ - $repos = app(JournalRepositoryInterface::class); - $repos->setUser($this->user); - - $destinationAccounts = $repos->getJournalDestinationAccounts($journal); - $sourceAccounts = $repos->getJournalDestinationAccounts($journal); - $matches = explode(',', $bill->match); - $description = strtolower($journal->description) . ' '; - $description .= strtolower(implode(' ', $destinationAccounts->pluck('name')->toArray())); - $description .= strtolower(implode(' ', $sourceAccounts->pluck('name')->toArray())); - - $wordMatch = $this->doWordMatch($matches, $description); - $amountMatch = $this->doAmountMatch($repos->getJournalTotal($journal), $bill->amount_min, $bill->amount_max); - - // when both, update! - if ($wordMatch && $amountMatch) { - $journal->bill()->associate($bill); - $journal->save(); - - return true; - } - if ($bill->id === $journal->bill_id) { - // if no match, but bill used to match, remove it: - $journal->bill_id = null; - $journal->save(); - - return true; - } - - return false; - } - /** * @param User $user */ diff --git a/app/Repositories/Bill/BillRepositoryInterface.php b/app/Repositories/Bill/BillRepositoryInterface.php index d6cea63eea..bdf1f6f29a 100644 --- a/app/Repositories/Bill/BillRepositoryInterface.php +++ b/app/Repositories/Bill/BillRepositoryInterface.php @@ -196,14 +196,6 @@ interface BillRepositoryInterface */ public function nextExpectedMatch(Bill $bill, Carbon $date): Carbon; - /** - * @param Bill $bill - * @param TransactionJournal $journal - * - * @return bool - */ - public function scan(Bill $bill, TransactionJournal $journal): bool; - /** * @param User $user */ diff --git a/app/Support/Events/BillScanner.php b/app/Support/Events/BillScanner.php deleted file mode 100644 index f07d5d71b6..0000000000 --- a/app/Support/Events/BillScanner.php +++ /dev/null @@ -1,47 +0,0 @@ -. - */ -declare(strict_types=1); - -namespace FireflyIII\Support\Events; - -use FireflyIII\Models\TransactionJournal; -use FireflyIII\Repositories\Bill\BillRepositoryInterface; - -/** - * Class BillScanner. - */ -class BillScanner -{ - /** - * @param TransactionJournal $journal - */ - public static function scan(TransactionJournal $journal) - { - /** @var BillRepositoryInterface $repository */ - $repository = app(BillRepositoryInterface::class); - $list = $journal->user->bills()->where('active', 1)->where('automatch', 1)->get(); - - /** @var \FireflyIII\Models\Bill $bill */ - foreach ($list as $bill) { - $repository->scan($bill, $journal); - } - } -} diff --git a/app/Support/Import/Configuration/File/UploadConfig.php b/app/Support/Import/Configuration/File/UploadConfig.php index 8a0d6dbc07..750e7603d8 100644 --- a/app/Support/Import/Configuration/File/UploadConfig.php +++ b/app/Support/Import/Configuration/File/UploadConfig.php @@ -123,7 +123,6 @@ class UploadConfig implements ConfigurationInterface $config['date-format'] = (string)$data['date_format']; $config['delimiter'] = 'tab' === $delimiter ? "\t" : $delimiter; $config['apply-rules'] = (int)($data['apply_rules'] ?? 0.0) === 1; - $config['match-bills'] = (int)($data['match_bills'] ?? 0.0) === 1; Log::debug('Entered import account.', ['id' => $importId]); diff --git a/resources/views/import/file/upload-config.twig b/resources/views/import/file/upload-config.twig index 68f21d5872..c7bf64435d 100644 --- a/resources/views/import/file/upload-config.twig +++ b/resources/views/import/file/upload-config.twig @@ -55,21 +55,6 @@ -
    - - -
    -
    -
    -
    -
    - {% for type, specific in data.specifics %}
    diff --git a/resources/views/rules/rule/edit.twig b/resources/views/rules/rule/edit.twig index e45e47e92f..61226548b3 100644 --- a/resources/views/rules/rule/edit.twig +++ b/resources/views/rules/rule/edit.twig @@ -19,6 +19,7 @@ {{ ExpandedForm.select('trigger',allJournalTriggers(), primaryTrigger) }} {{ ExpandedForm.checkbox('active',1,rule.active, {helpText: trans('firefly.rule_help_active')}) }} {{ ExpandedForm.checkbox('stop_processing',1,rule.stop_processing, {helpText: trans('firefly.rule_help_stop_processing')}) }} + {{ ExpandedForm.checkbox('strict',1,rule.strict, {helpText: trans('firefly.rule_help_strict')}) }} From 62b68c6a21dc2d5bf3b7558094aa49934c279934 Mon Sep 17 00:00:00 2001 From: James Cole Date: Sat, 14 Apr 2018 21:21:20 +0200 Subject: [PATCH 027/117] Fix tests. --- app/Repositories/Bill/BillRepository.php | 23 -------- .../Bill/BillRepositoryInterface.php | 7 --- database/factories/ModelFactory.php | 23 ++++---- .../Controllers/BillControllerTest.php | 27 ++++----- tests/Unit/Factory/BillFactoryTest.php | 42 +++++++------- .../Unit/Transformers/BillTransformerTest.php | 57 ++++++++++--------- 6 files changed, 74 insertions(+), 105 deletions(-) diff --git a/app/Repositories/Bill/BillRepository.php b/app/Repositories/Bill/BillRepository.php index ddc7e0b358..49e8a68e84 100644 --- a/app/Repositories/Bill/BillRepository.php +++ b/app/Repositories/Bill/BillRepository.php @@ -344,29 +344,6 @@ class BillRepository implements BillRepositoryInterface return $set; } - /** - * @param Bill $bill - * - * @return Collection - */ - public function getPossiblyRelatedJournals(Bill $bill): Collection - { - $set = new Collection( - DB::table('transactions')->where('amount', '>', 0)->where('amount', '>=', $bill->amount_min)->where('amount', '<=', $bill->amount_max) - ->get(['transaction_journal_id']) - ); - $ids = $set->pluck('transaction_journal_id')->toArray(); - - $journals = new Collection; - if (count($ids) > 0) { - $journals = $this->user->transactionJournals()->transactionTypes([TransactionType::WITHDRAWAL])->whereIn('transaction_journals.id', $ids)->get( - ['transaction_journals.*'] - ); - } - - return $journals; - } - /** * Return all rules for one bill * diff --git a/app/Repositories/Bill/BillRepositoryInterface.php b/app/Repositories/Bill/BillRepositoryInterface.php index bdf1f6f29a..c53c8aa6e3 100644 --- a/app/Repositories/Bill/BillRepositoryInterface.php +++ b/app/Repositories/Bill/BillRepositoryInterface.php @@ -133,13 +133,6 @@ interface BillRepositoryInterface */ public function getPayDatesInRange(Bill $bill, Carbon $start, Carbon $end): Collection; - /** - * @param Bill $bill - * - * @return Collection - */ - public function getPossiblyRelatedJournals(Bill $bill): Collection; - /** * Return all rules for one bill * diff --git a/database/factories/ModelFactory.php b/database/factories/ModelFactory.php index 5a1e9ee90d..e37bd22338 100644 --- a/database/factories/ModelFactory.php +++ b/database/factories/ModelFactory.php @@ -118,17 +118,18 @@ $factory->define( FireflyIII\Models\Bill::class, function (Faker\Generator $faker) { return [ - 'created_at' => new Carbon, - 'updated_at' => new Carbon, - 'user_id' => 1, - 'name' => $faker->words(3, true), - 'match' => $faker->words(3, true), - 'amount_min' => '100.00', - 'amount_max' => '100.00', - 'date' => '2017-01-01', - 'repeat_freq' => 'monthly', - 'skip' => 0, - 'automatch' => 1, + 'created_at' => new Carbon, + 'updated_at' => new Carbon, + 'user_id' => 1, + 'transaction_currency_id' => 1, + 'name' => $faker->words(3, true), + 'match' => $faker->words(3, true), + 'amount_min' => '100.00', + 'amount_max' => '100.00', + 'date' => '2017-01-01', + 'repeat_freq' => 'monthly', + 'skip' => 0, + 'automatch' => 1, ]; } ); diff --git a/tests/Feature/Controllers/BillControllerTest.php b/tests/Feature/Controllers/BillControllerTest.php index 68aabe1da0..7da8478c81 100644 --- a/tests/Feature/Controllers/BillControllerTest.php +++ b/tests/Feature/Controllers/BillControllerTest.php @@ -140,6 +140,7 @@ class BillControllerTest extends TestCase $repository->shouldReceive('getPaginator')->andReturn(new LengthAwarePaginator($collection, 1, 50))->once(); $repository->shouldReceive('setUser'); $repository->shouldReceive('getPaidDatesInRange')->twice()->andReturn(new Collection([new Carbon, new Carbon, new Carbon])); + $repository->shouldReceive('getRulesForBills')->andReturn([]); $this->be($this->user()); @@ -159,10 +160,8 @@ class BillControllerTest extends TestCase $journal = factory(TransactionJournal::class)->make(); $journalRepos = $this->mock(JournalRepositoryInterface::class); $repository = $this->mock(BillRepositoryInterface::class); - $repository->shouldReceive('getPossiblyRelatedJournals')->once()->andReturn(new Collection([$journal])); - $repository->shouldReceive('scan')->once(); $journalRepos->shouldReceive('first')->once()->andReturn(new TransactionJournal); - + $repository->shouldReceive('getRulesForBill')->andReturn(new Collection); $this->be($this->user()); $response = $this->get(route('bills.rescan', [1])); $response->assertStatus(302); @@ -199,6 +198,7 @@ class BillControllerTest extends TestCase $repository->shouldReceive('getYearAverage')->andReturn('0'); $repository->shouldReceive('getOverallAverage')->andReturn('0'); $repository->shouldReceive('nextExpectedMatch')->andReturn(new Carbon); + $repository->shouldReceive('getRulesForBill')->andReturn(new Collection); $journalRepos->shouldReceive('first')->once()->andReturn(new TransactionJournal); $collector->shouldReceive('setAllAssetAccounts')->andReturnSelf(); @@ -235,15 +235,14 @@ class BillControllerTest extends TestCase $attachHelper->shouldReceive('getMessages')->andReturn(new MessageBag); $data = [ - 'name' => 'New Bill ' . random_int(1000, 9999), - 'match' => 'some words', - 'amount_min' => '100', - 'amount_currency_id_amount_min' => 1, - 'amount_currency_id_amount_max' => 1, - 'skip' => 0, - 'amount_max' => '100', - 'date' => '2016-01-01', - 'repeat_freq' => 'monthly', + 'name' => 'New Bill ' . random_int(1000, 9999), + 'amount_min' => '100', + 'transaction_currency_id' => 1, + 'skip' => 0, + 'strict' => 1, + 'amount_max' => '100', + 'date' => '2016-01-01', + 'repeat_freq' => 'monthly', ]; $this->session(['bills.create.uri' => 'http://localhost']); $this->be($this->user()); @@ -271,10 +270,8 @@ class BillControllerTest extends TestCase $data = [ 'id' => 1, 'name' => 'Updated Bill ' . random_int(1000, 9999), - 'match' => 'some more words', 'amount_min' => '100', - 'amount_currency_id_amount_min' => 1, - 'amount_currency_id_amount_max' => 1, + 'transaction_currency_id' => 1, 'skip' => 0, 'amount_max' => '100', 'date' => '2016-01-01', diff --git a/tests/Unit/Factory/BillFactoryTest.php b/tests/Unit/Factory/BillFactoryTest.php index 7b8bf5f07e..7f4d83b1b3 100644 --- a/tests/Unit/Factory/BillFactoryTest.php +++ b/tests/Unit/Factory/BillFactoryTest.php @@ -42,16 +42,16 @@ class BillFactoryTest extends TestCase public function testCreateBasic() { $data = [ - 'name' => 'Some new bill #' . random_int(1, 1000), - 'match' => 'i,am,word' . random_int(1, 1000), - 'amount_min' => '5', - 'amount_max' => '10', - 'date' => '2018-01-01', - 'repeat_freq' => 'monthly', - 'skip' => 0, - 'automatch' => true, - 'active' => true, - 'notes' => 'Hello!', + 'name' => 'Some new bill #' . random_int(1, 1000), + 'amount_min' => '5', + 'transaction_currency_id' => 1, + 'amount_max' => '10', + 'date' => '2018-01-01', + 'repeat_freq' => 'monthly', + 'skip' => 0, + 'automatch' => true, + 'active' => true, + 'notes' => 'Hello!', ]; /** @var BillFactory $factory */ @@ -60,7 +60,6 @@ class BillFactoryTest extends TestCase $bill = $factory->create($data); $this->assertEquals($data['name'], $bill->name); - $this->assertEquals($data['match'], $bill->match); $this->assertEquals($data['amount_min'], $bill->amount_min); $this->assertEquals($data['repeat_freq'], $bill->repeat_freq); $note = $bill->notes()->first(); @@ -77,16 +76,16 @@ class BillFactoryTest extends TestCase public function testCreateEmptyNotes() { $data = [ - 'name' => 'Some new bill #' . random_int(1, 1000), - 'match' => 'i,am,word' . random_int(1, 1000), - 'amount_min' => '5', - 'amount_max' => '10', - 'date' => '2018-01-01', - 'repeat_freq' => 'monthly', - 'skip' => 0, - 'automatch' => true, - 'active' => true, - 'notes' => '', + 'name' => 'Some new bill #' . random_int(1, 1000), + 'amount_min' => '5', + 'amount_max' => '10', + 'date' => '2018-01-01', + 'repeat_freq' => 'monthly', + 'transaction_currency_id' => 1, + 'skip' => 0, + 'automatch' => true, + 'active' => true, + 'notes' => '', ]; /** @var BillFactory $factory */ @@ -95,7 +94,6 @@ class BillFactoryTest extends TestCase $bill = $factory->create($data); $this->assertEquals($data['name'], $bill->name); - $this->assertEquals($data['match'], $bill->match); $this->assertEquals($data['amount_min'], $bill->amount_min); $this->assertEquals($data['repeat_freq'], $bill->repeat_freq); $this->assertEquals(0, $bill->notes()->count()); diff --git a/tests/Unit/Transformers/BillTransformerTest.php b/tests/Unit/Transformers/BillTransformerTest.php index 75cee9e995..a7a0c714d8 100644 --- a/tests/Unit/Transformers/BillTransformerTest.php +++ b/tests/Unit/Transformers/BillTransformerTest.php @@ -49,15 +49,16 @@ class BillTransformerTest extends TestCase $bill = Bill::create( [ - 'user_id' => $this->user()->id, - 'name' => 'Some bill ' . random_int(1, 10000), - 'match' => 'word,' . random_int(1, 10000), - 'amount_min' => 12.34, - 'amount_max' => 45.67, - 'date' => '2018-01-02', - 'repeat_freq' => 'weekly', - 'skip' => 0, - 'active' => 1, + 'user_id' => $this->user()->id, + 'name' => 'Some bill ' . random_int(1, 10000), + 'match' => 'word,' . random_int(1, 10000), + 'amount_min' => 12.34, + 'amount_max' => 45.67, + 'transaction_currency_id' => 1, + 'date' => '2018-01-02', + 'repeat_freq' => 'weekly', + 'skip' => 0, + 'active' => 1, ] ); $transformer = new BillTransformer(new ParameterBag); @@ -77,15 +78,16 @@ class BillTransformerTest extends TestCase $bill = Bill::create( [ - 'user_id' => $this->user()->id, - 'name' => 'Some bill ' . random_int(1, 10000), - 'match' => 'word,' . random_int(1, 10000), - 'amount_min' => 12.34, - 'amount_max' => 45.67, - 'date' => '2018-01-02', - 'repeat_freq' => 'weekly', - 'skip' => 0, - 'active' => 1, + 'user_id' => $this->user()->id, + 'name' => 'Some bill ' . random_int(1, 10000), + 'match' => 'word,' . random_int(1, 10000), + 'amount_min' => 12.34, + 'amount_max' => 45.67, + 'date' => '2018-01-02', + 'transaction_currency_id' => 1, + 'repeat_freq' => 'weekly', + 'skip' => 0, + 'active' => 1, ] ); $noteText = 'I are a note ' . random_int(1, 10000); @@ -121,15 +123,16 @@ class BillTransformerTest extends TestCase $repository->shouldReceive('getPaidDatesInRange')->andReturn(new Collection([new Carbon('2018-01-02')])); $bill = Bill::create( [ - 'user_id' => $this->user()->id, - 'name' => 'Some bill ' . random_int(1, 10000), - 'match' => 'word,' . random_int(1, 10000), - 'amount_min' => 12.34, - 'amount_max' => 45.67, - 'date' => '2018-01-02', - 'repeat_freq' => 'monthly', - 'skip' => 0, - 'active' => 1, + 'user_id' => $this->user()->id, + 'name' => 'Some bill ' . random_int(1, 10000), + 'match' => 'word,' . random_int(1, 10000), + 'amount_min' => 12.34, + 'amount_max' => 45.67, + 'date' => '2018-01-02', + 'transaction_currency_id' => 1, + 'repeat_freq' => 'monthly', + 'skip' => 0, + 'active' => 1, ] ); $parameters = new ParameterBag(); From 191401f32ba97c6fb8da03acd2c3b6a437b27cf8 Mon Sep 17 00:00:00 2001 From: James Cole Date: Sat, 14 Apr 2018 22:37:20 +0200 Subject: [PATCH 028/117] Fix division by zero. --- app/Repositories/Budget/BudgetRepository.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/app/Repositories/Budget/BudgetRepository.php b/app/Repositories/Budget/BudgetRepository.php index 41bef35866..687f5afaef 100644 --- a/app/Repositories/Budget/BudgetRepository.php +++ b/app/Repositories/Budget/BudgetRepository.php @@ -61,7 +61,10 @@ class BudgetRepository implements BudgetRepositoryInterface $total = '0'; $count = 0; foreach ($budget->budgetlimits as $limit) { - $diff = (string)$limit->start_date->diffInDays($limit->end_date); + $diff = (string)$limit->start_date->diffInDays($limit->end_date); + if (bccomp('0', $diff) === 0) { + $diff = '1'; + } $amount = (string)$limit->amount; $perDay = bcdiv($amount, $diff); $total = bcadd($total, $perDay); From 4b019fe38b319d608751da710561ae1c914caea1 Mon Sep 17 00:00:00 2001 From: James Cole Date: Sat, 14 Apr 2018 23:06:27 +0200 Subject: [PATCH 029/117] Limit scope in transaction matcher. --- app/TransactionRules/TransactionMatcher.php | 53 +++++++++++++++++++-- 1 file changed, 48 insertions(+), 5 deletions(-) diff --git a/app/TransactionRules/TransactionMatcher.php b/app/TransactionRules/TransactionMatcher.php index 83fc9c268b..e3f154a1c4 100644 --- a/app/TransactionRules/TransactionMatcher.php +++ b/app/TransactionRules/TransactionMatcher.php @@ -24,6 +24,7 @@ namespace FireflyIII\TransactionRules; use FireflyIII\Helpers\Collector\JournalCollectorInterface; use FireflyIII\Models\Rule; +use FireflyIII\Models\RuleTrigger; use FireflyIII\Models\Transaction; use FireflyIII\Models\TransactionType; use Illuminate\Support\Collection; @@ -35,8 +36,14 @@ use Log; */ class TransactionMatcher { + /** @var string */ + private $exactAmount; /** @var int Limit of matcher */ private $limit = 10; + /** @var string */ + private $maxAmount; + /** @var string */ + private $minAmount; /** @var int Maximum number of transaction to search in (for performance reasons) * */ private $range = 200; /** @var Rule The rule to apply */ @@ -56,7 +63,7 @@ class TransactionMatcher */ public function findTransactionsByRule(): Collection { - if (0 === count($this->rule->ruleTriggers)) { + if (0 === \count($this->rule->ruleTriggers)) { return new Collection; } @@ -81,7 +88,7 @@ class TransactionMatcher */ public function findTransactionsByTriggers(): Collection { - if (0 === count($this->triggers)) { + if (0 === \count($this->triggers)) { return new Collection; } @@ -173,11 +180,34 @@ class TransactionMatcher * * @param Rule $rule */ - public function setRule(Rule $rule) + public function setRule(Rule $rule): void { $this->rule = $rule; } + /** + * + */ + private function readTriggers(): void + { + $valid = ['amount_less', 'amount_more', 'amount_exactly']; + if (null !== $this->rule) { + $allTriggers = $this->rule->ruleTriggers()->whereIn('trigger_type', $valid)->get(); + /** @var RuleTrigger $trigger */ + foreach ($allTriggers as $trigger) { + if ($trigger->trigger_type === 'amount_less') { + $this->maxAmount = $trigger->trigger_value; + } + if ($trigger->trigger_type === 'amount_more') { + $this->minAmount = $trigger->trigger_value; + } + if ($trigger->trigger_type === 'amount_exactly') { + $this->exactAmount = $trigger->trigger_value; + } + } + } + } + /** * Run the processor. * @@ -188,6 +218,12 @@ class TransactionMatcher */ private function runProcessor(Processor $processor): Collection { + // since we have a rule in $this->rule, we can add some of the triggers + // to the Journal Collector. + // Firefly III will then have to search through less transactions. + $this->readTriggers(); + + // Start a loop to fetch batches of transactions. The loop will finish if: // - all transactions have been fetched from the database // - the maximum number of transactions to return has been found @@ -202,8 +238,15 @@ class TransactionMatcher $collector = app(JournalCollectorInterface::class); $collector->setUser(auth()->user()); $collector->setAllAssetAccounts()->setLimit($pageSize)->setPage($page)->setTypes($this->transactionTypes); - - + if (null !== $this->maxAmount) { + $collector->amountLess($this->maxAmount); + } + if (null !== $this->minAmount) { + $collector->amountMore($this->minAmount); + } + if (null !== $this->exactAmount) { + $collector->amountIs($this->exactAmount); + } $set = $collector->getPaginatedJournals(); From f4afcb4d50951442013e3847f0f2bdb45c12395a Mon Sep 17 00:00:00 2001 From: James Cole Date: Sat, 14 Apr 2018 23:09:24 +0200 Subject: [PATCH 030/117] Add debug logging [skip ci] --- app/TransactionRules/TransactionMatcher.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/app/TransactionRules/TransactionMatcher.php b/app/TransactionRules/TransactionMatcher.php index e3f154a1c4..8a204fd3b0 100644 --- a/app/TransactionRules/TransactionMatcher.php +++ b/app/TransactionRules/TransactionMatcher.php @@ -197,12 +197,15 @@ class TransactionMatcher foreach ($allTriggers as $trigger) { if ($trigger->trigger_type === 'amount_less') { $this->maxAmount = $trigger->trigger_value; + Log::debug(sprintf('Set max amount to be %s', $trigger->trigger_value)); } if ($trigger->trigger_type === 'amount_more') { $this->minAmount = $trigger->trigger_value; + Log::debug(sprintf('Set min amount to be %s', $trigger->trigger_value)); } if ($trigger->trigger_type === 'amount_exactly') { $this->exactAmount = $trigger->trigger_value; + Log::debug(sprintf('Set exact amount to be %s', $trigger->trigger_value)); } } } @@ -239,12 +242,15 @@ class TransactionMatcher $collector->setUser(auth()->user()); $collector->setAllAssetAccounts()->setLimit($pageSize)->setPage($page)->setTypes($this->transactionTypes); if (null !== $this->maxAmount) { + Log::debug(sprintf('Amount must be less than %s', $this->maxAmount)); $collector->amountLess($this->maxAmount); } if (null !== $this->minAmount) { + Log::debug(sprintf('Amount must be more than %s', $this->minAmount)); $collector->amountMore($this->minAmount); } if (null !== $this->exactAmount) { + Log::debug(sprintf('Amount must be exactly %s', $this->exactAmount)); $collector->amountIs($this->exactAmount); } From 38b1fc7aa6d6f3f48a7663537c0354ef782967cb Mon Sep 17 00:00:00 2001 From: James Cole Date: Sat, 14 Apr 2018 23:12:54 +0200 Subject: [PATCH 031/117] Improve logging [skip ci] --- app/TransactionRules/Triggers/AmountExactly.php | 4 ++-- app/TransactionRules/Triggers/AmountLess.php | 4 ++-- app/TransactionRules/Triggers/AmountMore.php | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/app/TransactionRules/Triggers/AmountExactly.php b/app/TransactionRules/Triggers/AmountExactly.php index cabe53c3df..678cfd5f23 100644 --- a/app/TransactionRules/Triggers/AmountExactly.php +++ b/app/TransactionRules/Triggers/AmountExactly.php @@ -75,11 +75,11 @@ final class AmountExactly extends AbstractTrigger implements TriggerInterface $compare = $this->triggerValue; $result = bccomp($amount, $compare); if (0 === $result) { - Log::debug(sprintf('RuleTrigger AmountExactly for journal #%d: %d matches %d exactly, so return true', $journal->id, $amount, $compare)); + Log::debug(sprintf('RuleTrigger AmountExactly for journal #%d: %f matches %f exactly, so return true', $journal->id, $amount, $compare)); return true; } - Log::debug(sprintf('RuleTrigger AmountExactly for journal #%d: %d matches %d NOT exactly, so return false', $journal->id, $amount, $compare)); + Log::debug(sprintf('RuleTrigger AmountExactly for journal #%d: %f matches %f NOT exactly, so return false', $journal->id, $amount, $compare)); return false; } diff --git a/app/TransactionRules/Triggers/AmountLess.php b/app/TransactionRules/Triggers/AmountLess.php index d39579ab17..13325ef037 100644 --- a/app/TransactionRules/Triggers/AmountLess.php +++ b/app/TransactionRules/Triggers/AmountLess.php @@ -74,12 +74,12 @@ final class AmountLess extends AbstractTrigger implements TriggerInterface $compare = $this->triggerValue; $result = bccomp($amount, $compare); if ($result === -1) { - Log::debug(sprintf('RuleTrigger AmountLess for journal #%d: %d is less than %d, so return true', $journal->id, $amount, $compare)); + Log::debug(sprintf('RuleTrigger AmountLess for journal #%d: %f is less than %f, so return true', $journal->id, $amount, $compare)); return true; } - Log::debug(sprintf('RuleTrigger AmountLess for journal #%d: %d is NOT less than %d, so return false', $journal->id, $amount, $compare)); + Log::debug(sprintf('RuleTrigger AmountLess for journal #%d: %f is NOT less than %f, so return false', $journal->id, $amount, $compare)); return false; } diff --git a/app/TransactionRules/Triggers/AmountMore.php b/app/TransactionRules/Triggers/AmountMore.php index 545542b279..3914513bd8 100644 --- a/app/TransactionRules/Triggers/AmountMore.php +++ b/app/TransactionRules/Triggers/AmountMore.php @@ -80,12 +80,12 @@ final class AmountMore extends AbstractTrigger implements TriggerInterface $compare = $this->triggerValue; $result = bccomp($amount, $compare); if (1 === $result) { - Log::debug(sprintf('RuleTrigger AmountMore for journal #%d: %d is more than %d, so return true', $journal->id, $amount, $compare)); + Log::debug(sprintf('RuleTrigger AmountMore for journal #%d: %f is more than %f, so return true', $journal->id, $amount, $compare)); return true; } - Log::debug(sprintf('RuleTrigger AmountMore for journal #%d: %d is NOT more than %d, so return false', $journal->id, $amount, $compare)); + Log::debug(sprintf('RuleTrigger AmountMore for journal #%d: %f is NOT more than %f, so return false', $journal->id, $amount, $compare)); return false; } From b2aa73b31e5ff8609ad8f0d3c431e665146d254e Mon Sep 17 00:00:00 2001 From: James Cole Date: Sat, 14 Apr 2018 23:23:47 +0200 Subject: [PATCH 032/117] Improve transaction linking [skip ci] --- app/Repositories/Bill/BillRepository.php | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/app/Repositories/Bill/BillRepository.php b/app/Repositories/Bill/BillRepository.php index 49e8a68e84..d8f501f922 100644 --- a/app/Repositories/Bill/BillRepository.php +++ b/app/Repositories/Bill/BillRepository.php @@ -28,7 +28,6 @@ use FireflyIII\Factory\BillFactory; use FireflyIII\Models\Bill; use FireflyIII\Models\Transaction; use FireflyIII\Models\TransactionJournal; -use FireflyIII\Models\TransactionType; use FireflyIII\Repositories\Journal\JournalRepositoryInterface; use FireflyIII\Services\Internal\Destroy\BillDestroyService; use FireflyIII\Services\Internal\Update\BillUpdateService; @@ -427,11 +426,12 @@ class BillRepository implements BillRepositoryInterface */ public function linkCollectionToBill(Bill $bill, Collection $journals): void { - $ids = $journals->pluck('id')->toArray(); - DB::table('transaction_journals') - ->where('user_id', $this->user->id) - ->whereIn('id', $ids) - ->update(['bill_id' => $bill->id]); + /** @var TransactionJournal $journal */ + foreach ($journals as $journal) { + $journal->bill_id = $bill->id; + $journal->save(); + Log::debug(sprintf('Linked journal #%d to bill #%d', $journal->id, $bill->id)); + } } /** From 6c123373172b4720f0904b139e4b4b30c03dee6f Mon Sep 17 00:00:00 2001 From: James Cole Date: Sat, 14 Apr 2018 23:25:28 +0200 Subject: [PATCH 033/117] Improve transaction linking [skip ci] --- app/Repositories/Bill/BillRepository.php | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/app/Repositories/Bill/BillRepository.php b/app/Repositories/Bill/BillRepository.php index d8f501f922..f7acc46d9f 100644 --- a/app/Repositories/Bill/BillRepository.php +++ b/app/Repositories/Bill/BillRepository.php @@ -422,12 +422,13 @@ class BillRepository implements BillRepositoryInterface * Link a set of journals to a bill. * * @param Bill $bill - * @param Collection $journals + * @param Collection $transactions */ - public function linkCollectionToBill(Bill $bill, Collection $journals): void + public function linkCollectionToBill(Bill $bill, Collection $transactions): void { - /** @var TransactionJournal $journal */ - foreach ($journals as $journal) { + /** @var Transaction $transaction */ + foreach ($transactions as $transaction) { + $journal = $transaction->transactionJournal; $journal->bill_id = $bill->id; $journal->save(); Log::debug(sprintf('Linked journal #%d to bill #%d', $journal->id, $bill->id)); From dbe17debb4611d9346a024793a732fc0d30de6ff Mon Sep 17 00:00:00 2001 From: Brenden Conte Date: Sun, 15 Apr 2018 02:35:47 -0400 Subject: [PATCH 034/117] Remove the 'php artisan optimize' line from .deploy/docker/entroypoint.sh because the command was removed in artisan 5.6 --- .deploy/docker/entrypoint.sh | 1 - 1 file changed, 1 deletion(-) diff --git a/.deploy/docker/entrypoint.sh b/.deploy/docker/entrypoint.sh index bfafaaf3b3..17d62270c3 100755 --- a/.deploy/docker/entrypoint.sh +++ b/.deploy/docker/entrypoint.sh @@ -9,7 +9,6 @@ rm -f $FIREFLY_PATH/storage/logs/laravel.log cat .env.docker | envsubst > .env && cat .env composer dump-autoload -php artisan optimize php artisan package:discover php artisan firefly:instructions install exec apache2-foreground From 0c2c5d53445ec861bdebb8f89a01404198bfe66b Mon Sep 17 00:00:00 2001 From: James Cole Date: Sun, 15 Apr 2018 08:52:58 +0200 Subject: [PATCH 035/117] Code for #1326 --- app/Http/Controllers/NewUserController.php | 100 +++++++++++++++------ config/firefly.php | 2 +- resources/lang/en_US/firefly.php | 16 +++- resources/lang/en_US/form.php | 3 +- resources/lang/en_US/intro.php | 1 + resources/views/new-user/index.twig | 18 ++++ 6 files changed, 107 insertions(+), 33 deletions(-) diff --git a/app/Http/Controllers/NewUserController.php b/app/Http/Controllers/NewUserController.php index 2be34e546d..0e0e74445d 100644 --- a/app/Http/Controllers/NewUserController.php +++ b/app/Http/Controllers/NewUserController.php @@ -24,6 +24,7 @@ namespace FireflyIII\Http\Controllers; use Carbon\Carbon; use FireflyIII\Http\Requests\NewUserFormRequest; +use FireflyIII\Models\TransactionCurrency; use FireflyIII\Repositories\Account\AccountRepositoryInterface; use FireflyIII\Repositories\Currency\CurrencyRepositoryInterface; use Preferences; @@ -35,6 +36,9 @@ use View; */ class NewUserController extends Controller { + /** @var AccountRepositoryInterface */ + private $repository; + /** * NewUserController constructor. */ @@ -44,55 +48,70 @@ class NewUserController extends Controller $this->middleware( function ($request, $next) { + $this->repository = app(AccountRepositoryInterface::class); + return $next($request); } ); } /** - * @param AccountRepositoryInterface $repository - * * @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector|View */ - public function index(AccountRepositoryInterface $repository) + public function index() { app('view')->share('title', trans('firefly.welcome')); app('view')->share('mainTitleIcon', 'fa-fire'); $types = config('firefly.accountTypesByIdentifier.asset'); - $count = $repository->count($types); + $count = $this->repository->count($types); + + $languages = []; if ($count > 0) { return redirect(route('index')); } - return view('new-user.index'); + return view('new-user.index', compact('languages')); } /** * @param NewUserFormRequest $request - * @param AccountRepositoryInterface $repository * @param CurrencyRepositoryInterface $currencyRepository * * @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector */ - public function submit(NewUserFormRequest $request, AccountRepositoryInterface $repository, CurrencyRepositoryInterface $currencyRepository) + public function submit(NewUserFormRequest $request, CurrencyRepositoryInterface $currencyRepository) { - // create normal asset account: - $this->createAssetAccount($request, $repository); + $language = $request->string('language'); + if (!array_key_exists($language, config('firefly.languages'))) { + $language = 'en_US'; - // create savings account - $this->createSavingsAccount($request, $repository); + } - // also store currency preference from input: + // set language preference: + Preferences::set('language', $language); + // Store currency preference from input: $currency = $currencyRepository->findNull((int)$request->input('amount_currency_id_bank_balance')); - if (null !== $currency) { - // store currency preference: - Preferences::set('currencyPreference', $currency->code); - Preferences::mark(); + // if is null, set to EUR: + if (null === $currency) { + $currency = $currencyRepository->findByCodeNull('EUR'); } + // create normal asset account: + $this->createAssetAccount($request, $currency); + + // create savings account + $this->createSavingsAccount($request, $currency, $language); + + // create cash wallet account + $this->createCashWalletAccount($currency, $language); + + // store currency preference: + Preferences::set('currencyPreference', $currency->code); + Preferences::mark(); + // set default optional fields: $visibleFields = [ 'interest_date' => true, @@ -114,12 +133,12 @@ class NewUserController extends Controller } /** - * @param NewUserFormRequest $request - * @param AccountRepositoryInterface $repository + * @param NewUserFormRequest $request + * @param TransactionCurrency $currency * * @return bool */ - private function createAssetAccount(NewUserFormRequest $request, AccountRepositoryInterface $repository): bool + private function createAssetAccount(NewUserFormRequest $request, TransactionCurrency $currency): bool { $assetAccount = [ 'name' => $request->get('bank_name'), @@ -131,24 +150,51 @@ class NewUserController extends Controller 'accountRole' => 'defaultAsset', 'openingBalance' => $request->input('bank_balance'), 'openingBalanceDate' => new Carbon, - 'currency_id' => (int)$request->input('amount_currency_id_bank_balance'), + 'currency_id' => $currency->id, ]; - $repository->store($assetAccount); + $this->repository->store($assetAccount); return true; } /** - * @param NewUserFormRequest $request - * @param AccountRepositoryInterface $repository + * @param TransactionCurrency $currency + * @param string $language * * @return bool */ - private function createSavingsAccount(NewUserFormRequest $request, AccountRepositoryInterface $repository): bool + private function createCashWalletAccount(TransactionCurrency $currency, string $language): bool + { + $assetAccount = [ + 'name' => (string)trans('firefly.cash_wallet', [], $language), + 'iban' => null, + 'accountType' => 'asset', + 'virtualBalance' => 0, + 'account_type_id' => null, + 'active' => true, + 'accountRole' => 'cashWalletAsset', + 'openingBalance' => null, + 'openingBalanceDate' => null, + 'currency_id' => $currency->id, + ]; + + $this->repository->store($assetAccount); + + return true; + } + + /** + * @param NewUserFormRequest $request + * @param TransactionCurrency $currency + * @param string $language + * + * @return bool + */ + private function createSavingsAccount(NewUserFormRequest $request, TransactionCurrency $currency, string $language): bool { $savingsAccount = [ - 'name' => $request->get('bank_name') . ' savings account', + 'name' => (string)trans('firefly.new_savings_account', ['bank_name' => $request->get('bank_name')], $language), 'iban' => null, 'accountType' => 'asset', 'account_type_id' => null, @@ -157,9 +203,9 @@ class NewUserController extends Controller 'accountRole' => 'savingAsset', 'openingBalance' => $request->input('savings_balance'), 'openingBalanceDate' => new Carbon, - 'currency_id' => (int)$request->input('amount_currency_id_bank_balance'), + 'currency_id' => $currency->id, ]; - $repository->store($savingsAccount); + $this->repository->store($savingsAccount); return true; } diff --git a/config/firefly.php b/config/firefly.php index b4376d888c..f5b8183ed7 100644 --- a/config/firefly.php +++ b/config/firefly.php @@ -165,7 +165,7 @@ return [ 'default_export_format' => 'csv', 'default_import_format' => 'csv', 'bill_periods' => ['weekly', 'monthly', 'quarterly', 'half-year', 'yearly'], - 'accountRoles' => ['defaultAsset', 'sharedAsset', 'savingAsset', 'ccAsset',], + 'accountRoles' => ['defaultAsset', 'sharedAsset', 'savingAsset', 'ccAsset','cashWalletAsset'], 'ccTypes' => [ 'monthlyFull' => 'Full payment every month', ], diff --git a/resources/lang/en_US/firefly.php b/resources/lang/en_US/firefly.php index 162a18e399..0f8eb06692 100644 --- a/resources/lang/en_US/firefly.php +++ b/resources/lang/en_US/firefly.php @@ -267,7 +267,10 @@ return [ 'move_rule_group_down' => 'Move rule group down', 'save_rules_by_moving' => 'Save these rule(s) by moving them to another rule group:', 'make_new_rule' => 'Make new rule in rule group ":title"', + 'rule_is_strict' => 'strict rule', + 'rule_is_not_strict' => 'non-strict rule', 'rule_help_stop_processing' => 'When you check this box, later rules in this group will not be executed.', + 'rule_help_strict' => 'In strict rules ALL triggers must fire for the action(s) to be executed. In non-strict rules, ANY trigger is enough for the action(s) to be executed.', 'rule_help_active' => 'Inactive rules will never fire.', 'stored_new_rule' => 'Stored new rule with title ":title"', 'deleted_rule' => 'Deleted rule with title ":title"', @@ -636,8 +639,8 @@ return [ 'over_budget_warn' => ' Normally you budget about :amount per day. This is :over_amount per day.', // bills: - 'matching_on' => 'Matching on', - 'between_amounts' => 'between :low and :high.', + 'match_between_amounts' => 'Bill matches transactions between :low and :high.', + 'bill_related_rules' => 'Rules related to this bill', 'repeats' => 'Repeats', 'connected_journals' => 'Connected transactions', 'auto_match_on' => 'Automatically matched by Firefly III', @@ -647,13 +650,13 @@ return [ 'deleted_bill' => 'Deleted bill ":name"', 'edit_bill' => 'Edit bill ":name"', 'more' => 'More', - 'rescan_old' => 'Rescan old transactions', + 'rescan_old' => 'Run rules again, on all transactions', 'update_bill' => 'Update bill', 'updated_bill' => 'Updated bill ":name"', 'store_new_bill' => 'Store new bill', 'stored_new_bill' => 'Stored new bill ":name"', 'cannot_scan_inactive_bill' => 'Inactive bills cannot be scanned.', - 'rescanned_bill' => 'Rescanned everything.', + 'rescanned_bill' => 'Rescanned everything, and linked :total transaction(s) to the bill.', 'average_bill_amount_year' => 'Average bill amount (:year)', 'average_bill_amount_overall' => 'Average bill amount (overall)', 'bill_is_active' => 'Bill is active', @@ -807,6 +810,10 @@ return [ 'savings_balance_text' => 'Firefly III will automatically create a savings account for you. By default, there will be no money in your savings account, but if you tell Firefly III the balance it will be stored as such.', 'finish_up_new_user' => 'That\'s it! You can continue by pressing Submit. You will be taken to the index of Firefly III.', 'stored_new_accounts_new_user' => 'Yay! Your new accounts have been stored.', + 'set_preferred_language' => 'If you prefer to use Firefly III in another language, please indicate so here.', + 'language' => 'Language', + 'new_savings_account' => ':bank_name savings account', + 'cash_wallet' => 'Cash wallet', // home page: 'yourAccounts' => 'Your accounts', @@ -955,6 +962,7 @@ return [ 'account_role_sharedAsset' => 'Shared asset account', 'account_role_savingAsset' => 'Savings account', 'account_role_ccAsset' => 'Credit card', + 'account_role_cashWalletAsset' => 'Cash wallet', 'budget_chart_click' => 'Please click on a budget name in the table above to see a chart.', 'category_chart_click' => 'Please click on a category name in the table above to see a chart.', 'in_out_accounts' => 'Earned and spent per combination', diff --git a/resources/lang/en_US/form.php b/resources/lang/en_US/form.php index af213d8bbc..e763ae382d 100644 --- a/resources/lang/en_US/form.php +++ b/resources/lang/en_US/form.php @@ -34,11 +34,12 @@ return [ 'amount_min' => 'Minimum amount', 'amount_max' => 'Maximum amount', 'match' => 'Matches on', + 'strict' => 'Strict mode', 'repeat_freq' => 'Repeats', 'journal_currency_id' => 'Currency', 'currency_id' => 'Currency', 'transaction_currency_id' => 'Currency', - 'external_ip' => 'Your server\'s external IP', + 'external_ip' => 'Your server\'s external IP', 'attachments' => 'Attachments', 'journal_amount' => 'Amount', 'journal_source_account_name' => 'Revenue account (source)', diff --git a/resources/lang/en_US/intro.php b/resources/lang/en_US/intro.php index f5f1201be2..1d442a8d48 100644 --- a/resources/lang/en_US/intro.php +++ b/resources/lang/en_US/intro.php @@ -92,6 +92,7 @@ return [ 'piggy-banks_show_piggyEvents' => 'Any additions or removals are also listed here.', // bill index + 'bills_index_rules' => 'Here you see which rules will check if this bill is hit', 'bills_index_paid_in_period' => 'This field indicates when the bill was last paid.', 'bills_index_expected_in_period' => 'This field indicates for each bill if and when the next bill is expected to hit.', diff --git a/resources/views/new-user/index.twig b/resources/views/new-user/index.twig index e3f4b8a2e5..3f7022e34a 100644 --- a/resources/views/new-user/index.twig +++ b/resources/views/new-user/index.twig @@ -33,6 +33,24 @@ {{ ExpandedForm.number('savings_balance',0) }} +

    + {{ 'set_preferred_language'|_ }} +

    +
    + +
    + +
    +
    + +

    {{ 'finish_up_new_user'|_ }}

    From ef62e31b616dc5fe69e6bc420f125eacf67ba3e7 Mon Sep 17 00:00:00 2001 From: James Cole Date: Sun, 15 Apr 2018 10:12:04 +0200 Subject: [PATCH 036/117] Fix #1246 --- app/Http/Controllers/Controller.php | 4 + public/js/ff/moment/de_DE.js | 83 ++++++++++++ public/js/ff/moment/en_US.js | 1 + public/js/ff/moment/es_ES.js | 79 ++++++++++++ public/js/ff/moment/fr_FR.js | 71 ++++++++++ public/js/ff/moment/id_ID.js | 69 ++++++++++ public/js/ff/moment/it_IT.js | 56 ++++++++ public/js/ff/moment/nl_NL.js | 75 +++++++++++ public/js/ff/moment/pl_PL.js | 113 ++++++++++++++++ public/js/ff/moment/pt_BR.js | 48 +++++++ public/js/ff/moment/ru_RU.js | 169 ++++++++++++++++++++++++ public/js/ff/moment/tr_TR.js | 192 ++++++++++++++++++++++++++++ resources/views/layout/default.twig | 1 + 13 files changed, 961 insertions(+) create mode 100644 public/js/ff/moment/de_DE.js create mode 100644 public/js/ff/moment/en_US.js create mode 100644 public/js/ff/moment/es_ES.js create mode 100644 public/js/ff/moment/fr_FR.js create mode 100644 public/js/ff/moment/id_ID.js create mode 100644 public/js/ff/moment/it_IT.js create mode 100644 public/js/ff/moment/nl_NL.js create mode 100644 public/js/ff/moment/pl_PL.js create mode 100644 public/js/ff/moment/pt_BR.js create mode 100644 public/js/ff/moment/ru_RU.js create mode 100644 public/js/ff/moment/tr_TR.js diff --git a/app/Http/Controllers/Controller.php b/app/Http/Controllers/Controller.php index 851a8efff5..e9135c4698 100644 --- a/app/Http/Controllers/Controller.php +++ b/app/Http/Controllers/Controller.php @@ -98,6 +98,10 @@ class Controller extends BaseController Log::debug(sprintf('Check if user has already seen intro with key "%s". Result is %d', $key, $shownDemo)); } + // share language + $language = Preferences::get('language', config('firefly.default_language', 'en_US'))->data; + + View::share('language', $language); View::share('shownDemo', $shownDemo); View::share('current_route_name', $page); View::share('original_route_name', Route::currentRouteName()); diff --git a/public/js/ff/moment/de_DE.js b/public/js/ff/moment/de_DE.js new file mode 100644 index 0000000000..c016aa2489 --- /dev/null +++ b/public/js/ff/moment/de_DE.js @@ -0,0 +1,83 @@ +/* + * de_DE.js + * Copyright (c) 2018 thegrumpydictator@gmail.com + * + * This file is part of Firefly III. + * + * Firefly III is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Firefly III is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Firefly III. If not, see . + */ + +//! moment.js locale configuration + +function processRelativeTime$2(number, withoutSuffix, key, isFuture) { + var format = { + 'm': ['eine Minute', 'einer Minute'], + 'h': ['eine Stunde', 'einer Stunde'], + 'd': ['ein Tag', 'einem Tag'], + 'dd': [number + ' Tage', number + ' Tagen'], + 'M': ['ein Monat', 'einem Monat'], + 'MM': [number + ' Monate', number + ' Monaten'], + 'y': ['ein Jahr', 'einem Jahr'], + 'yy': [number + ' Jahre', number + ' Jahren'] + }; + return withoutSuffix ? format[key][0] : format[key][1]; +} + +moment.defineLocale('de_DE', { + months : 'Januar_Februar_März_April_Mai_Juni_Juli_August_September_Oktober_November_Dezember'.split('_'), + monthsShort : 'Jan._Feb._März_Apr._Mai_Juni_Juli_Aug._Sep._Okt._Nov._Dez.'.split('_'), + monthsParseExact : true, + weekdays : 'Sonntag_Montag_Dienstag_Mittwoch_Donnerstag_Freitag_Samstag'.split('_'), + weekdaysShort : 'So._Mo._Di._Mi._Do._Fr._Sa.'.split('_'), + weekdaysMin : 'So_Mo_Di_Mi_Do_Fr_Sa'.split('_'), + weekdaysParseExact : true, + longDateFormat : { + LT: 'HH:mm', + LTS: 'HH:mm:ss', + L : 'DD.MM.YYYY', + LL : 'D. MMMM YYYY', + LLL : 'D. MMMM YYYY HH:mm', + LLLL : 'dddd, D. MMMM YYYY HH:mm' + }, + calendar : { + sameDay: '[heute um] LT [Uhr]', + sameElse: 'L', + nextDay: '[morgen um] LT [Uhr]', + nextWeek: 'dddd [um] LT [Uhr]', + lastDay: '[gestern um] LT [Uhr]', + lastWeek: '[letzten] dddd [um] LT [Uhr]' + }, + relativeTime : { + future : 'in %s', + past : 'vor %s', + s : 'ein paar Sekunden', + ss : '%d Sekunden', + m : processRelativeTime$2, + mm : '%d Minuten', + h : processRelativeTime$2, + hh : '%d Stunden', + d : processRelativeTime$2, + dd : processRelativeTime$2, + M : processRelativeTime$2, + MM : processRelativeTime$2, + y : processRelativeTime$2, + yy : processRelativeTime$2 + }, + dayOfMonthOrdinalParse: /\d{1,2}\./, + ordinal : '%d.', + week : { + dow : 1, // Monday is the first day of the week. + doy : 4 // The week that contains Jan 4th is the first week of the year. + } +}); \ No newline at end of file diff --git a/public/js/ff/moment/en_US.js b/public/js/ff/moment/en_US.js new file mode 100644 index 0000000000..fb6112aa93 --- /dev/null +++ b/public/js/ff/moment/en_US.js @@ -0,0 +1 @@ +// default \ No newline at end of file diff --git a/public/js/ff/moment/es_ES.js b/public/js/ff/moment/es_ES.js new file mode 100644 index 0000000000..a5c256c8c6 --- /dev/null +++ b/public/js/ff/moment/es_ES.js @@ -0,0 +1,79 @@ +//! moment.js locale configuration + +var monthsShortDot$2 = 'ene._feb._mar._abr._may._jun._jul._ago._sep._oct._nov._dic.'.split('_'), + monthsShort$3 = 'ene_feb_mar_abr_may_jun_jul_ago_sep_oct_nov_dic'.split('_'); + +var monthsParse$1 = [/^ene/i, /^feb/i, /^mar/i, /^abr/i, /^may/i, /^jun/i, /^jul/i, /^ago/i, /^sep/i, /^oct/i, /^nov/i, /^dic/i]; +var monthsRegex$2 = /^(enero|febrero|marzo|abril|mayo|junio|julio|agosto|septiembre|octubre|noviembre|diciembre|ene\.?|feb\.?|mar\.?|abr\.?|may\.?|jun\.?|jul\.?|ago\.?|sep\.?|oct\.?|nov\.?|dic\.?)/i; + +moment.defineLocale('es', { + months : 'enero_febrero_marzo_abril_mayo_junio_julio_agosto_septiembre_octubre_noviembre_diciembre'.split('_'), + monthsShort : function (m, format) { + if (!m) { + return monthsShortDot$2; + } else if (/-MMM-/.test(format)) { + return monthsShort$3[m.month()]; + } else { + return monthsShortDot$2[m.month()]; + } + }, + monthsRegex : monthsRegex$2, + monthsShortRegex : monthsRegex$2, + monthsStrictRegex : /^(enero|febrero|marzo|abril|mayo|junio|julio|agosto|septiembre|octubre|noviembre|diciembre)/i, + monthsShortStrictRegex : /^(ene\.?|feb\.?|mar\.?|abr\.?|may\.?|jun\.?|jul\.?|ago\.?|sep\.?|oct\.?|nov\.?|dic\.?)/i, + monthsParse : monthsParse$1, + longMonthsParse : monthsParse$1, + shortMonthsParse : monthsParse$1, + weekdays : 'domingo_lunes_martes_miércoles_jueves_viernes_sábado'.split('_'), + weekdaysShort : 'dom._lun._mar._mié._jue._vie._sáb.'.split('_'), + weekdaysMin : 'do_lu_ma_mi_ju_vi_sá'.split('_'), + weekdaysParseExact : true, + longDateFormat : { + LT : 'H:mm', + LTS : 'H:mm:ss', + L : 'DD/MM/YYYY', + LL : 'D [de] MMMM [de] YYYY', + LLL : 'D [de] MMMM [de] YYYY H:mm', + LLLL : 'dddd, D [de] MMMM [de] YYYY H:mm' + }, + calendar : { + sameDay : function () { + return '[hoy a la' + ((this.hours() !== 1) ? 's' : '') + '] LT'; + }, + nextDay : function () { + return '[mañana a la' + ((this.hours() !== 1) ? 's' : '') + '] LT'; + }, + nextWeek : function () { + return 'dddd [a la' + ((this.hours() !== 1) ? 's' : '') + '] LT'; + }, + lastDay : function () { + return '[ayer a la' + ((this.hours() !== 1) ? 's' : '') + '] LT'; + }, + lastWeek : function () { + return '[el] dddd [pasado a la' + ((this.hours() !== 1) ? 's' : '') + '] LT'; + }, + sameElse : 'L' + }, + relativeTime : { + future : 'en %s', + past : 'hace %s', + s : 'unos segundos', + ss : '%d segundos', + m : 'un minuto', + mm : '%d minutos', + h : 'una hora', + hh : '%d horas', + d : 'un día', + dd : '%d días', + M : 'un mes', + MM : '%d meses', + y : 'un año', + yy : '%d años' + }, + dayOfMonthOrdinalParse : /\d{1,2}º/, + ordinal : '%dº', + week : { + dow : 1, // Monday is the first day of the week. + doy : 4 // The week that contains Jan 4th is the first week of the year. + } +}); \ No newline at end of file diff --git a/public/js/ff/moment/fr_FR.js b/public/js/ff/moment/fr_FR.js new file mode 100644 index 0000000000..97b85c5ee6 --- /dev/null +++ b/public/js/ff/moment/fr_FR.js @@ -0,0 +1,71 @@ + + //! moment.js locale configuration + + moment.defineLocale('fr_FR', { + months : 'janvier_février_mars_avril_mai_juin_juillet_août_septembre_octobre_novembre_décembre'.split('_'), + monthsShort : 'janv._févr._mars_avr._mai_juin_juil._août_sept._oct._nov._déc.'.split('_'), + monthsParseExact : true, + weekdays : 'dimanche_lundi_mardi_mercredi_jeudi_vendredi_samedi'.split('_'), + weekdaysShort : 'dim._lun._mar._mer._jeu._ven._sam.'.split('_'), + weekdaysMin : 'di_lu_ma_me_je_ve_sa'.split('_'), + weekdaysParseExact : true, + longDateFormat : { + LT : 'HH:mm', + LTS : 'HH:mm:ss', + L : 'DD/MM/YYYY', + LL : 'D MMMM YYYY', + LLL : 'D MMMM YYYY HH:mm', + LLLL : 'dddd D MMMM YYYY HH:mm' + }, + calendar : { + sameDay : '[Aujourd’hui à] LT', + nextDay : '[Demain à] LT', + nextWeek : 'dddd [à] LT', + lastDay : '[Hier à] LT', + lastWeek : 'dddd [dernier à] LT', + sameElse : 'L' + }, + relativeTime : { + future : 'dans %s', + past : 'il y a %s', + s : 'quelques secondes', + ss : '%d secondes', + m : 'une minute', + mm : '%d minutes', + h : 'une heure', + hh : '%d heures', + d : 'un jour', + dd : '%d jours', + M : 'un mois', + MM : '%d mois', + y : 'un an', + yy : '%d ans' + }, + dayOfMonthOrdinalParse: /\d{1,2}(er|)/, + ordinal : function (number, period) { + switch (period) { + // TODO: Return 'e' when day of month > 1. Move this case inside + // block for masculine words below. + // See https://github.com/moment/moment/issues/3375 + case 'D': + return number + (number === 1 ? 'er' : ''); + + // Words with masculine grammatical gender: mois, trimestre, jour + default: + case 'M': + case 'Q': + case 'DDD': + case 'd': + return number + (number === 1 ? 'er' : 'e'); + + // Words with feminine grammatical gender: semaine + case 'w': + case 'W': + return number + (number === 1 ? 're' : 'e'); + } + }, + week : { + dow : 1, // Monday is the first day of the week. + doy : 4 // The week that contains Jan 4th is the first week of the year. + } + }); \ No newline at end of file diff --git a/public/js/ff/moment/id_ID.js b/public/js/ff/moment/id_ID.js new file mode 100644 index 0000000000..90a4440717 --- /dev/null +++ b/public/js/ff/moment/id_ID.js @@ -0,0 +1,69 @@ +//! moment.js locale configuration + +moment.defineLocale('id_ID', { + months : 'Januari_Februari_Maret_April_Mei_Juni_Juli_Agustus_September_Oktober_November_Desember'.split('_'), + monthsShort : 'Jan_Feb_Mar_Apr_Mei_Jun_Jul_Agt_Sep_Okt_Nov_Des'.split('_'), + weekdays : 'Minggu_Senin_Selasa_Rabu_Kamis_Jumat_Sabtu'.split('_'), + weekdaysShort : 'Min_Sen_Sel_Rab_Kam_Jum_Sab'.split('_'), + weekdaysMin : 'Mg_Sn_Sl_Rb_Km_Jm_Sb'.split('_'), + longDateFormat : { + LT : 'HH.mm', + LTS : 'HH.mm.ss', + L : 'DD/MM/YYYY', + LL : 'D MMMM YYYY', + LLL : 'D MMMM YYYY [pukul] HH.mm', + LLLL : 'dddd, D MMMM YYYY [pukul] HH.mm' + }, + meridiemParse: /pagi|siang|sore|malam/, + meridiemHour : function (hour, meridiem) { + if (hour === 12) { + hour = 0; + } + if (meridiem === 'pagi') { + return hour; + } else if (meridiem === 'siang') { + return hour >= 11 ? hour : hour + 12; + } else if (meridiem === 'sore' || meridiem === 'malam') { + return hour + 12; + } + }, + meridiem : function (hours, minutes, isLower) { + if (hours < 11) { + return 'pagi'; + } else if (hours < 15) { + return 'siang'; + } else if (hours < 19) { + return 'sore'; + } else { + return 'malam'; + } + }, + calendar : { + sameDay : '[Hari ini pukul] LT', + nextDay : '[Besok pukul] LT', + nextWeek : 'dddd [pukul] LT', + lastDay : '[Kemarin pukul] LT', + lastWeek : 'dddd [lalu pukul] LT', + sameElse : 'L' + }, + relativeTime : { + future : 'dalam %s', + past : '%s yang lalu', + s : 'beberapa detik', + ss : '%d detik', + m : 'semenit', + mm : '%d menit', + h : 'sejam', + hh : '%d jam', + d : 'sehari', + dd : '%d hari', + M : 'sebulan', + MM : '%d bulan', + y : 'setahun', + yy : '%d tahun' + }, + week : { + dow : 1, // Monday is the first day of the week. + doy : 7 // The week that contains Jan 1st is the first week of the year. + } +}); \ No newline at end of file diff --git a/public/js/ff/moment/it_IT.js b/public/js/ff/moment/it_IT.js new file mode 100644 index 0000000000..5775d76228 --- /dev/null +++ b/public/js/ff/moment/it_IT.js @@ -0,0 +1,56 @@ +//! moment.js locale configuration + +moment.defineLocale('it_IT', { + months : 'gennaio_febbraio_marzo_aprile_maggio_giugno_luglio_agosto_settembre_ottobre_novembre_dicembre'.split('_'), + monthsShort : 'gen_feb_mar_apr_mag_giu_lug_ago_set_ott_nov_dic'.split('_'), + weekdays : 'domenica_lunedì_martedì_mercoledì_giovedì_venerdì_sabato'.split('_'), + weekdaysShort : 'dom_lun_mar_mer_gio_ven_sab'.split('_'), + weekdaysMin : 'do_lu_ma_me_gi_ve_sa'.split('_'), + longDateFormat : { + LT : 'HH:mm', + LTS : 'HH:mm:ss', + L : 'DD/MM/YYYY', + LL : 'D MMMM YYYY', + LLL : 'D MMMM YYYY HH:mm', + LLLL : 'dddd D MMMM YYYY HH:mm' + }, + calendar : { + sameDay: '[Oggi alle] LT', + nextDay: '[Domani alle] LT', + nextWeek: 'dddd [alle] LT', + lastDay: '[Ieri alle] LT', + lastWeek: function () { + switch (this.day()) { + case 0: + return '[la scorsa] dddd [alle] LT'; + default: + return '[lo scorso] dddd [alle] LT'; + } + }, + sameElse: 'L' + }, + relativeTime : { + future : function (s) { + return ((/^[0-9].+$/).test(s) ? 'tra' : 'in') + ' ' + s; + }, + past : '%s fa', + s : 'alcuni secondi', + ss : '%d secondi', + m : 'un minuto', + mm : '%d minuti', + h : 'un\'ora', + hh : '%d ore', + d : 'un giorno', + dd : '%d giorni', + M : 'un mese', + MM : '%d mesi', + y : 'un anno', + yy : '%d anni' + }, + dayOfMonthOrdinalParse : /\d{1,2}º/, + ordinal: '%dº', + week : { + dow : 1, // Monday is the first day of the week. + doy : 4 // The week that contains Jan 4th is the first week of the year. + } +}); diff --git a/public/js/ff/moment/nl_NL.js b/public/js/ff/moment/nl_NL.js new file mode 100644 index 0000000000..aa531709fd --- /dev/null +++ b/public/js/ff/moment/nl_NL.js @@ -0,0 +1,75 @@ + +//! moment.js locale configuration + +var monthsShortWithDots$2 = 'jan._feb._mrt._apr._mei_jun._jul._aug._sep._okt._nov._dec.'.split('_'), + monthsShortWithoutDots$2 = 'jan_feb_mrt_apr_mei_jun_jul_aug_sep_okt_nov_dec'.split('_'); + +var monthsParse$3 = [/^jan/i, /^feb/i, /^maart|mrt.?$/i, /^apr/i, /^mei$/i, /^jun[i.]?$/i, /^jul[i.]?$/i, /^aug/i, /^sep/i, /^okt/i, /^nov/i, /^dec/i]; +var monthsRegex$4 = /^(januari|februari|maart|april|mei|april|ju[nl]i|augustus|september|oktober|november|december|jan\.?|feb\.?|mrt\.?|apr\.?|ju[nl]\.?|aug\.?|sep\.?|okt\.?|nov\.?|dec\.?)/i; + +moment.defineLocale('nl_NL', { + months : 'januari_februari_maart_april_mei_juni_juli_augustus_september_oktober_november_december'.split('_'), + monthsShort : function (m, format) { + if (!m) { + return monthsShortWithDots$2; + } else if (/-MMM-/.test(format)) { + return monthsShortWithoutDots$2[m.month()]; + } else { + return monthsShortWithDots$2[m.month()]; + } + }, + + monthsRegex: monthsRegex$4, + monthsShortRegex: monthsRegex$4, + monthsStrictRegex: /^(januari|februari|maart|mei|ju[nl]i|april|augustus|september|oktober|november|december)/i, + monthsShortStrictRegex: /^(jan\.?|feb\.?|mrt\.?|apr\.?|mei|ju[nl]\.?|aug\.?|sep\.?|okt\.?|nov\.?|dec\.?)/i, + + monthsParse : monthsParse$3, + longMonthsParse : monthsParse$3, + shortMonthsParse : monthsParse$3, + + weekdays : 'zondag_maandag_dinsdag_woensdag_donderdag_vrijdag_zaterdag'.split('_'), + weekdaysShort : 'zo._ma._di._wo._do._vr._za.'.split('_'), + weekdaysMin : 'zo_ma_di_wo_do_vr_za'.split('_'), + weekdaysParseExact : true, + longDateFormat : { + LT : 'HH:mm', + LTS : 'HH:mm:ss', + L : 'DD-MM-YYYY', + LL : 'D MMMM YYYY', + LLL : 'D MMMM YYYY HH:mm', + LLLL : 'dddd D MMMM YYYY HH:mm' + }, + calendar : { + sameDay: '[vandaag om] LT', + nextDay: '[morgen om] LT', + nextWeek: 'dddd [om] LT', + lastDay: '[gisteren om] LT', + lastWeek: '[afgelopen] dddd [om] LT', + sameElse: 'L' + }, + relativeTime : { + future : 'over %s', + past : '%s geleden', + s : 'een paar seconden', + ss : '%d seconden', + m : 'één minuut', + mm : '%d minuten', + h : 'één uur', + hh : '%d uur', + d : 'één dag', + dd : '%d dagen', + M : 'één maand', + MM : '%d maanden', + y : 'één jaar', + yy : '%d jaar' + }, + dayOfMonthOrdinalParse: /\d{1,2}(ste|de)/, + ordinal : function (number) { + return number + ((number === 1 || number === 8 || number >= 20) ? 'ste' : 'de'); + }, + week : { + dow : 1, // Monday is the first day of the week. + doy : 4 // The week that contains Jan 4th is the first week of the year. + } +}); \ No newline at end of file diff --git a/public/js/ff/moment/pl_PL.js b/public/js/ff/moment/pl_PL.js new file mode 100644 index 0000000000..e2b5ff40dd --- /dev/null +++ b/public/js/ff/moment/pl_PL.js @@ -0,0 +1,113 @@ +//! moment.js locale configuration + +var monthsNominative = 'styczeń_luty_marzec_kwiecień_maj_czerwiec_lipiec_sierpień_wrzesień_październik_listopad_grudzień'.split('_'), + monthsSubjective = 'stycznia_lutego_marca_kwietnia_maja_czerwca_lipca_sierpnia_września_października_listopada_grudnia'.split('_'); +function plural$3(n) { + return (n % 10 < 5) && (n % 10 > 1) && ((~~(n / 10) % 10) !== 1); +} +function translate$8(number, withoutSuffix, key) { + var result = number + ' '; + switch (key) { + case 'ss': + return result + (plural$3(number) ? 'sekundy' : 'sekund'); + case 'm': + return withoutSuffix ? 'minuta' : 'minutę'; + case 'mm': + return result + (plural$3(number) ? 'minuty' : 'minut'); + case 'h': + return withoutSuffix ? 'godzina' : 'godzinę'; + case 'hh': + return result + (plural$3(number) ? 'godziny' : 'godzin'); + case 'MM': + return result + (plural$3(number) ? 'miesiące' : 'miesięcy'); + case 'yy': + return result + (plural$3(number) ? 'lata' : 'lat'); + } +} + +moment.defineLocale('pl_PL', { + months : function (momentToFormat, format) { + if (!momentToFormat) { + return monthsNominative; + } else if (format === '') { + // Hack: if format empty we know this is used to generate + // RegExp by moment. Give then back both valid forms of months + // in RegExp ready format. + return '(' + monthsSubjective[momentToFormat.month()] + '|' + monthsNominative[momentToFormat.month()] + ')'; + } else if (/D MMMM/.test(format)) { + return monthsSubjective[momentToFormat.month()]; + } else { + return monthsNominative[momentToFormat.month()]; + } + }, + monthsShort : 'sty_lut_mar_kwi_maj_cze_lip_sie_wrz_paź_lis_gru'.split('_'), + weekdays : 'niedziela_poniedziałek_wtorek_środa_czwartek_piątek_sobota'.split('_'), + weekdaysShort : 'ndz_pon_wt_śr_czw_pt_sob'.split('_'), + weekdaysMin : 'Nd_Pn_Wt_Śr_Cz_Pt_So'.split('_'), + longDateFormat : { + LT : 'HH:mm', + LTS : 'HH:mm:ss', + L : 'DD.MM.YYYY', + LL : 'D MMMM YYYY', + LLL : 'D MMMM YYYY HH:mm', + LLLL : 'dddd, D MMMM YYYY HH:mm' + }, + calendar : { + sameDay: '[Dziś o] LT', + nextDay: '[Jutro o] LT', + nextWeek: function () { + switch (this.day()) { + case 0: + return '[W niedzielę o] LT'; + + case 2: + return '[We wtorek o] LT'; + + case 3: + return '[W środę o] LT'; + + case 6: + return '[W sobotę o] LT'; + + default: + return '[W] dddd [o] LT'; + } + }, + lastDay: '[Wczoraj o] LT', + lastWeek: function () { + switch (this.day()) { + case 0: + return '[W zeszłą niedzielę o] LT'; + case 3: + return '[W zeszłą środę o] LT'; + case 6: + return '[W zeszłą sobotę o] LT'; + default: + return '[W zeszły] dddd [o] LT'; + } + }, + sameElse: 'L' + }, + relativeTime : { + future : 'za %s', + past : '%s temu', + s : 'kilka sekund', + ss : translate$8, + m : translate$8, + mm : translate$8, + h : translate$8, + hh : translate$8, + d : '1 dzień', + dd : '%d dni', + M : 'miesiąc', + MM : translate$8, + y : 'rok', + yy : translate$8 + }, + dayOfMonthOrdinalParse: /\d{1,2}\./, + ordinal : '%d.', + week : { + dow : 1, // Monday is the first day of the week. + doy : 4 // The week that contains Jan 4th is the first week of the year. + } +}); \ No newline at end of file diff --git a/public/js/ff/moment/pt_BR.js b/public/js/ff/moment/pt_BR.js new file mode 100644 index 0000000000..2de9bcfe93 --- /dev/null +++ b/public/js/ff/moment/pt_BR.js @@ -0,0 +1,48 @@ +//! moment.js locale configuration + +moment.defineLocale('pt_BR', { + months : 'janeiro_fevereiro_março_abril_maio_junho_julho_agosto_setembro_outubro_novembro_dezembro'.split('_'), + monthsShort : 'jan_fev_mar_abr_mai_jun_jul_ago_set_out_nov_dez'.split('_'), + weekdays : 'Domingo_Segunda-feira_Terça-feira_Quarta-feira_Quinta-feira_Sexta-feira_Sábado'.split('_'), + weekdaysShort : 'Dom_Seg_Ter_Qua_Qui_Sex_Sáb'.split('_'), + weekdaysMin : 'Do_2ª_3ª_4ª_5ª_6ª_Sá'.split('_'), + weekdaysParseExact : true, + longDateFormat : { + LT : 'HH:mm', + LTS : 'HH:mm:ss', + L : 'DD/MM/YYYY', + LL : 'D [de] MMMM [de] YYYY', + LLL : 'D [de] MMMM [de] YYYY [às] HH:mm', + LLLL : 'dddd, D [de] MMMM [de] YYYY [às] HH:mm' + }, + calendar : { + sameDay: '[Hoje às] LT', + nextDay: '[Amanhã às] LT', + nextWeek: 'dddd [às] LT', + lastDay: '[Ontem às] LT', + lastWeek: function () { + return (this.day() === 0 || this.day() === 6) ? + '[Último] dddd [às] LT' : // Saturday + Sunday + '[Última] dddd [às] LT'; // Monday - Friday + }, + sameElse: 'L' + }, + relativeTime : { + future : 'em %s', + past : 'há %s', + s : 'poucos segundos', + ss : '%d segundos', + m : 'um minuto', + mm : '%d minutos', + h : 'uma hora', + hh : '%d horas', + d : 'um dia', + dd : '%d dias', + M : 'um mês', + MM : '%d meses', + y : 'um ano', + yy : '%d anos' + }, + dayOfMonthOrdinalParse: /\d{1,2}º/, + ordinal : '%dº' +}); \ No newline at end of file diff --git a/public/js/ff/moment/ru_RU.js b/public/js/ff/moment/ru_RU.js new file mode 100644 index 0000000000..36e37a6f88 --- /dev/null +++ b/public/js/ff/moment/ru_RU.js @@ -0,0 +1,169 @@ +//! moment.js locale configuration + +function plural$4(word, num) { + var forms = word.split('_'); + return num % 10 === 1 && num % 100 !== 11 ? forms[0] : (num % 10 >= 2 && num % 10 <= 4 && (num % 100 < 10 || num % 100 >= 20) ? forms[1] : forms[2]); +} +function relativeTimeWithPlural$3(number, withoutSuffix, key) { + var format = { + 'ss': withoutSuffix ? 'секунда_секунды_секунд' : 'секунду_секунды_секунд', + 'mm': withoutSuffix ? 'минута_минуты_минут' : 'минуту_минуты_минут', + 'hh': 'час_часа_часов', + 'dd': 'день_дня_дней', + 'MM': 'месяц_месяца_месяцев', + 'yy': 'год_года_лет' + }; + if (key === 'm') { + return withoutSuffix ? 'минута' : 'минуту'; + } + else { + return number + ' ' + plural$4(format[key], +number); + } +} +var monthsParse$4 = [/^янв/i, /^фев/i, /^мар/i, /^апр/i, /^ма[йя]/i, /^июн/i, /^июл/i, /^авг/i, /^сен/i, /^окт/i, /^ноя/i, /^дек/i]; + +// http://new.gramota.ru/spravka/rules/139-prop : § 103 +// Сокращения месяцев: http://new.gramota.ru/spravka/buro/search-answer?s=242637 +// CLDR data: http://www.unicode.org/cldr/charts/28/summary/ru.html#1753 +moment.defineLocale('ru_RU', { + months : { + format: 'января_февраля_марта_апреля_мая_июня_июля_августа_сентября_октября_ноября_декабря'.split('_'), + standalone: 'январь_февраль_март_апрель_май_июнь_июль_август_сентябрь_октябрь_ноябрь_декабрь'.split('_') + }, + monthsShort : { + // по CLDR именно "июл." и "июн.", но какой смысл менять букву на точку ? + format: 'янв._февр._мар._апр._мая_июня_июля_авг._сент._окт._нояб._дек.'.split('_'), + standalone: 'янв._февр._март_апр._май_июнь_июль_авг._сент._окт._нояб._дек.'.split('_') + }, + weekdays : { + standalone: 'воскресенье_понедельник_вторник_среда_четверг_пятница_суббота'.split('_'), + format: 'воскресенье_понедельник_вторник_среду_четверг_пятницу_субботу'.split('_'), + isFormat: /\[ ?[Вв] ?(?:прошлую|следующую|эту)? ?\] ?dddd/ + }, + weekdaysShort : 'вс_пн_вт_ср_чт_пт_сб'.split('_'), + weekdaysMin : 'вс_пн_вт_ср_чт_пт_сб'.split('_'), + monthsParse : monthsParse$4, + longMonthsParse : monthsParse$4, + shortMonthsParse : monthsParse$4, + + // полные названия с падежами, по три буквы, для некоторых, по 4 буквы, сокращения с точкой и без точки + monthsRegex: /^(январ[ья]|янв\.?|феврал[ья]|февр?\.?|марта?|мар\.?|апрел[ья]|апр\.?|ма[йя]|июн[ья]|июн\.?|июл[ья]|июл\.?|августа?|авг\.?|сентябр[ья]|сент?\.?|октябр[ья]|окт\.?|ноябр[ья]|нояб?\.?|декабр[ья]|дек\.?)/i, + + // копия предыдущего + monthsShortRegex: /^(январ[ья]|янв\.?|феврал[ья]|февр?\.?|марта?|мар\.?|апрел[ья]|апр\.?|ма[йя]|июн[ья]|июн\.?|июл[ья]|июл\.?|августа?|авг\.?|сентябр[ья]|сент?\.?|октябр[ья]|окт\.?|ноябр[ья]|нояб?\.?|декабр[ья]|дек\.?)/i, + + // полные названия с падежами + monthsStrictRegex: /^(январ[яь]|феврал[яь]|марта?|апрел[яь]|ма[яй]|июн[яь]|июл[яь]|августа?|сентябр[яь]|октябр[яь]|ноябр[яь]|декабр[яь])/i, + + // Выражение, которое соотвествует только сокращённым формам + monthsShortStrictRegex: /^(янв\.|февр?\.|мар[т.]|апр\.|ма[яй]|июн[ья.]|июл[ья.]|авг\.|сент?\.|окт\.|нояб?\.|дек\.)/i, + longDateFormat : { + LT : 'H:mm', + LTS : 'H:mm:ss', + L : 'DD.MM.YYYY', + LL : 'D MMMM YYYY г.', + LLL : 'D MMMM YYYY г., H:mm', + LLLL : 'dddd, D MMMM YYYY г., H:mm' + }, + calendar : { + sameDay: '[Сегодня в] LT', + nextDay: '[Завтра в] LT', + lastDay: '[Вчера в] LT', + nextWeek: function (now) { + if (now.week() !== this.week()) { + switch (this.day()) { + case 0: + return '[В следующее] dddd [в] LT'; + case 1: + case 2: + case 4: + return '[В следующий] dddd [в] LT'; + case 3: + case 5: + case 6: + return '[В следующую] dddd [в] LT'; + } + } else { + if (this.day() === 2) { + return '[Во] dddd [в] LT'; + } else { + return '[В] dddd [в] LT'; + } + } + }, + lastWeek: function (now) { + if (now.week() !== this.week()) { + switch (this.day()) { + case 0: + return '[В прошлое] dddd [в] LT'; + case 1: + case 2: + case 4: + return '[В прошлый] dddd [в] LT'; + case 3: + case 5: + case 6: + return '[В прошлую] dddd [в] LT'; + } + } else { + if (this.day() === 2) { + return '[Во] dddd [в] LT'; + } else { + return '[В] dddd [в] LT'; + } + } + }, + sameElse: 'L' + }, + relativeTime : { + future : 'через %s', + past : '%s назад', + s : 'несколько секунд', + ss : relativeTimeWithPlural$3, + m : relativeTimeWithPlural$3, + mm : relativeTimeWithPlural$3, + h : 'час', + hh : relativeTimeWithPlural$3, + d : 'день', + dd : relativeTimeWithPlural$3, + M : 'месяц', + MM : relativeTimeWithPlural$3, + y : 'год', + yy : relativeTimeWithPlural$3 + }, + meridiemParse: /ночи|утра|дня|вечера/i, + isPM : function (input) { + return /^(дня|вечера)$/.test(input); + }, + meridiem : function (hour, minute, isLower) { + if (hour < 4) { + return 'ночи'; + } else if (hour < 12) { + return 'утра'; + } else if (hour < 17) { + return 'дня'; + } else { + return 'вечера'; + } + }, + dayOfMonthOrdinalParse: /\d{1,2}-(й|го|я)/, + ordinal: function (number, period) { + switch (period) { + case 'M': + case 'd': + case 'DDD': + return number + '-й'; + case 'D': + return number + '-го'; + case 'w': + case 'W': + return number + '-я'; + default: + return number; + } + }, + week : { + dow : 1, // Monday is the first day of the week. + doy : 4 // The week that contains Jan 4th is the first week of the year. + } +}); \ No newline at end of file diff --git a/public/js/ff/moment/tr_TR.js b/public/js/ff/moment/tr_TR.js new file mode 100644 index 0000000000..9e889dc917 --- /dev/null +++ b/public/js/ff/moment/tr_TR.js @@ -0,0 +1,192 @@ + +//! moment.js locale configuration + +var numbersNouns = 'pagh_wa’_cha’_wej_loS_vagh_jav_Soch_chorgh_Hut'.split('_'); + +function translateFuture(output) { + var time = output; + time = (output.indexOf('jaj') !== -1) ? + time.slice(0, -3) + 'leS' : + (output.indexOf('jar') !== -1) ? + time.slice(0, -3) + 'waQ' : + (output.indexOf('DIS') !== -1) ? + time.slice(0, -3) + 'nem' : + time + ' pIq'; + return time; +} + +function translatePast(output) { + var time = output; + time = (output.indexOf('jaj') !== -1) ? + time.slice(0, -3) + 'Hu’' : + (output.indexOf('jar') !== -1) ? + time.slice(0, -3) + 'wen' : + (output.indexOf('DIS') !== -1) ? + time.slice(0, -3) + 'ben' : + time + ' ret'; + return time; +} + +function translate$10(number, withoutSuffix, string, isFuture) { + var numberNoun = numberAsNoun(number); + switch (string) { + case 'ss': + return numberNoun + ' lup'; + case 'mm': + return numberNoun + ' tup'; + case 'hh': + return numberNoun + ' rep'; + case 'dd': + return numberNoun + ' jaj'; + case 'MM': + return numberNoun + ' jar'; + case 'yy': + return numberNoun + ' DIS'; + } +} + +function numberAsNoun(number) { + var hundred = Math.floor((number % 1000) / 100), + ten = Math.floor((number % 100) / 10), + one = number % 10, + word = ''; + if (hundred > 0) { + word += numbersNouns[hundred] + 'vatlh'; + } + if (ten > 0) { + word += ((word !== '') ? ' ' : '') + numbersNouns[ten] + 'maH'; + } + if (one > 0) { + word += ((word !== '') ? ' ' : '') + numbersNouns[one]; + } + return (word === '') ? 'pagh' : word; +} + +moment.defineLocale('tlh', { + months : 'tera’ jar wa’_tera’ jar cha’_tera’ jar wej_tera’ jar loS_tera’ jar vagh_tera’ jar jav_tera’ jar Soch_tera’ jar chorgh_tera’ jar Hut_tera’ jar wa’maH_tera’ jar wa’maH wa’_tera’ jar wa’maH cha’'.split('_'), + monthsShort : 'jar wa’_jar cha’_jar wej_jar loS_jar vagh_jar jav_jar Soch_jar chorgh_jar Hut_jar wa’maH_jar wa’maH wa’_jar wa’maH cha’'.split('_'), + monthsParseExact : true, + weekdays : 'lojmItjaj_DaSjaj_povjaj_ghItlhjaj_loghjaj_buqjaj_ghInjaj'.split('_'), + weekdaysShort : 'lojmItjaj_DaSjaj_povjaj_ghItlhjaj_loghjaj_buqjaj_ghInjaj'.split('_'), + weekdaysMin : 'lojmItjaj_DaSjaj_povjaj_ghItlhjaj_loghjaj_buqjaj_ghInjaj'.split('_'), + longDateFormat : { + LT : 'HH:mm', + LTS : 'HH:mm:ss', + L : 'DD.MM.YYYY', + LL : 'D MMMM YYYY', + LLL : 'D MMMM YYYY HH:mm', + LLLL : 'dddd, D MMMM YYYY HH:mm' + }, + calendar : { + sameDay: '[DaHjaj] LT', + nextDay: '[wa’leS] LT', + nextWeek: 'LLL', + lastDay: '[wa’Hu’] LT', + lastWeek: 'LLL', + sameElse: 'L' + }, + relativeTime : { + future : translateFuture, + past : translatePast, + s : 'puS lup', + ss : translate$10, + m : 'wa’ tup', + mm : translate$10, + h : 'wa’ rep', + hh : translate$10, + d : 'wa’ jaj', + dd : translate$10, + M : 'wa’ jar', + MM : translate$10, + y : 'wa’ DIS', + yy : translate$10 + }, + dayOfMonthOrdinalParse: /\d{1,2}\./, + ordinal : '%d.', + week : { + dow : 1, // Monday is the first day of the week. + doy : 4 // The week that contains Jan 4th is the first week of the year. + } +}); + +var suffixes$4 = { + 1: '\'inci', + 5: '\'inci', + 8: '\'inci', + 70: '\'inci', + 80: '\'inci', + 2: '\'nci', + 7: '\'nci', + 20: '\'nci', + 50: '\'nci', + 3: '\'üncü', + 4: '\'üncü', + 100: '\'üncü', + 6: '\'ncı', + 9: '\'uncu', + 10: '\'uncu', + 30: '\'uncu', + 60: '\'ıncı', + 90: '\'ıncı' +}; + +hooks.defineLocale('tr_TR', { + months : 'Ocak_Şubat_Mart_Nisan_Mayıs_Haziran_Temmuz_Ağustos_Eylül_Ekim_Kasım_Aralık'.split('_'), + monthsShort : 'Oca_Şub_Mar_Nis_May_Haz_Tem_Ağu_Eyl_Eki_Kas_Ara'.split('_'), + weekdays : 'Pazar_Pazartesi_Salı_Çarşamba_Perşembe_Cuma_Cumartesi'.split('_'), + weekdaysShort : 'Paz_Pts_Sal_Çar_Per_Cum_Cts'.split('_'), + weekdaysMin : 'Pz_Pt_Sa_Ça_Pe_Cu_Ct'.split('_'), + longDateFormat : { + LT : 'HH:mm', + LTS : 'HH:mm:ss', + L : 'DD.MM.YYYY', + LL : 'D MMMM YYYY', + LLL : 'D MMMM YYYY HH:mm', + LLLL : 'dddd, D MMMM YYYY HH:mm' + }, + calendar : { + sameDay : '[bugün saat] LT', + nextDay : '[yarın saat] LT', + nextWeek : '[gelecek] dddd [saat] LT', + lastDay : '[dün] LT', + lastWeek : '[geçen] dddd [saat] LT', + sameElse : 'L' + }, + relativeTime : { + future : '%s sonra', + past : '%s önce', + s : 'birkaç saniye', + ss : '%d saniye', + m : 'bir dakika', + mm : '%d dakika', + h : 'bir saat', + hh : '%d saat', + d : 'bir gün', + dd : '%d gün', + M : 'bir ay', + MM : '%d ay', + y : 'bir yıl', + yy : '%d yıl' + }, + ordinal: function (number, period) { + switch (period) { + case 'd': + case 'D': + case 'Do': + case 'DD': + return number; + default: + if (number === 0) { // special case for zero + return number + '\'ıncı'; + } + var a = number % 10, + b = number % 100 - a, + c = number >= 100 ? 100 : null; + return number + (suffixes$4[a] || suffixes$4[b] || suffixes$4[c]); + } + }, + week : { + dow : 1, // Monday is the first day of the week. + doy : 7 // The week that contains Jan 1st is the first week of the year. + } +}); diff --git a/resources/views/layout/default.twig b/resources/views/layout/default.twig index 978b52d7d5..177491f146 100644 --- a/resources/views/layout/default.twig +++ b/resources/views/layout/default.twig @@ -157,6 +157,7 @@ + From ae273f83200da0531bbf10be5f88b4abd9b08de3 Mon Sep 17 00:00:00 2001 From: James Cole Date: Sun, 15 Apr 2018 10:44:47 +0200 Subject: [PATCH 037/117] Also test PHP 7.2 --- .travis.yml | 1 + public/js/ff/moment/tr_TR.js | 2 +- .../Controllers/Auth/TwoFactorControllerTest.php | 15 +++++++++++++++ .../Feature/Controllers/NewUserControllerTest.php | 5 +++-- .../Controllers/PreferencesControllerTest.php | 2 +- 5 files changed, 21 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index 100fc61eeb..4543dc5049 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,7 @@ language: php php: - 7.1 + - 7.2 cache: directories: diff --git a/public/js/ff/moment/tr_TR.js b/public/js/ff/moment/tr_TR.js index 9e889dc917..c28097304d 100644 --- a/public/js/ff/moment/tr_TR.js +++ b/public/js/ff/moment/tr_TR.js @@ -130,7 +130,7 @@ var suffixes$4 = { 90: '\'ıncı' }; -hooks.defineLocale('tr_TR', { +moment.defineLocale('tr_TR', { months : 'Ocak_Şubat_Mart_Nisan_Mayıs_Haziran_Temmuz_Ağustos_Eylül_Ekim_Kasım_Aralık'.split('_'), monthsShort : 'Oca_Şub_Mar_Nis_May_Haz_Tem_Ağu_Eyl_Eki_Kas_Ara'.split('_'), weekdays : 'Pazar_Pazartesi_Salı_Çarşamba_Perşembe_Cuma_Cumartesi'.split('_'), diff --git a/tests/Feature/Controllers/Auth/TwoFactorControllerTest.php b/tests/Feature/Controllers/Auth/TwoFactorControllerTest.php index dd347ecdca..fe774da3cc 100644 --- a/tests/Feature/Controllers/Auth/TwoFactorControllerTest.php +++ b/tests/Feature/Controllers/Auth/TwoFactorControllerTest.php @@ -57,10 +57,13 @@ class TwoFactorControllerTest extends TestCase $truePref->data = true; $secretPreference = new Preference; $secretPreference->data = 'JZMES376Z6YXY4QZ'; + $langPreference = new Preference; + $langPreference->data = 'en_US'; Preferences::shouldReceive('get')->withArgs(['twoFactorAuthEnabled', false])->andReturn($truePref)->twice(); Preferences::shouldReceive('get')->withArgs(['twoFactorAuthSecret', null])->andReturn($secretPreference)->once(); Preferences::shouldReceive('get')->withArgs(['twoFactorAuthSecret'])->andReturn($secretPreference)->once(); + Preferences::shouldReceive('get')->withArgs(['language', 'en_US'])->andReturn($langPreference); $response = $this->get(route('two-factor.index')); $response->assertStatus(200); @@ -75,9 +78,13 @@ class TwoFactorControllerTest extends TestCase $falsePreference = new Preference; $falsePreference->data = false; + $langPreference = new Preference; + $langPreference->data = 'en_US'; + Preferences::shouldReceive('get')->withArgs(['twoFactorAuthEnabled', false])->andReturn($falsePreference)->twice(); Preferences::shouldReceive('get')->withArgs(['twoFactorAuthSecret', null])->andReturn(null)->once(); Preferences::shouldReceive('get')->withArgs(['twoFactorAuthSecret'])->andReturn(null)->once(); + Preferences::shouldReceive('get')->withArgs(['language', 'en_US'])->andReturn($langPreference); $response = $this->get(route('two-factor.index')); $response->assertStatus(302); @@ -96,9 +103,13 @@ class TwoFactorControllerTest extends TestCase $truePref->data = true; $secretPreference = new Preference; $secretPreference->data = ''; + $langPreference = new Preference; + $langPreference->data = 'en_US'; + Preferences::shouldReceive('get')->withArgs(['twoFactorAuthEnabled', false])->andReturn($truePref)->twice(); Preferences::shouldReceive('get')->withArgs(['twoFactorAuthSecret', null])->andReturn($secretPreference)->once(); Preferences::shouldReceive('get')->withArgs(['twoFactorAuthSecret'])->andReturn($secretPreference)->once(); + Preferences::shouldReceive('get')->withArgs(['language', 'en_US'])->andReturn($langPreference); $response = $this->get(route('two-factor.index')); $response->assertStatus(500); @@ -115,9 +126,13 @@ class TwoFactorControllerTest extends TestCase $truePreference->data = true; $secretPreference = new Preference; $secretPreference->data = 'JZMES376Z6YXY4QZ'; + $langPreference = new Preference; + $langPreference->data = 'en_US'; + Preferences::shouldReceive('get')->withArgs(['twoFactorAuthEnabled', false])->andReturn($truePreference); Preferences::shouldReceive('get')->withArgs(['twoFactorAuthSecret', null])->andReturn($secretPreference); Preferences::shouldReceive('get')->withArgs(['twoFactorAuthSecret'])->andReturn($secretPreference); + Preferences::shouldReceive('get')->withArgs(['language', 'en_US'])->andReturn($langPreference); $response = $this->get(route('two-factor.lost')); $response->assertStatus(200); diff --git a/tests/Feature/Controllers/NewUserControllerTest.php b/tests/Feature/Controllers/NewUserControllerTest.php index 1752a5ad52..1a107b62b3 100644 --- a/tests/Feature/Controllers/NewUserControllerTest.php +++ b/tests/Feature/Controllers/NewUserControllerTest.php @@ -97,13 +97,14 @@ class NewUserControllerTest extends TestCase $accountRepos = $this->mock(AccountRepositoryInterface::class); $journalRepos = $this->mock(JournalRepositoryInterface::class); $journalRepos->shouldReceive('first')->once()->andReturn(new TransactionJournal); - $accountRepos->shouldReceive('store')->times(2); + $accountRepos->shouldReceive('store')->times(3); $currencyRepos->shouldReceive('findNull')->andReturn(TransactionCurrency::find(1)); $data = [ 'bank_name' => 'New bank', 'savings_balance' => '1000', 'bank_balance' => '100', + 'language' => 'en_US', 'amount_currency_id_bank_balance' => 1, ]; $this->be($this->emptyUser()); @@ -122,7 +123,7 @@ class NewUserControllerTest extends TestCase $accountRepos = $this->mock(AccountRepositoryInterface::class); $journalRepos = $this->mock(JournalRepositoryInterface::class); $journalRepos->shouldReceive('first')->once()->andReturn(new TransactionJournal); - $accountRepos->shouldReceive('store')->twice(); + $accountRepos->shouldReceive('store')->times(3); $currencyRepos->shouldReceive('findNull')->andReturn(TransactionCurrency::find(1)); $data = [ diff --git a/tests/Feature/Controllers/PreferencesControllerTest.php b/tests/Feature/Controllers/PreferencesControllerTest.php index 341d69d1f5..224130c430 100644 --- a/tests/Feature/Controllers/PreferencesControllerTest.php +++ b/tests/Feature/Controllers/PreferencesControllerTest.php @@ -30,7 +30,7 @@ use FireflyIII\Repositories\User\UserRepositoryInterface; use Illuminate\Support\Collection; use Log; use Tests\TestCase; - +use Preferences; /** * Class PreferencesControllerTest * From a85ebb49b2a7260639a3570c251b5807ec96a584 Mon Sep 17 00:00:00 2001 From: James Cole Date: Sun, 15 Apr 2018 14:03:23 +0200 Subject: [PATCH 038/117] Improve test coverage. --- .../Json/AutoCompleteControllerTest.php | 76 +++++++++++++++++++ .../Controllers/JsonControllerTest.php | 75 ------------------ 2 files changed, 76 insertions(+), 75 deletions(-) diff --git a/tests/Feature/Controllers/Json/AutoCompleteControllerTest.php b/tests/Feature/Controllers/Json/AutoCompleteControllerTest.php index 9bca378ba4..89f54f9d6c 100644 --- a/tests/Feature/Controllers/Json/AutoCompleteControllerTest.php +++ b/tests/Feature/Controllers/Json/AutoCompleteControllerTest.php @@ -25,9 +25,15 @@ namespace Tests\Feature\Controllers\Json; use FireflyIII\Helpers\Collector\JournalCollectorInterface; use FireflyIII\Models\Account; use FireflyIII\Models\AccountType; +use FireflyIII\Models\Budget; +use FireflyIII\Models\Category; +use FireflyIII\Models\Tag; use FireflyIII\Models\TransactionJournal; use FireflyIII\Repositories\Account\AccountRepositoryInterface; +use FireflyIII\Repositories\Budget\BudgetRepositoryInterface; +use FireflyIII\Repositories\Category\CategoryRepositoryInterface; use FireflyIII\Repositories\Journal\JournalRepositoryInterface; +use FireflyIII\Repositories\Tag\TagRepositoryInterface; use Illuminate\Support\Collection; use Log; use Tests\TestCase; @@ -37,6 +43,8 @@ use Tests\TestCase; */ class AutoCompleteControllerTest extends TestCase { + + /** * */ @@ -81,6 +89,40 @@ class AutoCompleteControllerTest extends TestCase $response->assertStatus(200); } + /** + * @covers \FireflyIII\Http\Controllers\Json\AutoCompleteController::budgets + */ + public function testBudgets() + { + // mock stuff + $budget = factory(Budget::class)->make(); + $categoryRepos = $this->mock(BudgetRepositoryInterface::class); + $journalRepos = $this->mock(JournalRepositoryInterface::class); + $journalRepos->shouldReceive('first')->once()->andReturn(new TransactionJournal); + $categoryRepos->shouldReceive('getBudgets')->andReturn(new Collection([$budget])); + $this->be($this->user()); + $response = $this->get(route('json.budgets')); + $response->assertStatus(200); + $response->assertExactJson([$budget->name]); + } + + /** + * @covers \FireflyIII\Http\Controllers\Json\AutoCompleteController::categories + */ + public function testCategories() + { + // mock stuff + $category = factory(Category::class)->make(); + $categoryRepos = $this->mock(CategoryRepositoryInterface::class); + $journalRepos = $this->mock(JournalRepositoryInterface::class); + $journalRepos->shouldReceive('first')->once()->andReturn(new TransactionJournal); + $categoryRepos->shouldReceive('getCategories')->andReturn(new Collection([$category])); + $this->be($this->user()); + $response = $this->get(route('json.categories')); + $response->assertStatus(200); + $response->assertExactJson([$category->name]); + } + /** * @covers \FireflyIII\Http\Controllers\Json\AutoCompleteController::expenseAccounts */ @@ -144,6 +186,24 @@ class AutoCompleteControllerTest extends TestCase $response->assertExactJson([$accountA->name]); } + /** + * @covers \FireflyIII\Http\Controllers\Json\AutoCompleteController::tags + */ + public function testTags() + { + // mock stuff + $tag = factory(Tag::class)->make(); + $tagRepos = $this->mock(TagRepositoryInterface::class); + $journalRepos = $this->mock(JournalRepositoryInterface::class); + $journalRepos->shouldReceive('first')->once()->andReturn(new TransactionJournal); + $tagRepos->shouldReceive('get')->andReturn(new Collection([$tag]))->once(); + + $this->be($this->user()); + $response = $this->get(route('json.tags')); + $response->assertStatus(200); + $response->assertExactJson([$tag->tag]); + } + /** * @covers \FireflyIII\Http\Controllers\Json\AutoCompleteController::transactionJournals */ @@ -163,4 +223,20 @@ class AutoCompleteControllerTest extends TestCase $response->assertStatus(200); $response->assertExactJson([]); } + + /** + * @covers \FireflyIII\Http\Controllers\Json\AutoCompleteController::transactionTypes + */ + public function testTransactionTypes(): void + { + // mock stuff + $journalRepos = $this->mock(JournalRepositoryInterface::class); + $journalRepos->shouldReceive('first')->once()->andReturn(new TransactionJournal); + $journalRepos->shouldReceive('getTransactionTypes')->once()->andReturn(new Collection); + + $this->be($this->user()); + $response = $this->get(route('json.transaction-types', ['deposit'])); + $response->assertStatus(200); + $response->assertExactJson([]); + } } diff --git a/tests/Feature/Controllers/JsonControllerTest.php b/tests/Feature/Controllers/JsonControllerTest.php index 37b01eb501..7f11abfb47 100644 --- a/tests/Feature/Controllers/JsonControllerTest.php +++ b/tests/Feature/Controllers/JsonControllerTest.php @@ -22,15 +22,8 @@ declare(strict_types=1); namespace Tests\Feature\Controllers; -use FireflyIII\Models\Budget; -use FireflyIII\Models\Category; -use FireflyIII\Models\Tag; use FireflyIII\Models\TransactionJournal; -use FireflyIII\Repositories\Budget\BudgetRepositoryInterface; -use FireflyIII\Repositories\Category\CategoryRepositoryInterface; use FireflyIII\Repositories\Journal\JournalRepositoryInterface; -use FireflyIII\Repositories\Tag\TagRepositoryInterface; -use Illuminate\Support\Collection; use Log; use Tests\TestCase; @@ -67,74 +60,6 @@ class JsonControllerTest extends TestCase $response->assertStatus(200); } - /** - * @covers \FireflyIII\Http\Controllers\JsonController::budgets - */ - public function testBudgets() - { - // mock stuff - $budget = factory(Budget::class)->make(); - $categoryRepos = $this->mock(BudgetRepositoryInterface::class); - $journalRepos = $this->mock(JournalRepositoryInterface::class); - $journalRepos->shouldReceive('first')->once()->andReturn(new TransactionJournal); - $categoryRepos->shouldReceive('getBudgets')->andReturn(new Collection([$budget])); - $this->be($this->user()); - $response = $this->get(route('json.budgets')); - $response->assertStatus(200); - $response->assertExactJson([$budget->name]); - } - - /** - * @covers \FireflyIII\Http\Controllers\JsonController::categories - */ - public function testCategories() - { - // mock stuff - $category = factory(Category::class)->make(); - $categoryRepos = $this->mock(CategoryRepositoryInterface::class); - $journalRepos = $this->mock(JournalRepositoryInterface::class); - $journalRepos->shouldReceive('first')->once()->andReturn(new TransactionJournal); - $categoryRepos->shouldReceive('getCategories')->andReturn(new Collection([$category])); - $this->be($this->user()); - $response = $this->get(route('json.categories')); - $response->assertStatus(200); - $response->assertExactJson([$category->name]); - } - - /** - * @covers \FireflyIII\Http\Controllers\JsonController::tags - */ - public function testTags() - { - // mock stuff - $tag = factory(Tag::class)->make(); - $tagRepos = $this->mock(TagRepositoryInterface::class); - $journalRepos = $this->mock(JournalRepositoryInterface::class); - $journalRepos->shouldReceive('first')->once()->andReturn(new TransactionJournal); - $tagRepos->shouldReceive('get')->andReturn(new Collection([$tag]))->once(); - - $this->be($this->user()); - $response = $this->get(route('json.tags')); - $response->assertStatus(200); - $response->assertExactJson([$tag->tag]); - } - - /** - * @covers \FireflyIII\Http\Controllers\JsonController::transactionTypes - */ - public function testTransactionTypes() - { - // mock stuff - $journalRepos = $this->mock(JournalRepositoryInterface::class); - $journalRepos->shouldReceive('first')->once()->andReturn(new TransactionJournal); - $journalRepos->shouldReceive('getTransactionTypes')->once()->andReturn(new Collection); - - $this->be($this->user()); - $response = $this->get(route('json.transaction-types', ['deposit'])); - $response->assertStatus(200); - $response->assertExactJson([]); - } - /** * @covers \FireflyIII\Http\Controllers\JsonController::trigger */ From 91494584c20f3e0670608164fba992facee8d890 Mon Sep 17 00:00:00 2001 From: James Cole Date: Sun, 15 Apr 2018 17:58:39 +0200 Subject: [PATCH 039/117] Fix #1327 --- resources/views/piggy-banks/show.twig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/resources/views/piggy-banks/show.twig b/resources/views/piggy-banks/show.twig index e6c9666f7c..5aa3e4e5a1 100644 --- a/resources/views/piggy-banks/show.twig +++ b/resources/views/piggy-banks/show.twig @@ -54,7 +54,7 @@ {{ 'start_date'|_ }} {% if piggyBank.startdate %} - {{ piggyBank.startdate.format('jS F Y') }} + {{ piggyBank.startdate.formatLocalized(monthAndDayFormat) }} {% else %} {{ 'no_start_date'|_ }} {% endif %} @@ -64,7 +64,7 @@ {{ 'target_date'|_ }} {% if piggyBank.targetdate %} - {{ piggyBank.targetdate.format('jS F Y') }} + {{ piggyBank.targetdate.formatLocalized(monthAndDayFormat) }} {% else %} {{ 'no_target_date'|_ }} {% endif %} From ce1614f4e7de18cd1ded0027edb3db09528ba2d9 Mon Sep 17 00:00:00 2001 From: James Cole Date: Sun, 15 Apr 2018 19:11:10 +0200 Subject: [PATCH 040/117] Fix chart range. --- app/Http/Controllers/Chart/AccountController.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/Http/Controllers/Chart/AccountController.php b/app/Http/Controllers/Chart/AccountController.php index 2ecbddb591..b365bc23a5 100644 --- a/app/Http/Controllers/Chart/AccountController.php +++ b/app/Http/Controllers/Chart/AccountController.php @@ -349,7 +349,7 @@ class AccountController extends Controller $balance = (float)app('steam')->balance($account, $current); $label = app('navigation')->periodShow($current, $step); $chartData[$label] = $balance; - $current = app('navigation')->addPeriod($current, $step, 1); + $current = app('navigation')->addPeriod($current, $step, 0); } break; // @codeCoverageIgnoreEnd From f4f3c8798e77e952bdf450df873d5322a014e0e5 Mon Sep 17 00:00:00 2001 From: James Cole Date: Sun, 15 Apr 2018 19:20:04 +0200 Subject: [PATCH 041/117] Fix for #1328 --- .../Controllers/Chart/PiggyBankController.php | 46 +++++++++++++++---- 1 file changed, 38 insertions(+), 8 deletions(-) diff --git a/app/Http/Controllers/Chart/PiggyBankController.php b/app/Http/Controllers/Chart/PiggyBankController.php index 37beb074ce..791c5f3b9d 100644 --- a/app/Http/Controllers/Chart/PiggyBankController.php +++ b/app/Http/Controllers/Chart/PiggyBankController.php @@ -22,12 +22,14 @@ declare(strict_types=1); namespace FireflyIII\Http\Controllers\Chart; +use Carbon\Carbon; use FireflyIII\Generator\Chart\Basic\GeneratorInterface; use FireflyIII\Http\Controllers\Controller; use FireflyIII\Models\PiggyBank; use FireflyIII\Models\PiggyBankEvent; use FireflyIII\Repositories\PiggyBank\PiggyBankRepositoryInterface; use FireflyIII\Support\CacheProperties; +use Illuminate\Support\Collection; /** * Class PiggyBankController. @@ -64,16 +66,44 @@ class PiggyBankController extends Controller if ($cache->has()) { return response()->json($cache->get()); // @codeCoverageIgnore } + $set = $repository->getEvents($piggyBank); + $set = $set->reverse(); + + // get first event or start date of piggy bank or today + $startDate = $piggyBank->start_date ?? new Carbon; + + /** @var PiggyBankEvent $first */ + $firstEvent = $set->first(); + $firstDate = null === $firstEvent ? new Carbon : $firstEvent->date; + + // which ever is older: + $oldest = $startDate->lt($firstDate) ? $startDate : $firstDate; + $today = new Carbon; + // depending on diff, do something with range of chart. + $step = '1D'; + $months = $oldest->diffInMonths($today); + if ($months > 3) { + $step = '1W'; // @codeCoverageIgnore + } + if ($months > 24) { + $step = '1M'; // @codeCoverageIgnore + } + if ($months > 100) { + $step = '1Y'; // @codeCoverageIgnore + } - $set = $repository->getEvents($piggyBank); - $set = $set->reverse(); $chartData = []; - $sum = '0'; - /** @var PiggyBankEvent $entry */ - foreach ($set as $entry) { - $label = $entry->date->formatLocalized((string)trans('config.month_and_day')); - $sum = bcadd($sum, $entry->amount); - $chartData[$label] = $sum; + while ($oldest <= $today) { + /** @var Collection $filtered */ + $filtered = $set->filter( + function (PiggyBankEvent $event) use ($oldest) { + return $event->date->lte($oldest); + } + ); + $currentSum = $filtered->sum('amount'); + $label = $oldest->formatLocalized((string)trans('config.month_and_day')); + $chartData[$label] = $currentSum; + $oldest = app('navigation')->addPeriod($oldest, $step, 0); } $data = $this->generator->singleSet($piggyBank->name, $chartData); From 6f974fe2850c9ea635b572965972490efbf9b0c3 Mon Sep 17 00:00:00 2001 From: James Cole Date: Sun, 15 Apr 2018 19:20:24 +0200 Subject: [PATCH 042/117] Improve API and test coverage. --- app/Api/V1/Controllers/BillController.php | 41 +-- app/Api/V1/Controllers/CurrencyController.php | 68 ++--- app/Api/V1/Requests/BillRequest.php | 46 ++- app/Api/V1/Requests/CurrencyRequest.php | 3 - .../Api/V1/Controllers/BillControllerTest.php | 3 +- .../V1/Controllers/CurrencyControllerTest.php | 267 ++++++++++++++++++ 6 files changed, 342 insertions(+), 86 deletions(-) create mode 100644 tests/Api/V1/Controllers/CurrencyControllerTest.php diff --git a/app/Api/V1/Controllers/BillController.php b/app/Api/V1/Controllers/BillController.php index a6aeeda7b9..bbf38c444d 100644 --- a/app/Api/V1/Controllers/BillController.php +++ b/app/Api/V1/Controllers/BillController.php @@ -27,6 +27,7 @@ use FireflyIII\Exceptions\FireflyException; use FireflyIII\Models\Bill; use FireflyIII\Repositories\Bill\BillRepositoryInterface; use FireflyIII\Transformers\BillTransformer; +use Illuminate\Http\JsonResponse; use Illuminate\Http\Request; use Illuminate\Support\Collection; use League\Fractal\Manager; @@ -47,7 +48,7 @@ class BillController extends Controller /** * BillController constructor. * - * @throws \FireflyIII\Exceptions\FireflyException + * @throws FireflyException */ public function __construct() { @@ -66,11 +67,11 @@ class BillController extends Controller /** * Remove the specified resource from storage. * - * @param \FireflyIII\Models\Bill $bill + * @param Bill $bill * - * @return \Illuminate\Http\Response + * @return JsonResponse */ - public function delete(Bill $bill) + public function delete(Bill $bill): JsonResponse { $this->repository->destroy($bill); @@ -82,9 +83,9 @@ class BillController extends Controller * * @param Request $request * - * @return \Illuminate\Http\JsonResponse + * @return JsonResponse */ - public function index(Request $request) + public function index(Request $request): JsonResponse { $pageSize = (int)Preferences::getForUser(auth()->user(), 'listPageSize', 50)->data; $paginator = $this->repository->getPaginator($pageSize); @@ -106,9 +107,9 @@ class BillController extends Controller * @param Request $request * @param Bill $bill * - * @return \Illuminate\Http\JsonResponse + * @return JsonResponse */ - public function show(Request $request, Bill $bill) + public function show(Request $request, Bill $bill): JsonResponse { $manager = new Manager(); // add include parameter: @@ -126,22 +127,22 @@ class BillController extends Controller /** * @param BillRequest $request * - * @return \Illuminate\Http\JsonResponse + * @return JsonResponse * @throws FireflyException */ - public function store(BillRequest $request) + public function store(BillRequest $request): JsonResponse { - $bill = $this->repository->store($request->getAll()); - if(null !== $bill) { - $manager = new Manager(); - $baseUrl = $request->getSchemeAndHttpHost() . '/api/v1'; - $manager->setSerializer(new JsonApiSerializer($baseUrl)); + $bill = $this->repository->store($request->getAll()); + if (null !== $bill) { + $manager = new Manager(); + $baseUrl = $request->getSchemeAndHttpHost() . '/api/v1'; + $manager->setSerializer(new JsonApiSerializer($baseUrl)); - $resource = new Item($bill, new BillTransformer($this->parameters), 'bills'); + $resource = new Item($bill, new BillTransformer($this->parameters), 'bills'); - return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json'); + return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json'); } - throw new FireflyException('Could not store new bill.'); + throw new FireflyException('Could not store new bill.'); // @codeCoverageIgnore } @@ -150,9 +151,9 @@ class BillController extends Controller * @param BillRequest $request * @param Bill $bill * - * @return \Illuminate\Http\JsonResponse + * @return JsonResponse */ - public function update(BillRequest $request, Bill $bill) + public function update(BillRequest $request, Bill $bill): JsonResponse { $data = $request->getAll(); $bill = $this->repository->update($bill, $data); diff --git a/app/Api/V1/Controllers/CurrencyController.php b/app/Api/V1/Controllers/CurrencyController.php index 2302f3b4be..176986afb8 100644 --- a/app/Api/V1/Controllers/CurrencyController.php +++ b/app/Api/V1/Controllers/CurrencyController.php @@ -20,25 +20,7 @@ */ declare(strict_types=1); -/** - * CurrencyController.php - * Copyright (c) 2018 thegrumpydictator@gmail.com - * - * This file is part of Firefly III. - * - * Firefly III is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Firefly III is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Firefly III. If not, see . - */ + namespace FireflyIII\Api\V1\Controllers; @@ -49,8 +31,11 @@ use FireflyIII\Models\TransactionCurrency; use FireflyIII\Repositories\Currency\CurrencyRepositoryInterface; use FireflyIII\Repositories\User\UserRepositoryInterface; use FireflyIII\Transformers\CurrencyTransformer; +use Illuminate\Http\JsonResponse; use Illuminate\Http\Request; +use Illuminate\Pagination\LengthAwarePaginator; use League\Fractal\Manager; +use League\Fractal\Pagination\IlluminatePaginatorAdapter; use League\Fractal\Resource\Collection as FractalCollection; use League\Fractal\Resource\Item; use League\Fractal\Serializer\JsonApiSerializer; @@ -69,7 +54,7 @@ class CurrencyController extends Controller /** * CurrencyRepository constructor. * - * @throws \FireflyIII\Exceptions\FireflyException + * @throws FireflyException */ public function __construct() { @@ -91,10 +76,10 @@ class CurrencyController extends Controller * * @param TransactionCurrency $currency * - * @return \Illuminate\Http\Response + * @return JsonResponse * @throws FireflyException */ - public function delete(TransactionCurrency $currency) + public function delete(TransactionCurrency $currency): JsonResponse { if (!$this->userRepository->hasRole(auth()->user(), 'owner')) { // access denied: @@ -113,18 +98,27 @@ class CurrencyController extends Controller * * @param Request $request * - * @return \Illuminate\Http\JsonResponse + * @return JsonResponse */ - public function index(Request $request) + public function index(Request $request): JsonResponse { + $pageSize = (int)Preferences::getForUser(auth()->user(), 'listPageSize', 50)->data; $collection = $this->repository->get(); - $manager = new Manager(); - $baseUrl = $request->getSchemeAndHttpHost() . '/api/v1'; + $count = $collection->count(); + // slice them: + $currencies = $collection->slice(($this->parameters->get('page') - 1) * $pageSize, $pageSize); + $paginator = new LengthAwarePaginator($currencies, $count, $pageSize, $this->parameters->get('page')); + $paginator->setPath(route('api.v1.currencies.index') . $this->buildParams()); + + + $manager = new Manager(); + $baseUrl = $request->getSchemeAndHttpHost() . '/api/v1'; $manager->setSerializer(new JsonApiSerializer($baseUrl)); $defaultCurrency = app('amount')->getDefaultCurrencyByUser(auth()->user()); $this->parameters->set('defaultCurrency', $defaultCurrency); - $resource = new FractalCollection($collection, new CurrencyTransformer($this->parameters), 'currencies'); + $resource = new FractalCollection($currencies, new CurrencyTransformer($this->parameters), 'currencies'); + $resource->setPaginator(new IlluminatePaginatorAdapter($paginator)); return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json'); } @@ -134,9 +128,9 @@ class CurrencyController extends Controller * @param Request $request * @param TransactionCurrency $currency * - * @return \Illuminate\Http\JsonResponse + * @return JsonResponse */ - public function show(Request $request, TransactionCurrency $currency) + public function show(Request $request, TransactionCurrency $currency): JsonResponse { $manager = new Manager(); // add include parameter: @@ -156,10 +150,10 @@ class CurrencyController extends Controller /** * @param CurrencyRequest $request * - * @return \Illuminate\Http\JsonResponse + * @return JsonResponse * @throws FireflyException */ - public function store(CurrencyRequest $request) + public function store(CurrencyRequest $request): JsonResponse { $currency = $this->repository->store($request->getAll()); @@ -178,18 +172,18 @@ class CurrencyController extends Controller return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json'); } - throw new FireflyException('Could not store new currency.'); + throw new FireflyException('Could not store new currency.'); // @codeCoverageIgnore } /** - * @param BillRequest $request + * @param CurrencyRequest $request * @param TransactionCurrency $currency * - * @return \Illuminate\Http\JsonResponse + * @return JsonResponse */ - public function update(CurrencyRequest $request, TransactionCurrency $currency) + public function update(CurrencyRequest $request, TransactionCurrency $currency): JsonResponse { $data = $request->getAll(); $currency = $this->repository->update($currency, $data); @@ -199,8 +193,8 @@ class CurrencyController extends Controller Preferences::mark(); } - $manager = new Manager(); - $baseUrl = $request->getSchemeAndHttpHost() . '/api/v1'; + $manager = new Manager(); + $baseUrl = $request->getSchemeAndHttpHost() . '/api/v1'; $manager->setSerializer(new JsonApiSerializer($baseUrl)); $defaultCurrency = app('amount')->getDefaultCurrencyByUser(auth()->user()); diff --git a/app/Api/V1/Requests/BillRequest.php b/app/Api/V1/Requests/BillRequest.php index 9cc6a848ed..64f64127d6 100644 --- a/app/Api/V1/Requests/BillRequest.php +++ b/app/Api/V1/Requests/BillRequest.php @@ -46,18 +46,17 @@ class BillRequest extends Request public function getAll(): array { $data = [ - 'name' => $this->string('name'), - 'match' => $this->string('match'), - 'amount_min' => $this->string('amount_min'), - 'amount_max' => $this->string('amount_max'), - //'currency_id' => $this->integer('currency_id'), - //'currency_code' => $this->string('currency_code'), - 'date' => $this->date('date'), - 'repeat_freq' => $this->string('repeat_freq'), - 'skip' => $this->integer('skip'), - 'automatch' => $this->boolean('automatch'), - 'active' => $this->boolean('active'), - 'notes' => $this->string('notes'), + 'name' => $this->string('name'), + 'amount_min' => $this->string('amount_min'), + 'amount_max' => $this->string('amount_max'), + 'currency_id' => $this->integer('currency_id'), + 'currency_code' => $this->string('currency_code'), + 'date' => $this->date('date'), + 'repeat_freq' => $this->string('repeat_freq'), + 'skip' => $this->integer('skip'), + 'automatch' => $this->boolean('automatch'), + 'active' => $this->boolean('active'), + 'notes' => $this->string('notes'), ]; return $data; @@ -69,18 +68,17 @@ class BillRequest extends Request public function rules(): array { $rules = [ - 'name' => 'required|between:1,255|uniqueObjectForUser:bills,name', - 'match' => 'required|between:1,255|uniqueObjectForUser:bills,match', - 'amount_min' => 'required|numeric|more:0', - 'amount_max' => 'required|numeric|more:0', - //'currency_id' => 'numeric|exists:transaction_currencies,id|required_without:currency_code', - //'currency_code' => 'min:3|max:3|exists:transaction_currencies,code|required_without:currency_id', - 'date' => 'required|date', - 'repeat_freq' => 'required|in:weekly,monthly,quarterly,half-year,yearly', - 'skip' => 'required|between:0,31', - 'automatch' => 'required|boolean', - 'active' => 'required|boolean', - 'notes' => 'between:1,65536', + 'name' => 'required|between:1,255|uniqueObjectForUser:bills,name', + 'amount_min' => 'required|numeric|more:0', + 'amount_max' => 'required|numeric|more:0', + 'currency_id' => 'numeric|exists:transaction_currencies,id|required_without:currency_code', + 'currency_code' => 'min:3|max:3|exists:transaction_currencies,code|required_without:currency_id', + 'date' => 'required|date', + 'repeat_freq' => 'required|in:weekly,monthly,quarterly,half-year,yearly', + 'skip' => 'required|between:0,31', + 'automatch' => 'required|boolean', + 'active' => 'required|boolean', + 'notes' => 'between:1,65536', ]; switch ($this->method()) { default: diff --git a/app/Api/V1/Requests/CurrencyRequest.php b/app/Api/V1/Requests/CurrencyRequest.php index 1a3c3c020c..72666a3a77 100644 --- a/app/Api/V1/Requests/CurrencyRequest.php +++ b/app/Api/V1/Requests/CurrencyRequest.php @@ -74,9 +74,6 @@ class CurrencyRequest extends Request $rules['name'] = 'required|between:1,255|unique:transaction_currencies,name,' . $currency->id; $rules['code'] = 'required|between:1,255|unique:transaction_currencies,code,' . $currency->id; $rules['symbol'] = 'required|between:1,255|unique:transaction_currencies,symbol,' . $currency->id; - //$bill = $this->route()->parameter('bill'); - //$rules['name'] .= ',' . $bill->id; - //$rules['match'] .= ',' . $bill->id; break; } diff --git a/tests/Api/V1/Controllers/BillControllerTest.php b/tests/Api/V1/Controllers/BillControllerTest.php index ebb886fede..22a4b6cdf0 100644 --- a/tests/Api/V1/Controllers/BillControllerTest.php +++ b/tests/Api/V1/Controllers/BillControllerTest.php @@ -50,8 +50,7 @@ class BillControllerTest extends TestCase /** * Send delete * - * @covers \FireflyIII\Api\V1\Controllers\BillController::delete - * @covers \FireflyIII\Api\V1\Controllers\BillController::__construct + * @covers \FireflyIII\Api\V1\Controllers\BillController */ public function testDelete() { diff --git a/tests/Api/V1/Controllers/CurrencyControllerTest.php b/tests/Api/V1/Controllers/CurrencyControllerTest.php new file mode 100644 index 0000000000..70c18e13a6 --- /dev/null +++ b/tests/Api/V1/Controllers/CurrencyControllerTest.php @@ -0,0 +1,267 @@ +. + */ + +declare(strict_types=1); + +namespace Tests\Api\V1\Controllers; + + +use FireflyIII\Models\Preference; +use FireflyIII\Models\TransactionCurrency; +use FireflyIII\Repositories\Currency\CurrencyRepositoryInterface; +use FireflyIII\Repositories\User\UserRepositoryInterface; +use Laravel\Passport\Passport; +use Log; +use Mockery; +use Preferences; +use Tests\TestCase; + +/** + * Class CurrencyControllerTest + */ +class CurrencyControllerTest extends TestCase +{ + /** + * + */ + public function setUp() + { + parent::setUp(); + Passport::actingAs($this->user()); + Log::debug(sprintf('Now in %s.', get_class($this))); + + } + + /** + * Send delete + * + * @covers \FireflyIII\Api\V1\Controllers\CurrencyController + */ + public function testDelete(): void + { + // mock stuff: + $repository = $this->mock(CurrencyRepositoryInterface::class); + $userRepos = $this->mock(UserRepositoryInterface::class); + + // mock calls: + $repository->shouldReceive('setUser')->once(); + //$userRepos->shouldReceive('setUser')->once(); + + $userRepos->shouldReceive('hasRole')->once()->withArgs([Mockery::any(), 'owner'])->andReturn(true); + $repository->shouldReceive('canDeleteCurrency')->once()->andReturn(true); + + $repository->shouldReceive('destroy')->once()->andReturn(true); + + // get a currency + $currency = TransactionCurrency::first(); + + // call API + $response = $this->delete('/api/v1/currencies/' . $currency->id); + $response->assertStatus(204); + } + + /** + * Show index. + * + * @covers \FireflyIII\Api\V1\Controllers\CurrencyController + */ + public function testIndex(): void + { + $collection = TransactionCurrency::get(); + // mock stuff: + $repository = $this->mock(CurrencyRepositoryInterface::class); + + // mock calls: + $repository->shouldReceive('setUser')->once(); + $repository->shouldReceive('get')->withNoArgs()->andReturn($collection)->once(); + + // test API + $response = $this->get('/api/v1/currencies'); + $response->assertStatus(200); + $response->assertJson(['data' => [],]); + $response->assertJson( + ['meta' => ['pagination' => ['total' => $collection->count(), 'count' => $collection->count(), 'per_page' => 50, 'current_page' => 1, + 'total_pages' => 1]],] + ); + $response->assertJson( + ['links' => ['self' => true, 'first' => true, 'last' => true,],] + ); + $response->assertHeader('Content-Type', 'application/vnd.api+json'); + } + + /** + * Test show of a currency. + * + * @covers \FireflyIII\Api\V1\Controllers\CurrencyController + */ + public function testShow(): void + { + // create stuff + $currency = TransactionCurrency::first(); + $repository = $this->mock(CurrencyRepositoryInterface::class); + + // mock calls: + $repository->shouldReceive('setUser')->once(); + + // test API + $response = $this->get('/api/v1/currencies/' . $currency->id); + $response->assertStatus(200); + $response->assertJson( + ['data' => [ + 'type' => 'currencies', + 'id' => $currency->id, + ],] + ); + $response->assertHeader('Content-Type', 'application/vnd.api+json'); + } + + /** + * @covers \FireflyIII\Api\V1\Controllers\CurrencyController + * @covers \FireflyIII\Api\V1\Requests\CurrencyRequest + */ + public function testStore(): void + { + + $currency = TransactionCurrency::first(); + $repository = $this->mock(CurrencyRepositoryInterface::class); + + // mock calls: + $repository->shouldReceive('setUser')->once(); + $repository->shouldReceive('store')->andReturn($currency); + + // data to submit: + $data = [ + 'name' => 'New currency', + 'code' => 'ABC', + 'symbol' => 'A', + 'decimal_places' => 2, + 'default' => 'false', + ]; + + // test API + $response = $this->post('/api/v1/currencies', $data, ['Accept' => 'application/json']); + $response->assertStatus(200); + $response->assertJson(['data' => ['type' => 'currencies', 'links' => true],]); + $response->assertHeader('Content-Type', 'application/vnd.api+json'); + $response->assertSee($currency->name); + } + + /** + * @covers \FireflyIII\Api\V1\Controllers\CurrencyController + * @covers \FireflyIII\Api\V1\Requests\CurrencyRequest + */ + public function testStoreWithDefault(): void + { + $currency = TransactionCurrency::first(); + $repository = $this->mock(CurrencyRepositoryInterface::class); + $preference = new Preference; + $preference->data = 'EUR'; + // mock calls: + $repository->shouldReceive('setUser')->once(); + $repository->shouldReceive('store')->andReturn($currency); + Preferences::shouldReceive('set')->withArgs(['currencyPreference', 'EUR'])->once(); + Preferences::shouldReceive('mark')->once(); + Preferences::shouldReceive('lastActivity')->once(); + Preferences::shouldReceive('getForUser')->once()->andReturn($preference); + + // data to submit: + $data = [ + 'name' => 'New currency', + 'code' => 'ABC', + 'symbol' => 'A', + 'decimal_places' => 2, + 'default' => 'true', + ]; + + // test API + $response = $this->post('/api/v1/currencies', $data, ['Accept' => 'application/json']); + $response->assertStatus(200); + $response->assertJson(['data' => ['type' => 'currencies', 'links' => true],]); + $response->assertHeader('Content-Type', 'application/vnd.api+json'); + $response->assertSee($currency->name); + } + + /** + * @covers \FireflyIII\Api\V1\Controllers\CurrencyController + * @covers \FireflyIII\Api\V1\Requests\CurrencyRequest + */ + public function testUpdate(): void + { + $currency = TransactionCurrency::first(); + $repository = $this->mock(CurrencyRepositoryInterface::class); + + // mock calls: + $repository->shouldReceive('setUser')->once(); + $repository->shouldReceive('update')->andReturn($currency); + + // data to submit: + $data = [ + 'name' => 'Updated currency', + 'code' => 'ABC', + 'symbol' => '$E', + 'decimal_places' => '2', + 'default' => 'false', + ]; + + // test API + $response = $this->put('/api/v1/currencies/' . $currency->id, $data, ['Accept' => 'application/json']); + $response->assertStatus(200); + $response->assertJson(['data' => ['type' => 'currencies', 'links' => true],]); + $response->assertHeader('Content-Type', 'application/vnd.api+json'); + $response->assertSee($currency->name); + } + + /** + * @covers \FireflyIII\Api\V1\Controllers\CurrencyController + * @covers \FireflyIII\Api\V1\Requests\CurrencyRequest + */ + public function testUpdateWithDefault(): void + { + $currency = TransactionCurrency::first(); + $repository = $this->mock(CurrencyRepositoryInterface::class); + $preference = new Preference; + $preference->data = 'EUR'; + + // mock calls: + $repository->shouldReceive('setUser')->once(); + $repository->shouldReceive('update')->andReturn($currency); + Preferences::shouldReceive('set')->withArgs(['currencyPreference', 'EUR'])->once(); + Preferences::shouldReceive('mark')->once(); + Preferences::shouldReceive('lastActivity')->once(); + Preferences::shouldReceive('getForUser')->once()->andReturn($preference); + + // data to submit: + $data = [ + 'name' => 'Updated currency', + 'code' => 'ABC', + 'symbol' => '$E', + 'decimal_places' => '2', + 'default' => 'true', + ]; + + // test API + $response = $this->put('/api/v1/currencies/' . $currency->id, $data, ['Accept' => 'application/json']); + $response->assertStatus(200); + $response->assertJson(['data' => ['type' => 'currencies', 'links' => true],]); + $response->assertHeader('Content-Type', 'application/vnd.api+json'); + $response->assertSee($currency->name); + } +} \ No newline at end of file From 1f78b9d4bc210b98b8413762fc0fe435b253725f Mon Sep 17 00:00:00 2001 From: James Cole Date: Sun, 15 Apr 2018 19:24:20 +0200 Subject: [PATCH 043/117] Add today as well. #1328 --- app/Http/Controllers/Chart/PiggyBankController.php | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/app/Http/Controllers/Chart/PiggyBankController.php b/app/Http/Controllers/Chart/PiggyBankController.php index 791c5f3b9d..bf6d1df692 100644 --- a/app/Http/Controllers/Chart/PiggyBankController.php +++ b/app/Http/Controllers/Chart/PiggyBankController.php @@ -105,6 +105,15 @@ class PiggyBankController extends Controller $chartData[$label] = $currentSum; $oldest = app('navigation')->addPeriod($oldest, $step, 0); } + /** @var Collection $filtered */ + $finalFiltered = $set->filter( + function (PiggyBankEvent $event) use ($today) { + return $event->date->lte($today); + } + ); + $finalSum = $filtered->sum('amount'); + $finalLabel = $today->formatLocalized((string)trans('config.month_and_day')); + $chartData[$finalLabel] = $finalSum; $data = $this->generator->singleSet($piggyBank->name, $chartData); $cache->store($data); From 1aa94613707186d8b92ea1607c49d44d30e8e169 Mon Sep 17 00:00:00 2001 From: James Cole Date: Mon, 16 Apr 2018 17:51:37 +0200 Subject: [PATCH 044/117] Fix reference to unknown method. --- app/Api/V1/Requests/TransactionRequest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/Api/V1/Requests/TransactionRequest.php b/app/Api/V1/Requests/TransactionRequest.php index 280a7ca741..dfbf8d0619 100644 --- a/app/Api/V1/Requests/TransactionRequest.php +++ b/app/Api/V1/Requests/TransactionRequest.php @@ -225,7 +225,7 @@ class TransactionRequest extends Request return $first; } - $account = $repository->findByNameNull($accountName, [AccountType::ASSET]); + $account = $repository->findByName($accountName, [AccountType::ASSET]); if (null === $account) { $validator->errors()->add($nameField, trans('validation.belongs_user')); From 58a6a95d90edea08f4d6bf30d2d88aaad962bea2 Mon Sep 17 00:00:00 2001 From: James Cole Date: Mon, 16 Apr 2018 17:59:35 +0200 Subject: [PATCH 045/117] Debug code for transaction view. [skip ci] --- resources/views/transactions/show.twig | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/resources/views/transactions/show.twig b/resources/views/transactions/show.twig index e1627928e6..4ccdf24165 100644 --- a/resources/views/transactions/show.twig +++ b/resources/views/transactions/show.twig @@ -360,7 +360,9 @@ - {% set maxIdentifier = ((transactions|length) / 2) -1 %} + {{ dump(transactions|length) }} + + {#{% set maxIdentifier = ((transactions|length) / 2) -1 %}#} {% for x in 0..maxIdentifier %} {# loop each transaction in the array.#} From b3af74404137105878e03eb9152accaa660ddd81 Mon Sep 17 00:00:00 2001 From: James Cole Date: Mon, 16 Apr 2018 18:02:35 +0200 Subject: [PATCH 046/117] Debug code for transaction view. [skip ci] --- resources/views/transactions/show.twig | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/resources/views/transactions/show.twig b/resources/views/transactions/show.twig index 4ccdf24165..6fdb1d95ab 100644 --- a/resources/views/transactions/show.twig +++ b/resources/views/transactions/show.twig @@ -347,6 +347,8 @@

    {{ 'transactions'|_ }}

    + {{ dump(transactions) }} + {{ dump(transactions|length) }} @@ -360,8 +362,8 @@ - {{ dump(transactions|length) }} + {% set maxIdentifier = 1 %} {#{% set maxIdentifier = ((transactions|length) / 2) -1 %}#} {% for x in 0..maxIdentifier %} From 49e48725a563c3fb2a132bbbcc8d6087cd2c0269 Mon Sep 17 00:00:00 2001 From: James Cole Date: Mon, 16 Apr 2018 18:03:56 +0200 Subject: [PATCH 047/117] Debug code for transaction view. [skip ci] --- app/Http/Controllers/TransactionController.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/app/Http/Controllers/TransactionController.php b/app/Http/Controllers/TransactionController.php index f010d38b26..7728d5f9b0 100644 --- a/app/Http/Controllers/TransactionController.php +++ b/app/Http/Controllers/TransactionController.php @@ -228,6 +228,9 @@ class TransactionController extends Controller $what = strtolower($transactionType); $subTitle = trans('firefly.' . $what) . ' "' . $journal->description . '"'; + var_dump($transactions); + exit; + return view('transactions.show', compact('journal', 'events', 'subTitle', 'what', 'transactions', 'linkTypes', 'links')); } From 147e04ecd2bd7424a790459ec28db4c8e4a99e64 Mon Sep 17 00:00:00 2001 From: James Cole Date: Mon, 16 Apr 2018 18:06:53 +0200 Subject: [PATCH 048/117] Debug code for transaction view. [skip ci] --- app/Http/Controllers/TransactionController.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/app/Http/Controllers/TransactionController.php b/app/Http/Controllers/TransactionController.php index 7728d5f9b0..5a35d0b6e7 100644 --- a/app/Http/Controllers/TransactionController.php +++ b/app/Http/Controllers/TransactionController.php @@ -228,8 +228,6 @@ class TransactionController extends Controller $what = strtolower($transactionType); $subTitle = trans('firefly.' . $what) . ' "' . $journal->description . '"'; - var_dump($transactions); - exit; return view('transactions.show', compact('journal', 'events', 'subTitle', 'what', 'transactions', 'linkTypes', 'links')); } From ecdc00dcb7ebe24e3401091f931f1f6b43d27a9c Mon Sep 17 00:00:00 2001 From: James Cole Date: Mon, 16 Apr 2018 19:24:46 +0200 Subject: [PATCH 049/117] Debug code for transaction view. [skip ci] --- app/Http/Controllers/TransactionController.php | 2 +- resources/views/transactions/show.twig | 6 +----- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/app/Http/Controllers/TransactionController.php b/app/Http/Controllers/TransactionController.php index 5a35d0b6e7..b4782f84bd 100644 --- a/app/Http/Controllers/TransactionController.php +++ b/app/Http/Controllers/TransactionController.php @@ -228,7 +228,7 @@ class TransactionController extends Controller $what = strtolower($transactionType); $subTitle = trans('firefly.' . $what) . ' "' . $journal->description . '"'; - + var_dump($transactions);exit; return view('transactions.show', compact('journal', 'events', 'subTitle', 'what', 'transactions', 'linkTypes', 'links')); } diff --git a/resources/views/transactions/show.twig b/resources/views/transactions/show.twig index 6fdb1d95ab..e1627928e6 100644 --- a/resources/views/transactions/show.twig +++ b/resources/views/transactions/show.twig @@ -347,8 +347,6 @@

    {{ 'transactions'|_ }}

    - {{ dump(transactions) }} - {{ dump(transactions|length) }}
    @@ -362,9 +360,7 @@ - - {% set maxIdentifier = 1 %} - {#{% set maxIdentifier = ((transactions|length) / 2) -1 %}#} + {% set maxIdentifier = ((transactions|length) / 2) -1 %} {% for x in 0..maxIdentifier %} {# loop each transaction in the array.#} From 1a8293d9efc625b665b76701d6eb2ab58e02fa58 Mon Sep 17 00:00:00 2001 From: James Cole Date: Mon, 16 Apr 2018 19:25:33 +0200 Subject: [PATCH 050/117] Fix view for transaction controller. --- .../Controllers/TransactionController.php | 1 - app/Http/Middleware/Authenticate.php | 35 ++++++++++++------- 2 files changed, 22 insertions(+), 14 deletions(-) diff --git a/app/Http/Controllers/TransactionController.php b/app/Http/Controllers/TransactionController.php index b4782f84bd..f010d38b26 100644 --- a/app/Http/Controllers/TransactionController.php +++ b/app/Http/Controllers/TransactionController.php @@ -228,7 +228,6 @@ class TransactionController extends Controller $what = strtolower($transactionType); $subTitle = trans('firefly.' . $what) . ' "' . $journal->description . '"'; - var_dump($transactions);exit; return view('transactions.show', compact('journal', 'events', 'subTitle', 'what', 'transactions', 'linkTypes', 'links')); } diff --git a/app/Http/Middleware/Authenticate.php b/app/Http/Middleware/Authenticate.php index cfd265b47b..04cd89f0fb 100644 --- a/app/Http/Middleware/Authenticate.php +++ b/app/Http/Middleware/Authenticate.php @@ -24,8 +24,10 @@ declare(strict_types=1); namespace FireflyIII\Http\Middleware; use Closure; +use FireflyIII\Exceptions\FireflyException; use Illuminate\Auth\AuthenticationException; use Illuminate\Contracts\Auth\Factory as Auth; +use Illuminate\Database\QueryException; /** * Class Authenticate @@ -76,24 +78,31 @@ class Authenticate * * @return mixed * @throws \Illuminate\Auth\AuthenticationException + * @throws FireflyException */ protected function authenticate(array $guards) { - if (empty($guards)) { - // go for default guard: - if ($this->auth->check()) { - // do an extra check on user object. - $user = $this->auth->authenticate(); - if (1 === (int)$user->blocked) { - $message = (string)trans('firefly.block_account_logout'); - if ('email_changed' === $user->blocked_code) { - $message = (string)trans('firefly.email_changed_logout'); - } - app('session')->flash('logoutMessage', $message); - $this->auth->logout(); - throw new AuthenticationException('Blocked account.', $guards); + if (empty($guards)) { + try { + // go for default guard: + if ($this->auth->check()) { + + // do an extra check on user object. + $user = $this->auth->authenticate(); + if (1 === (int)$user->blocked) { + $message = (string)trans('firefly.block_account_logout'); + if ('email_changed' === $user->blocked_code) { + $message = (string)trans('firefly.email_changed_logout'); + } + app('session')->flash('logoutMessage', $message); + $this->auth->logout(); + + throw new AuthenticationException('Blocked account.', $guards); + } } + } catch (QueryException $e) { + throw new FireflyException('It seems the database has not yet been initialized. Did you run the correct upgrade or installation commands?'); } return $this->auth->authenticate(); From 178f917a49b66ffb02c7855103a80bd5d77aa52b Mon Sep 17 00:00:00 2001 From: James Cole Date: Mon, 16 Apr 2018 19:29:26 +0200 Subject: [PATCH 051/117] Fix #1348 --- app/Helpers/Collector/JournalCollector.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/app/Helpers/Collector/JournalCollector.php b/app/Helpers/Collector/JournalCollector.php index 4895be8241..528d8b21e5 100644 --- a/app/Helpers/Collector/JournalCollector.php +++ b/app/Helpers/Collector/JournalCollector.php @@ -254,6 +254,9 @@ class JournalCollector implements JournalCollectorInterface $key = 'query-' . substr($hash, -8); $cache = new CacheProperties; $cache->addProperty($key); + foreach($this->filters as $filter) { + $cache->addProperty((string)$filter); + } if ($cache->has()) { Log::debug(sprintf('Return cache of query with ID "%s".', $key)); From eb6ac7d1d1f93ad4bfbfa12021b752c2c49e9102 Mon Sep 17 00:00:00 2001 From: James Cole Date: Mon, 16 Apr 2018 20:12:30 +0200 Subject: [PATCH 052/117] Remove unused methods. --- resources/views/reports/partials/journals-audit.twig | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/resources/views/reports/partials/journals-audit.twig b/resources/views/reports/partials/journals-audit.twig index b9c03d77c2..b59e9103b7 100644 --- a/resources/views/reports/partials/journals-audit.twig +++ b/resources/views/reports/partials/journals-audit.twig @@ -66,18 +66,18 @@ @@ -85,19 +85,19 @@ {# new optional fields (3x) #} From 900e8202e6906094469cdbf72c2862e9a330b360 Mon Sep 17 00:00:00 2001 From: James Cole Date: Mon, 16 Apr 2018 20:21:28 +0200 Subject: [PATCH 053/117] Remove some deprecated functions. --- app/Providers/FireflyServiceProvider.php | 2 + app/Support/Twig/Extension/Account.php | 51 ++++++++++++++++++++++ app/Support/Twig/General.php | 4 +- app/Support/Twig/Loader/AccountLoader.php | 52 +++++++++++++++++++++++ resources/views/list/accounts.twig | 2 +- resources/views/reports/index.twig | 4 +- 6 files changed, 110 insertions(+), 5 deletions(-) create mode 100644 app/Support/Twig/Extension/Account.php create mode 100644 app/Support/Twig/Loader/AccountLoader.php diff --git a/app/Providers/FireflyServiceProvider.php b/app/Providers/FireflyServiceProvider.php index 6bea0cca5b..842103b20e 100644 --- a/app/Providers/FireflyServiceProvider.php +++ b/app/Providers/FireflyServiceProvider.php @@ -61,6 +61,7 @@ use FireflyIII\Support\Steam; use FireflyIII\Support\Twig\AmountFormat; use FireflyIII\Support\Twig\General; use FireflyIII\Support\Twig\Journal; +use FireflyIII\Support\Twig\Loader\AccountLoader; use FireflyIII\Support\Twig\Loader\TransactionJournalLoader; use FireflyIII\Support\Twig\Loader\TransactionLoader; use FireflyIII\Support\Twig\PiggyBank; @@ -93,6 +94,7 @@ class FireflyServiceProvider extends ServiceProvider $config = app('config'); Twig::addExtension(new Functions($config)); Twig::addRuntimeLoader(new TransactionLoader); + Twig::addRuntimeLoader(new AccountLoader); Twig::addRuntimeLoader(new TransactionJournalLoader); Twig::addExtension(new PiggyBank); Twig::addExtension(new General); diff --git a/app/Support/Twig/Extension/Account.php b/app/Support/Twig/Extension/Account.php new file mode 100644 index 0000000000..c3e61b32ba --- /dev/null +++ b/app/Support/Twig/Extension/Account.php @@ -0,0 +1,51 @@ +. + */ +declare(strict_types=1); + +namespace FireflyIII\Support\Twig\Extension; + +use FireflyIII\Models\Account as AccountModel; +use FireflyIII\Repositories\Account\AccountRepositoryInterface; +use Twig_Extension; + +/** + * Class Account. + */ +class Account extends Twig_Extension +{ + /** + * @param AccountModel $account + * @param string $field + * + * @return string + */ + public function getMetaField(AccountModel $account, string $field): string + { + /** @var AccountRepositoryInterface $repository */ + $repository = app(AccountRepositoryInterface::class); + $result = $repository->getMetaValue($account, $field); + if (null === $result) { + return ''; + } + + return $result; + } +} diff --git a/app/Support/Twig/General.php b/app/Support/Twig/General.php index eb53c2311d..ca06db2ada 100644 --- a/app/Support/Twig/General.php +++ b/app/Support/Twig/General.php @@ -29,6 +29,7 @@ use Route; use Twig_Extension; use Twig_SimpleFilter; use Twig_SimpleFunction; +use FireflyIII\Support\Twig\Extension\Account as AccountExtension; /** * Class TwigSupport. @@ -58,12 +59,11 @@ class General extends Twig_Extension $this->getCurrencySymbol(), $this->phpdate(), $this->env(), - //$this->getAmountFromJournal(), $this->activeRouteStrict(), - //$this->steamPositive(), $this->activeRoutePartial(), $this->activeRoutePartialWhat(), $this->formatDate(), + new Twig_SimpleFunction('accountGetMetaField', [AccountExtension::class, 'getMetaField']), ]; } diff --git a/app/Support/Twig/Loader/AccountLoader.php b/app/Support/Twig/Loader/AccountLoader.php new file mode 100644 index 0000000000..be92e6586d --- /dev/null +++ b/app/Support/Twig/Loader/AccountLoader.php @@ -0,0 +1,52 @@ +. + */ +declare(strict_types=1); + +namespace FireflyIII\Support\Twig\Loader; + +use FireflyIII\Support\Twig\Extension\Account; +use Twig_RuntimeLoaderInterface; + +/** + * Class AccountLoader. + */ +class AccountLoader implements Twig_RuntimeLoaderInterface +{ + /** + * Creates the runtime implementation of a Twig element (filter/function/test). + * + * @param string $class A runtime class + * + * @return object|null The runtime instance or null if the loader does not know how to create the runtime for this class + */ + public function load($class) + { + // implement the logic to create an instance of $class + // and inject its dependencies + // most of the time, it means using your dependency injection container + + if (Account::class === $class) { + return app(Account::class); + } + + return null; + } +} diff --git a/resources/views/list/accounts.twig b/resources/views/list/accounts.twig index 90c69be280..7d016cbf77 100644 --- a/resources/views/list/accounts.twig +++ b/resources/views/list/accounts.twig @@ -40,7 +40,7 @@ {% endfor %} {% endif %} - + - {% for piggyBank in piggyBanks %} - + {% for piggy in piggyBanks %} + - - diff --git a/resources/views/piggy-banks/add-mobile.twig b/resources/views/piggy-banks/add-mobile.twig index 05c4b9667b..586e932204 100644 --- a/resources/views/piggy-banks/add-mobile.twig +++ b/resources/views/piggy-banks/add-mobile.twig @@ -16,11 +16,11 @@
    {% if maxAmount > 0 %}

    - {{ 'max_amount_add'|_ }}: {{ maxAmount|formatAmount }}. + {{ 'max_amount_add'|_ }}: {{ formatAmountByCurrency(currency,maxAmount) }}.

    -
    {{ getCurrencySymbol()|raw }}
    +
    {{ currency.symbol|raw }}
    diff --git a/resources/views/piggy-banks/add.twig b/resources/views/piggy-banks/add.twig index 78af5e46cc..9c4da8d832 100644 --- a/resources/views/piggy-banks/add.twig +++ b/resources/views/piggy-banks/add.twig @@ -11,12 +11,12 @@

    - {{ 'max_amount_add'|_ }}: {{ maxAmount|formatAmount }}. + {{ 'max_amount_add'|_ }}: {{ formatAmountByCurrency(currency,maxAmount) }}.

    -
    {{ getCurrencySymbol()|raw }}
    - +
    {{ currency.symbol|raw }}
    +
    diff --git a/resources/views/piggy-banks/edit.twig b/resources/views/piggy-banks/edit.twig index 427a9670a5..7b99a5be8d 100644 --- a/resources/views/piggy-banks/edit.twig +++ b/resources/views/piggy-banks/edit.twig @@ -20,7 +20,7 @@ {{ ExpandedForm.text('name') }} {{ ExpandedForm.assetAccountList('account_id', null, {label: 'saveOnAccount'|_ }) }} - {{ ExpandedForm.amount('targetamount') }} + {{ ExpandedForm.amountNoCurrency('targetamount') }} diff --git a/resources/views/piggy-banks/index.twig b/resources/views/piggy-banks/index.twig index 145a4a4a71..9f735be2ab 100644 --- a/resources/views/piggy-banks/index.twig +++ b/resources/views/piggy-banks/index.twig @@ -5,7 +5,7 @@ {% endblock %} {% block content %} - {% if piggyBanks.count == 0 %} + {% if piggyBanks|length == 0 %} {% include 'partials.empty' with {what: 'default', type: 'piggies',route: route('piggy-banks.create')} %} {% else %}
    @@ -49,11 +49,21 @@ {% for id,info in accounts %}
    - - - - - + + + + + {% endfor %} diff --git a/resources/views/piggy-banks/remove-mobile.twig b/resources/views/piggy-banks/remove-mobile.twig index 18ae39a048..f5fbe224e2 100644 --- a/resources/views/piggy-banks/remove-mobile.twig +++ b/resources/views/piggy-banks/remove-mobile.twig @@ -15,12 +15,12 @@

    - {{ 'max_amount_remove'|_ }}: {{ currentRelevantRepAmount(piggyBank)|formatAmount }}. + {{ 'max_amount_remove'|_ }}: {{ formatAmountByCurrency(currency, repetition.currentamount) }}.

    -
    {{ getCurrencySymbol()|raw }}
    - {{ currency.symbol|raw }}
    +

    diff --git a/resources/views/piggy-banks/remove.twig b/resources/views/piggy-banks/remove.twig index 190616cc24..7527b7d798 100644 --- a/resources/views/piggy-banks/remove.twig +++ b/resources/views/piggy-banks/remove.twig @@ -11,12 +11,12 @@

    From 529dd490b7960c9325bcb8d9ed1d748d3be40208 Mon Sep 17 00:00:00 2001 From: James Cole Date: Sun, 22 Apr 2018 07:16:09 +0200 Subject: [PATCH 068/117] Fix #1336 --- app/Http/Controllers/Account/ReconcileController.php | 6 +++++- resources/views/accounts/reconcile/transactions.twig | 5 ++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/app/Http/Controllers/Account/ReconcileController.php b/app/Http/Controllers/Account/ReconcileController.php index a78eda07b5..33f80dd1f6 100644 --- a/app/Http/Controllers/Account/ReconcileController.php +++ b/app/Http/Controllers/Account/ReconcileController.php @@ -320,10 +320,12 @@ class ReconcileController extends Controller 'notes' => implode(', ', $data['transactions']), ]; - $journal = $repository->store($journalData); + $repository->store($journalData); } Log::debug('End of routine.'); + Preferences::mark(); + Session::flash('success', trans('firefly.reconciliation_stored')); return redirect(route('accounts.show', [$account->id])); @@ -438,6 +440,8 @@ class ReconcileController extends Controller $this->repository->update($journal, $data); + + // @codeCoverageIgnoreStart if (1 === (int)$request->get('return_to_edit')) { Session::put('reconcile.edit.fromUpdate', true); diff --git a/resources/views/accounts/reconcile/transactions.twig b/resources/views/accounts/reconcile/transactions.twig index dc315196a6..7053e9a77e 100644 --- a/resources/views/accounts/reconcile/transactions.twig +++ b/resources/views/accounts/reconcile/transactions.twig @@ -88,14 +88,13 @@ {% set transactionAmount = transaction.transaction_foreign_amount %} {% endif %} - {% if transaction.reconciled %} {{ transaction|transactionReconciled }} - {% else %} {% endif %} From 49421f50acfba306d6d0de0ea4fc2bcbed4ea2d4 Mon Sep 17 00:00:00 2001 From: James Cole Date: Sun, 22 Apr 2018 08:07:33 +0200 Subject: [PATCH 069/117] Will not store fields with empty strings or weird value --- .../Internal/Support/AccountServiceTrait.php | 26 +++++++++++-------- .../Internal/Update/AccountUpdateService.php | 4 +++ 2 files changed, 19 insertions(+), 11 deletions(-) diff --git a/app/Services/Internal/Support/AccountServiceTrait.php b/app/Services/Internal/Support/AccountServiceTrait.php index f126d66605..9e320e3034 100644 --- a/app/Services/Internal/Support/AccountServiceTrait.php +++ b/app/Services/Internal/Support/AccountServiceTrait.php @@ -329,18 +329,22 @@ trait AccountServiceTrait /** @var AccountMeta $entry */ $entry = $account->accountMeta()->where('name', $field)->first(); - // if $data has field and $entry is null, create new one: - if (isset($data[$field]) && null === $entry) { - Log::debug(sprintf('Created meta-field "%s":"%s" for account #%d ("%s") ', $field, $data[$field], $account->id, $account->name)); - $factory->create(['account_id' => $account->id, 'name' => $field, 'data' => $data[$field],]); - } + // must not be an empty string: + if (isset($data[$field]) && strlen((string)$data[$field]) > 0) { - // if $data has field and $entry is not null, update $entry: - // let's not bother with a service. - if (isset($data[$field]) && null !== $entry) { - $entry->data = $data[$field]; - $entry->save(); - Log::debug(sprintf('Updated meta-field "%s":"%s" for #%d ("%s") ', $field, $data[$field], $account->id, $account->name)); + // if $data has field and $entry is null, create new one: + if (null === $entry) { + Log::debug(sprintf('Created meta-field "%s":"%s" for account #%d ("%s") ', $field, $data[$field], $account->id, $account->name)); + $factory->create(['account_id' => $account->id, 'name' => $field, 'data' => $data[$field],]); + } + + // if $data has field and $entry is not null, update $entry: + // let's not bother with a service. + if (null !== $entry) { + $entry->data = $data[$field]; + $entry->save(); + Log::debug(sprintf('Updated meta-field "%s":"%s" for #%d ("%s") ', $field, $data[$field], $account->id, $account->name)); + } } } } diff --git a/app/Services/Internal/Update/AccountUpdateService.php b/app/Services/Internal/Update/AccountUpdateService.php index c9711c0b46..e286d702d1 100644 --- a/app/Services/Internal/Update/AccountUpdateService.php +++ b/app/Services/Internal/Update/AccountUpdateService.php @@ -51,6 +51,10 @@ class AccountUpdateService $account->iban = $data['iban']; $account->save(); + if($data['currency_id'] === 0) { + unset($data['currency_id']); + } + // update all meta data: $this->updateMetaData($account, $data); From c682e69ee7e80c128eb2b720eed2ee789a4af25b Mon Sep 17 00:00:00 2001 From: James Cole Date: Sun, 22 Apr 2018 08:07:46 +0200 Subject: [PATCH 070/117] Keep order --- app/Helpers/Collector/JournalCollector.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/Helpers/Collector/JournalCollector.php b/app/Helpers/Collector/JournalCollector.php index 528d8b21e5..16f798adef 100644 --- a/app/Helpers/Collector/JournalCollector.php +++ b/app/Helpers/Collector/JournalCollector.php @@ -254,7 +254,7 @@ class JournalCollector implements JournalCollectorInterface $key = 'query-' . substr($hash, -8); $cache = new CacheProperties; $cache->addProperty($key); - foreach($this->filters as $filter) { + foreach ($this->filters as $filter) { $cache->addProperty((string)$filter); } if ($cache->has()) { @@ -682,6 +682,7 @@ class JournalCollector implements JournalCollectorInterface ->orderBy('transaction_journals.order', 'ASC') ->orderBy('transaction_journals.id', 'DESC') ->orderBy('transaction_journals.description', 'DESC') + ->orderBy('transactions.identifier', 'ASC') ->orderBy('transactions.amount', 'DESC'); $this->query = $query; From e005fe7ce144c0d22c408d594cffea0ee806793f Mon Sep 17 00:00:00 2001 From: James Cole Date: Sun, 22 Apr 2018 08:07:57 +0200 Subject: [PATCH 071/117] Also show foreign amount. --- app/Http/Controllers/Transaction/SplitController.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/app/Http/Controllers/Transaction/SplitController.php b/app/Http/Controllers/Transaction/SplitController.php index d0a961fb41..3229d73ac9 100644 --- a/app/Http/Controllers/Transaction/SplitController.php +++ b/app/Http/Controllers/Transaction/SplitController.php @@ -247,8 +247,9 @@ class SplitController extends Controller } if (count($res) > 0) { - $res['amount'] = app('steam')->positive((string)$res['amount']); - $transactions[] = $res; + $res['amount'] = app('steam')->positive((string)$res['amount']); + $res['foreign_amount'] = app('steam')->positive((string)$res['foreign_amount']); + $transactions[] = $res; } } From f16b2257c61323812c650b286032e8bae85e7d6e Mon Sep 17 00:00:00 2001 From: James Cole Date: Sun, 22 Apr 2018 08:08:09 +0200 Subject: [PATCH 072/117] Custom input for amount. --- public/css/firefly.css | 25 +++ resources/views/transactions/split/edit.twig | 152 ++++++++++--------- 2 files changed, 102 insertions(+), 75 deletions(-) diff --git a/public/css/firefly.css b/public/css/firefly.css index 4a9b209600..25487e0ffe 100644 --- a/public/css/firefly.css +++ b/public/css/firefly.css @@ -18,6 +18,31 @@ * along with Firefly III. If not, see . */ +.split_amount_input { + width: 40%; + border-radius: 0; + height: 36px; + padding: 6px 12px; + background-color: #fff; + background-image: none; + border: 1px solid #ccd0d2; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075); + -webkit-transition: border-color .15s ease-in-out, box-shadow .15s ease-in-out; + -webkit-transition: border-color .15s ease-in-out, -webkit-box-shadow .15s ease-in-out; + transition: border-color .15s ease-in-out, -webkit-box-shadow .15s ease-in-out; + transition: border-color .15s ease-in-out, box-shadow .15s ease-in-out; + transition: border-color .15s ease-in-out, box-shadow .15s ease-in-out, -webkit-box-shadow .15s ease-in-out; + +} + +.split_amount_input:focus { + border-color: #98cbe8; + outline: 0; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 8px rgba(152, 203, 232, .6); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 8px rgba(152, 203, 232, .6); +} + #daterange { cursor: pointer; } diff --git a/resources/views/transactions/split/edit.twig b/resources/views/transactions/split/edit.twig index 1cb3cbc0cb..dc5dbb9e60 100644 --- a/resources/views/transactions/split/edit.twig +++ b/resources/views/transactions/split/edit.twig @@ -184,7 +184,7 @@
    -
     
    + {# HEADER #}
    {{ trans('list.split_number') }}
    {{ trans('list.description') }}
    {# withdrawal and deposit have a destination. #} @@ -195,28 +195,25 @@ {% if preFilled.what == 'deposit' %}
    {{ trans('list.source') }}
    {% endif %} -
    {{ trans('list.amount') }}
    -
    -   -
    +
    {{ trans('list.amount') }}
    {# only withdrawal has budget #} {% if preFilled.what == 'withdrawal' %} -
    {{ trans('list.budget') }}
    +
    {{ trans('list.budget') }}
    {% endif %}
    {{ trans('list.category') }}
    + {# ROWS #} + + {% for index, transaction in preFilled.transactions %}
    {# button #}
    - + #{{ loop.index }}
    - {# index #} -
    #{{ loop.index }}
    - {# description #}
    + value="{% if transaction.destination_type != 'Cash account' %}{{ transaction.destination_name }}{% endif %}" + class="form-control"/>
    {% endif %} @@ -241,81 +239,85 @@ {% endif %} {# amount#} +
    + {{ transaction.currency_symbol }}  + {% if transaction.foreign_amount != null %} + {{ transaction.foreign_currency_symbol }}  + + {% endif %} + +
    + {# + {% if transaction.foreign_amount != null %} +
    + {% else %} +
    + {% endif %} + + {% if transaction.foreign_amount != null %} -
    - {% else %} -
    - {% endif %} +
    -
    {{ transaction.currency_symbol }}
    - {{ transaction.foreign_currency_symbol }}
    +
    - -
    - - {# foreign amount #} - {% if transaction.foreign_amount != null %} -
    -
    -
    {{ transaction.foreign_currency_symbol }}
    - -
    - - -
    - {% endif %} - - {# budget #} - {% if preFilled.what == 'withdrawal' %} -
    - -
    - {% endif %} - - {# category #} -
    - + +
    + {% endif %} + #} + {# budget #} + {% if preFilled.what == 'withdrawal' %} +
    +
    - {% endfor %} + {% endif %} + + {# category #} +
    +
    -

    -
    - {{ 'add_another_split'|_ }} -

    -
    -
    -
    -
    -
    -
    - {# panel for options #} -
    -
    -

    {{ 'options'|_ }}

    -
    -
    - {{ ExpandedForm.optionsList('update','split-transaction') }} -
    - + {% endfor %} +
    +

    +
    + {{ 'add_another_split'|_ }} +

    +
    +
    +
    +
    +
    +
    + {# panel for options #} +
    +
    +

    {{ 'options'|_ }}

    +
    +
    + {{ ExpandedForm.optionsList('update','split-transaction') }} +
    +
    +
    {% endblock %} From 01c10e320cc8fc4209e8dd78487c78347472936b Mon Sep 17 00:00:00 2001 From: James Cole Date: Sun, 22 Apr 2018 09:16:51 +0200 Subject: [PATCH 073/117] Fix for #1364 --- .../Transaction/SplitController.php | 8 +- public/js/ff/transactions/split/edit.js | 63 ++++-- resources/lang/en_US/form.php | 1 + resources/views/transactions/split/edit.twig | 189 +++++++++--------- 4 files changed, 143 insertions(+), 118 deletions(-) diff --git a/app/Http/Controllers/Transaction/SplitController.php b/app/Http/Controllers/Transaction/SplitController.php index 3229d73ac9..6910c9ec72 100644 --- a/app/Http/Controllers/Transaction/SplitController.php +++ b/app/Http/Controllers/Transaction/SplitController.php @@ -189,7 +189,8 @@ class SplitController extends Controller $destinationAccounts = $this->repository->getJournalDestinationAccounts($journal); $array = [ 'journal_description' => $request->old('journal_description', $journal->description), - 'journal_amount' => $this->repository->getJournalTotal($journal), + 'journal_amount' => '0', + 'journal_foreign_amount' => '0', 'sourceAccounts' => $sourceAccounts, 'journal_source_account_id' => $request->old('journal_source_account_id', $sourceAccounts->first()->id), 'journal_source_account_name' => $request->old('journal_source_account_name', $sourceAccounts->first()->name), @@ -213,9 +214,12 @@ class SplitController extends Controller 'transactions' => $this->getTransactionDataFromJournal($journal), ]; // update transactions array with old request data. - $array['transactions'] = $this->updateWithPrevious($array['transactions'], $request->old()); + // update journal amount and foreign amount: + $array['journal_amount'] = array_sum(array_column($array['transactions'], 'amount')); + $array['journal_foreign_amount'] = array_sum(array_column($array['transactions'], 'foreign_amount')); + return $array; } diff --git a/public/js/ff/transactions/split/edit.js b/public/js/ff/transactions/split/edit.js index 97b4c1f88f..9b5aae1e99 100644 --- a/public/js/ff/transactions/split/edit.js +++ b/public/js/ff/transactions/split/edit.js @@ -19,7 +19,7 @@ */ -/** global: originalSum, accounting, what, Modernizr, currencySymbol */ +/** global: originalSum,originalForeignSum, accounting, what, Modernizr, currencySymbol, foreignCurrencySymbol */ var destAccounts = {}; var srcAccounts = {}; @@ -69,7 +69,8 @@ $(document).ready(function () { }); - $('input[name$="][amount]"]').on('input', calculateSum); + $('input[name$="][amount]"]').on('change', calculateBothSums); + $('input[name$="][foreign_amount]"]').on('change', calculateBothSums); if (!Modernizr.inputtypes.date) { $('input[type="date"]').datepicker( @@ -80,6 +81,12 @@ $(document).ready(function () { } }); +function calculateBothSums() { + console.log("Now in calculateBothSums()"); + calculateSum(); + calculateForeignSum(); +} + /** * New and cool * @param e @@ -113,8 +120,8 @@ function cloneDivRow() { source.removeClass('initial-row'); source.find('.count').text('#' + count); - source.find('input[name$="][amount]"]').val("").on('input', calculateSum); - source.find('input[name$="][foreign_amount]"]').val("").on('input', calculateSum); + source.find('input[name$="][amount]"]').val("").on('change', calculateBothSums); + source.find('input[name$="][foreign_amount]"]').val("").on('change', calculateBothSums); if (destAccounts.length > 0) { source.find('input[name$="destination_account_name]"]').typeahead({source: destAccounts, autoSelect: false}); } @@ -134,7 +141,7 @@ function cloneDivRow() { // remove original click things, add them again: $('.remove-current-split').unbind('click').click(removeDivRow); - calculateSum(); + calculateBothSums(); resetDivSplits(); return false; @@ -166,16 +173,10 @@ function resetDivSplits() { $.each($('.remove-current-split'), function (i, v) { var button = $(v); button.attr('data-split', i); - button.find('i').attr('data-split', i); + button.find('span').text(' #' + (i + 1)); }); - // loop each indicator (#) and update it: - $.each($('td.count'), function (i, v) { - var cell = $(v); - var index = i + 1; - cell.text('#' + index); - }); // loop each possible field. @@ -234,6 +235,7 @@ function resetDivSplits() { function calculateSum() { "use strict"; + console.log("Now in calculateSum()"); var left = originalSum * -1; var sum = 0; var set = $('input[name$="][amount]"]'); @@ -245,14 +247,43 @@ function calculateSum() { sum = Math.round(sum * 100) / 100; left = Math.round(left * 100) / 100; + console.log("Sum is " + sum + ", left is " + left); $('.amount-warning').remove(); if (sum !== originalSum) { - var holder = $('#journal_amount_holder'); - var par = holder.find('p.form-control-static'); - $('').text(' (' + accounting.formatMoney(sum, currencySymbol) + ')').addClass('text-danger amount-warning').appendTo(par); + console.log("Is different from original sum " + originalSum); + var paragraph = $('#journal_amount_holder').find('p.form-control-static'); + + $('').text(' (' + accounting.formatMoney(sum, currencySymbol) + ')').addClass('text-danger amount-warning').appendTo(paragraph); + // also add what's left to divide (or vice versa) - $('').text(' (' + accounting.formatMoney(left, currencySymbol) + ')').addClass('text-danger amount-warning').appendTo(par); + $('').text(' (' + accounting.formatMoney(left, currencySymbol) + ')').addClass('text-danger amount-warning').appendTo(paragraph); + } + +} + + +function calculateForeignSum() { + // "use strict"; + var left = originalForeignSum * -1; + var sum = 0; + var set = $('input[name$="][foreign_amount]"]'); + for (var i = 0; i < set.length; i++) { + var current = $(set[i]); + sum += (current.val() === "" ? 0 : parseFloat(current.val())); + left += (current.val() === "" ? 0 : parseFloat(current.val())); + } + sum = Math.round(sum * 100) / 100; + left = Math.round(left * 100) / 100; + + + $('.amount-warning-foreign').remove(); + if (sum !== originalForeignSum) { + var paragraph = $('#journal_foreign_amount_holder').find('p.form-control-static'); + $('').text(' (' + accounting.formatMoney(sum, foreignCurrencySymbol) + ')').addClass('text-danger amount-warning-foreign').appendTo(paragraph); + + // also add what's left to divide (or vice versa) + $('').text(' (' + accounting.formatMoney(left, foreignCurrencySymbol) + ')').addClass('text-danger amount-warning-foreign').appendTo(paragraph); } } \ No newline at end of file diff --git a/resources/lang/en_US/form.php b/resources/lang/en_US/form.php index e763ae382d..9904018181 100644 --- a/resources/lang/en_US/form.php +++ b/resources/lang/en_US/form.php @@ -94,6 +94,7 @@ return [ 'convert_Transfer' => 'Convert transfer', 'amount' => 'Amount', + 'foreign_amount' => 'Foreign amount', 'date' => 'Date', 'interest_date' => 'Interest date', 'book_date' => 'Book date', diff --git a/resources/views/transactions/split/edit.twig b/resources/views/transactions/split/edit.twig index dc5dbb9e60..b4dd2ad247 100644 --- a/resources/views/transactions/split/edit.twig +++ b/resources/views/transactions/split/edit.twig @@ -50,18 +50,29 @@ {{ ExpandedForm.assetAccountList('journal_destination_account_id', preFilled.journal_destination_account_id) }} {% endif %} - {# TOTAL AMOUNT IS STATIC TEXT #} - {% if preFilled.what == 'withdrawal' or preFilled.what == 'transfer' %} - {{ ExpandedForm.staticText('journal_amount', formatAmountByAccount(accountArray[preFilled.journal_source_account_id], preFilled.journal_amount, true) ) }} - - {% endif %} - - {% if preFilled.what == 'deposit' %} - {{ ExpandedForm.staticText('journal_amount', formatAmountByAccount(accountArray[preFilled.journal_destination_account_id], preFilled.journal_amount, true) ) }} - - {% endif %} - + {# show amount and some helper text when making splits: #} + {# amount #} +
    + +
    +

    + {{ formatAmountBySymbol(preFilled.journal_amount, preFilled.transactions[0].currency_symbol, preFilled.transactions[0].currency_dp) }} +

    +
    +
    + {# foreign amount, if not zero. #} + {% if preFilled.journal_foreign_amount != 0 %} +
    + +
    +

    + {{ formatAmountBySymbol(preFilled.journal_foreign_amount, preFilled.transactions[0].foreign_currency_symbol, preFilled.transactions[0].foreign_currency_dp) }} +

    +
    +
    + {% endif %} + {# DATE #} {{ ExpandedForm.date('date', journal.date) }} @@ -207,101 +218,83 @@ {% for index, transaction in preFilled.transactions %} -
    - {# button #} - +
    + {# button #} + - {# description #} -
    - -
    - - {# destination for withdrawals: #} - {% if preFilled.what == 'withdrawal' %} -
    - +
    - {% endif %} - {# source for deposits #} - {% if preFilled.what == 'deposit' %} -
    - -
    - {% endif %} - - {# amount#} -
    - {{ transaction.currency_symbol }}  - {% if transaction.foreign_amount != null %} - {{ transaction.foreign_currency_symbol }}  - - {% endif %} - -
    - {# - {% if transaction.foreign_amount != null %} -
    - {% else %} -
    - {% endif %} - - - {% if transaction.foreign_amount != null %} -
    -
    -
    {{ transaction.foreign_currency_symbol }}
    - + {# destination for withdrawals: #} + {% if preFilled.what == 'withdrawal' %} +
    +
    - + {% endif %} + {# source for deposits #} + {% if preFilled.what == 'deposit' %} +
    + +
    + {% endif %} + + {# amount#} +
    + {{ transaction.currency_symbol }}  + {% if transaction.foreign_amount != null %} + {{ transaction.foreign_currency_symbol }}  + + {% endif %} +
    - {% endif %} - #} - {# budget #} - {% if preFilled.what == 'withdrawal' %} -
    - -
    - {% endif %} + {# budget #} + {% if preFilled.what == 'withdrawal' %} +
    + +
    + {% endif %} - {# category #} -
    - -
    + {# category #} +
    + +
    +
    + {% endfor %}
    - {% endfor %} +

    +
    + {{ 'add_another_split'|_ }} +

    -

    -
    - {{ 'add_another_split'|_ }} -

    -
    {# panel for options #} @@ -329,14 +322,10 @@ {% block scripts %} From 07768a43c8b33ea1f29ec90f864a5a9842ec6d82 Mon Sep 17 00:00:00 2001 From: James Cole Date: Sun, 22 Apr 2018 09:40:03 +0200 Subject: [PATCH 074/117] Code for #1321 --- public/js/ff/transactions/single/edit.js | 2 ++ resources/lang/en_US/form.php | 1 + resources/views/transactions/single/edit.twig | 30 +++++++++++++++++-- 3 files changed, 30 insertions(+), 3 deletions(-) diff --git a/public/js/ff/transactions/single/edit.js b/public/js/ff/transactions/single/edit.js index 86b79bf30a..cf5248e021 100644 --- a/public/js/ff/transactions/single/edit.js +++ b/public/js/ff/transactions/single/edit.js @@ -52,6 +52,8 @@ $(document).ready(function () { // convert source currency to destination currency (slightly different routine for transfers) $('#ffInput_source_amount').on('change', convertSourceToDestination); + // + }); diff --git a/resources/lang/en_US/form.php b/resources/lang/en_US/form.php index 9904018181..46bf5d8c85 100644 --- a/resources/lang/en_US/form.php +++ b/resources/lang/en_US/form.php @@ -95,6 +95,7 @@ return [ 'amount' => 'Amount', 'foreign_amount' => 'Foreign amount', + 'existing_attachments' => 'Existing attachments', 'date' => 'Date', 'interest_date' => 'Interest date', 'book_date' => 'Book date', diff --git a/resources/views/transactions/single/edit.twig b/resources/views/transactions/single/edit.twig index 13c50709be..11fc096c5b 100644 --- a/resources/views/transactions/single/edit.twig +++ b/resources/views/transactions/single/edit.twig @@ -177,15 +177,39 @@
    {% endif %} - {% if optionalFields.attachments %} + {% if optionalFields.attachments or journal.attachments|length > 0 %}

    {{ 'optional_field_attachments'|_ }}

    - {% if optionalFields.attachments %} - {{ ExpandedForm.file('attachments[]', {'multiple': 'multiple','helpText': trans('firefly.upload_max_file_size', {'size': uploadSize|filesize}) }) }} + {% if journal.attachments|length > 0 %} +
    + +
    + {% for att in journal.attachments %} + + {% endfor %} +
    +
    {% endif %} + + {{ ExpandedForm.file('attachments[]', {'multiple': 'multiple','helpText': trans('firefly.upload_max_file_size', {'size': uploadSize|filesize}) }) }} +
    {% endif %} From 8f3e4a2dee19b9527817725797c4d17f004604f0 Mon Sep 17 00:00:00 2001 From: James Cole Date: Sun, 22 Apr 2018 11:17:30 +0200 Subject: [PATCH 075/117] Code for #1356 --- app/Http/Controllers/BudgetController.php | 83 +++++++++++++---------- public/js/ff/budgets/index.js | 8 ++- resources/views/budgets/index.twig | 8 ++- 3 files changed, 60 insertions(+), 39 deletions(-) diff --git a/app/Http/Controllers/BudgetController.php b/app/Http/Controllers/BudgetController.php index ebe0ca12e3..f82fa49e95 100644 --- a/app/Http/Controllers/BudgetController.php +++ b/app/Http/Controllers/BudgetController.php @@ -87,16 +87,31 @@ class BudgetController extends Controller $budgetLimit = $this->repository->updateLimitAmount($budget, $start, $end, $amount); $largeDiff = false; $warnText = ''; - $average = '0'; - $current = '0'; if (0 === bccomp($amount, '0')) { $budgetLimit = null; } + // if today is between start and end, use the diff in days between end and today (days left) + // otherwise, use diff between start and end. + $today = new Carbon; + if ($today->gte($start) && $today->lte($end)) { + $days = $end->diffInDays($today); + } + if ($today->lte($start) || $today->gte($end)) { + $days = $start->diffInDays($end); + } + $days = $days === 0 ? 1 : $days; + // calculate left in budget: - $spent = $repository->spentInPeriod(new Collection([$budget]), new Collection, $start, $end); - $currency = app('amount')->getDefaultCurrency(); - $left = app('amount')->formatAnything($currency, bcadd($amount, $spent), true); + $spent = $repository->spentInPeriod(new Collection([$budget]), new Collection, $start, $end); + $currency = app('amount')->getDefaultCurrency(); + $left = app('amount')->formatAnything($currency, bcadd($amount, $spent), true); + $leftPerDay = 'none'; + + // is user has money left, calculate. + if (1 === bccomp(bcadd($amount, $spent), '0')) { + $leftPerDay = app('amount')->formatAnything($currency, bcdiv(bcadd($amount, $spent), (string)$days), true); + } // over or under budgeting, compared to previous budgets? @@ -112,8 +127,8 @@ class BudgetController extends Controller $warnText = (string)trans( 'firefly.over_budget_warn', [ - 'amount' => app('amount')->formatAnything($currency, $average, false), - 'over_amount' => app('amount')->formatAnything($currency, $current, false), + 'amount' => app('amount')->formatAnything($currency, $average, false), + 'over_amount' => app('amount')->formatAnything($currency, $current, false), ] ); } @@ -122,14 +137,15 @@ class BudgetController extends Controller return response()->json( [ - 'left' => $left, - 'name' => $budget->name, - 'limit' => $budgetLimit ? $budgetLimit->id : 0, - 'amount' => $amount, - 'current' => $current, - 'average' => $average, - 'large_diff' => $largeDiff, - 'warn_text' => $warnText, + 'left' => $left, + 'name' => $budget->name, + 'limit' => $budgetLimit ? $budgetLimit->id : 0, + 'amount' => $amount, + 'current' => $current, + 'average' => $average, + 'large_diff' => $largeDiff, + 'left_per_day' => $leftPerDay, + 'warn_text' => $warnText, ] ); @@ -219,6 +235,17 @@ class BudgetController extends Controller $page = 0 === (int)$request->get('page') ? 1 : (int)$request->get('page'); $pageSize = (int)Preferences::get('listPageSize', 50)->data; + // if today is between start and end, use the diff in days between end and today (days left) + // otherwise, use diff between start and end. + $today = new Carbon; + if ($today->gte($start) && $today->lte($end)) { + $days = $end->diffInDays($today); + } + if ($today->lte($start) || $today->gte($end)) { + $days = $start->diffInDays($end); + } + $days = $days === 0 ? 1 : $days; + // make date if present: if (null !== $moment || '' !== (string)$moment) { try { @@ -283,27 +310,11 @@ class BudgetController extends Controller $prevText = app('navigation')->periodShow($prev, $range); return view( - 'budgets.index', - compact( - 'available', - 'currentMonth', - 'next', - 'nextText', - 'prev', 'allBudgets', - 'prevText', - 'periodStart', - 'periodEnd', - 'page', - 'budgetInformation', - 'inactive', - 'budgets', - 'spent', - 'budgeted', - 'previousLoop', - 'nextLoop', - 'start', - 'end' - ) + 'budgets.index', compact( + 'available', 'currentMonth', 'next', 'nextText', 'prev', 'allBudgets', 'prevText', 'periodStart', 'periodEnd', 'days', 'page', + 'budgetInformation', + 'inactive', 'budgets', 'spent', 'budgeted', 'previousLoop', 'nextLoop', 'start', 'end' + ) ); } diff --git a/public/js/ff/budgets/index.js b/public/js/ff/budgets/index.js index 736ba8ae67..8651b947ae 100644 --- a/public/js/ff/budgets/index.js +++ b/public/js/ff/budgets/index.js @@ -129,7 +129,13 @@ function updateBudgetedAmounts(e) { budgeted = budgeted + difference; // fill in "left" value: - leftCell.html(data.left); + + + if (data.left_per_day !== 'none') { + leftCell.html(data.left + '(' + data.left_per_day + ')'); + } else { + leftCell.html(data.left); + } // update "budgeted" input: target.val(data.amount); diff --git a/resources/views/budgets/index.twig b/resources/views/budgets/index.twig index 24212b52de..71dad53b7e 100644 --- a/resources/views/budgets/index.twig +++ b/resources/views/budgets/index.twig @@ -146,8 +146,8 @@
    - - + + @@ -188,10 +188,14 @@ {% endfor %} From c2e8a673308528ff5abd4e6d92089402ca6544bb Mon Sep 17 00:00:00 2001 From: James Cole Date: Sun, 22 Apr 2018 11:29:20 +0200 Subject: [PATCH 076/117] Code for #1367 --- app/Http/Controllers/RuleController.php | 4 +++- app/Support/ExpandedForm.php | 16 +++++++++++----- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/app/Http/Controllers/RuleController.php b/app/Http/Controllers/RuleController.php index 99d71a5e02..b6d08b6886 100644 --- a/app/Http/Controllers/RuleController.php +++ b/app/Http/Controllers/RuleController.php @@ -83,7 +83,9 @@ class RuleController extends Controller $this->createDefaultRule(); $bill = null; $billId = (int)$request->get('fromBill'); - $preFilled = []; + $preFilled = [ + 'strict' => true, + ]; $groups = ExpandedForm::makeSelectList($ruleGroupRepository->get()); $oldTriggers = []; $oldActions = []; diff --git a/app/Support/ExpandedForm.php b/app/Support/ExpandedForm.php index 0662f811bc..08fbd72e8c 100644 --- a/app/Support/ExpandedForm.php +++ b/app/Support/ExpandedForm.php @@ -169,11 +169,17 @@ class ExpandedForm */ public function checkbox(string $name, $value = 1, $checked = null, $options = []): string { - $options['checked'] = true === $checked ? true : null; - $label = $this->label($name, $options); - $options = $this->expandOptionArray($name, $label, $options); - $classes = $this->getHolderClasses($name); - $value = $this->fillFieldValue($name, $value); + $options['checked'] = true === $checked ? true : false; + + if (Session::has('preFilled')) { + $preFilled = session('preFilled'); + $options['checked'] = $preFilled[$name] ?? $options['checked']; + } + + $label = $this->label($name, $options); + $options = $this->expandOptionArray($name, $label, $options); + $classes = $this->getHolderClasses($name); + $value = $this->fillFieldValue($name, $value); unset($options['placeholder'], $options['autocomplete'], $options['class']); From ea484a77875c2d64af3949eaee4a534331c3f366 Mon Sep 17 00:00:00 2001 From: James Cole Date: Sun, 22 Apr 2018 12:01:18 +0200 Subject: [PATCH 077/117] Small bill related fixes. --- app/Http/Controllers/Transaction/SingleController.php | 9 ++++++++- app/Http/Controllers/Transaction/SplitController.php | 4 ++++ resources/views/bills/show.twig | 10 ---------- 3 files changed, 12 insertions(+), 11 deletions(-) diff --git a/app/Http/Controllers/Transaction/SingleController.php b/app/Http/Controllers/Transaction/SingleController.php index c76a87dc9c..e9d9d95ad6 100644 --- a/app/Http/Controllers/Transaction/SingleController.php +++ b/app/Http/Controllers/Transaction/SingleController.php @@ -398,7 +398,14 @@ class SingleController extends Controller } // @codeCoverageIgnoreEnd - $data = $request->getJournalData(); + $data = $request->getJournalData(); + + // keep current bill: + $data['bill_id'] = $journal->bill_id; + var_dump($data); + + exit; + $journal = $repository->update($journal, $data); /** @var array $files */ $files = $request->hasFile('attachments') ? $request->file('attachments') : null; diff --git a/app/Http/Controllers/Transaction/SplitController.php b/app/Http/Controllers/Transaction/SplitController.php index 6910c9ec72..94443d2433 100644 --- a/app/Http/Controllers/Transaction/SplitController.php +++ b/app/Http/Controllers/Transaction/SplitController.php @@ -144,6 +144,10 @@ class SplitController extends Controller return $this->redirectToAccount($journal); // @codeCoverageIgnore } $data = $request->getAll(); + + // keep current bill: + $data['bill_id'] = $journal->bill_id; + $journal = $this->repository->update($journal, $data); /** @var array $files */ diff --git a/resources/views/bills/show.twig b/resources/views/bills/show.twig index 14cb9384a0..7f61c3d402 100644 --- a/resources/views/bills/show.twig +++ b/resources/views/bills/show.twig @@ -42,16 +42,6 @@ {% endif %} - - - - {% for journal in journals %} - {% if journal.transaction_count == 2 %} - - - - + + + {# AMOUNT #} + - - - - {# category #} - - {# budget #} - - - {% endif %} + {% endif %} + + + + + {# category #} + + {# budget #} + + {% endfor %}
    {{ transaction.date.formatLocalized(monthAndDayFormat) }} {% if transaction.transactionJournal.hasMeta('book_date') %} - {{ getMetaDate(transaction.transactionJournal, 'book_date').formatLocalized(monthAndDayFormat) }} + {{ journalGetMetaDate(transaction.transactionJournal, 'book_date').formatLocalized(monthAndDayFormat) }} {% endif %} {% if transaction.transactionJournal.hasMeta('process_date') %} - {{ getMetaDate(transaction.transactionJournal, 'process_date').formatLocalized(monthAndDayFormat) }} + {{ journalGetMetaDate(transaction.transactionJournal, 'process_date').formatLocalized(monthAndDayFormat) }} {% endif %} {% if transaction.transactionJournal.hasMeta('interest_date') %} - {{ getMetaDate(transaction.transactionJournal, 'interest_date').formatLocalized(monthAndDayFormat) }} + {{ journalGetMetaDate(transaction.transactionJournal, 'interest_date').formatLocalized(monthAndDayFormat) }} {% endif %} {% if transaction.transactionJournal.hasMeta('due_date') %} - {{ getMetaDate(transaction.transactionJournal, 'due_date').formatLocalized(monthAndDayFormat) }} + {{ journalGetMetaDate(transaction.transactionJournal, 'due_date').formatLocalized(monthAndDayFormat) }} {% endif %} {% if transaction.transactionJournal.hasMeta('payment_date') %} - {{ getMetaDate(transaction.transactionJournal, 'payment_date').formatLocalized(monthAndDayFormat) }} + {{ journalGetMetaDate(transaction.transactionJournal, 'payment_date').formatLocalized(monthAndDayFormat) }} {% endif %} {% if transaction.transactionJournal.hasMeta('invoice_date') %} - {{ getMetaDate(transaction.transactionJournal, 'invoice_date').formatLocalized(monthAndDayFormat) }} + {{ journalGetMetaDate(transaction.transactionJournal, 'invoice_date').formatLocalized(monthAndDayFormat) }} {% endif %} {{ formatAmountByAccount(account, account.endBalance) }} diff --git a/resources/views/reports/index.twig b/resources/views/reports/index.twig index fac9b2b1b8..ea2ef75733 100644 --- a/resources/views/reports/index.twig +++ b/resources/views/reports/index.twig @@ -41,8 +41,8 @@ {% for account in accounts %} {% endfor %} From 7cc8539298ce52876e619ff50eee294266048bc3 Mon Sep 17 00:00:00 2001 From: James Cole Date: Thu, 19 Apr 2018 18:27:39 +0200 Subject: [PATCH 054/117] Fix for #1349, thanks to @NyKoF --- app/Import/Storage/ImportStorage.php | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/app/Import/Storage/ImportStorage.php b/app/Import/Storage/ImportStorage.php index 0e75e0fce1..e53c707ea2 100644 --- a/app/Import/Storage/ImportStorage.php +++ b/app/Import/Storage/ImportStorage.php @@ -210,9 +210,14 @@ class ImportStorage $source = $assetAccount; $destination = $opposingAccount; + // switch account arounds when the transaction type is a deposit. if ($transactionType === TransactionType::DEPOSIT) { - $destination = $assetAccount; - $source = $opposingAccount; + [$destination, $source] = [$source, $destination]; + } + // switch accounts around when the amount is negative and it's a transfer. + // credits to @NyKoF + if($transactionType === TransactionType::TRANSFER && -1 === bccomp($amount, '0')) { + [$destination, $source] = [$source, $destination]; } Log::debug( sprintf('Will make #%s (%s) the source and #%s (%s) the destination.', $source->id, $source->name, $destination->id, $destination->name) @@ -248,7 +253,7 @@ class ImportStorage [ 'description' => null, 'amount' => $amount, - 'currency_id' => (int)$currencyId, + 'currency_id' => $currencyId, 'currency_code' => null, 'foreign_amount' => $foreignAmount, 'foreign_currency_id' => $foreignCurrencyId, From c6d3a5bedc6480a8d761a1bb5d804461dbfa0569 Mon Sep 17 00:00:00 2001 From: James Cole Date: Thu, 19 Apr 2018 20:03:02 +0200 Subject: [PATCH 055/117] Code for #1351 --- .../Controllers/Import/IndexController.php | 40 +++++++++++++++++++ resources/views/import/index.twig | 29 ++++++++++++++ routes/web.php | 1 + 3 files changed, 70 insertions(+) diff --git a/app/Http/Controllers/Import/IndexController.php b/app/Http/Controllers/Import/IndexController.php index 6216cc0045..3b3c21e48f 100644 --- a/app/Http/Controllers/Import/IndexController.php +++ b/app/Http/Controllers/Import/IndexController.php @@ -28,8 +28,10 @@ use FireflyIII\Http\Middleware\IsDemoUser; use FireflyIII\Import\Routine\RoutineInterface; use FireflyIII\Models\ImportJob; use FireflyIII\Repositories\ImportJob\ImportJobRepositoryInterface; +use Illuminate\Http\Request; use Illuminate\Http\Response as LaravelResponse; use Log; +use Preferences; use View; @@ -132,6 +134,44 @@ class IndexController extends Controller return view('import.index', compact('subTitle', 'subTitleIcon', 'routines')); } + /** + * @param Request $request + * @param string $bank + * + * @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector + */ + public function reset(Request $request, string $bank) + { + if ($bank === 'bunq') { + // remove bunq related preferences. + Preferences::delete('bunq_api_key'); + Preferences::delete('bunq_server_public_key'); + Preferences::delete('bunq_private_key'); + Preferences::delete('bunq_public_key'); + Preferences::delete('bunq_installation_token'); + Preferences::delete('bunq_installation_id'); + Preferences::delete('bunq_device_server_id'); + Preferences::delete('external_ip'); + + } + + if ($bank === 'spectre') { + // remove spectre related preferences: + Preferences::delete('spectre_client_id'); + Preferences::delete('spectre_app_secret'); + Preferences::delete('spectre_service_secret'); + Preferences::delete('spectre_private_key'); + Preferences::delete('spectre_public_key'); + Preferences::delete('spectre_customer'); + } + + Preferences::mark(); + $request->session()->flash('info', (string)trans('firefly.settings_reset_for_' . $bank)); + + return redirect(route('import.index')); + + } + /** * @param ImportJob $job * diff --git a/resources/views/import/index.twig b/resources/views/import/index.twig index c9b5682c9a..02fa364a94 100644 --- a/resources/views/import/index.twig +++ b/resources/views/import/index.twig @@ -64,6 +64,35 @@ +
    +
    +
    +
    +

    {{ 'reset_import_settings_title'|_ }}

    +
    +
    +

    + {{ 'reset_import_settings_text'|_ }} +

    + +
    +
    +
    {% endblock %} {% block scripts %} diff --git a/routes/web.php b/routes/web.php index 897e64e490..696cc57bf9 100755 --- a/routes/web.php +++ b/routes/web.php @@ -446,6 +446,7 @@ Route::group( // import method prerequisites: Route::get('prerequisites/{bank}', ['uses' => 'Import\PrerequisitesController@index', 'as' => 'prerequisites']); Route::post('prerequisites/{bank}', ['uses' => 'Import\PrerequisitesController@post', 'as' => 'prerequisites.post']); + Route::get('reset/{bank}', ['uses' => 'Import\IndexController@reset', 'as' => 'reset']); // create the job: Route::get('create/{bank}', ['uses' => 'Import\IndexController@create', 'as' => 'create-job']); From dcc45631daabcdc6af25484eb09ac7a5a2bbbbd0 Mon Sep 17 00:00:00 2001 From: James Cole Date: Thu, 19 Apr 2018 20:04:04 +0200 Subject: [PATCH 056/117] New language strings [skip ci] --- resources/lang/en_US/firefly.php | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/resources/lang/en_US/firefly.php b/resources/lang/en_US/firefly.php index 0f8eb06692..7e83a1ac11 100644 --- a/resources/lang/en_US/firefly.php +++ b/resources/lang/en_US/firefly.php @@ -1022,6 +1022,7 @@ return [ 'events' => 'Events', 'target_amount' => 'Target amount', 'start_date' => 'Start date', + 'no_start_date' => 'No start date', 'target_date' => 'Target date', 'no_target_date' => 'No target date', 'table' => 'Table', @@ -1159,6 +1160,13 @@ return [ 'import_index_sub_title' => 'Index', 'import_general_index_intro' => 'Welcome to Firefly III\'s import routine. There are a few ways of importing data into Firefly III, displayed here as buttons.', 'upload_error' => 'The file you have uploaded could not be processed. Possibly it is of an invalid file type or encoding. The log files will have more information.', + 'reset_import_settings_title' => 'Reset import configuration', + 'reset_import_settings_text' => 'You can use these links to reset your import settings for specific providers. This is useful when bad settings stop you from importing data.', + 'reset_settings_bunq' => 'Remove bunq API key, local external IP address and bunq related RSA keys.', + 'reset_settings_spectre' => 'Remove Spectre client ID, service secret and app secret. This will also remove your Spectre keypair. Remember to update the new one.', + 'settings_reset_for_bunq' => 'Bunq settings reset.', + 'settings_reset_for_spectre' => 'Spectre settings reset.', + // sandstorm.io errors and messages: 'sandstorm_not_available' => 'This function is not available when you are using Firefly III within a Sandstorm.io environment.', From f8718e0b7b034f066ea6ef5f1487a679291b7fda Mon Sep 17 00:00:00 2001 From: James Cole Date: Sat, 21 Apr 2018 20:26:41 +0200 Subject: [PATCH 057/117] Fix some issues with verify database code. --- app/Console/Commands/UpgradeDatabase.php | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/app/Console/Commands/UpgradeDatabase.php b/app/Console/Commands/UpgradeDatabase.php index 6d4241aa39..7115bb3819 100644 --- a/app/Console/Commands/UpgradeDatabase.php +++ b/app/Console/Commands/UpgradeDatabase.php @@ -551,7 +551,13 @@ class UpgradeDatabase extends Command { /** @var CurrencyRepositoryInterface $repository */ $repository = app(CurrencyRepositoryInterface::class); - $currency = $repository->find((int)$transaction->account->getMeta('currency_id')); + $currency = $repository->findNull((int)$transaction->account->getMeta('currency_id')); + + if (null === $currency) { + Log::error(sprintf('Account #%d ("%s") must have currency preference but has none.', $transaction->account->id, $transaction->account->name)); + + return; + } // has no currency ID? Must have, so fill in using account preference: if (null === $transaction->transaction_currency_id) { @@ -581,9 +587,9 @@ class UpgradeDatabase extends Command $journal = $transaction->transactionJournal; /** @var Transaction $opposing */ $opposing = $journal->transactions()->where('amount', '>', 0)->where('identifier', $transaction->identifier)->first(); - $opposingCurrency = $repository->find((int)$opposing->account->getMeta('currency_id')); + $opposingCurrency = $repository->findNull((int)$opposing->account->getMeta('currency_id')); - if (null === $opposingCurrency->id) { + if (null === $opposingCurrency) { Log::error(sprintf('Account #%d ("%s") must have currency preference but has none.', $opposing->account->id, $opposing->account->name)); return; @@ -599,7 +605,12 @@ class UpgradeDatabase extends Command $opposing->transaction_currency_id = $currency->id; $transaction->save(); $opposing->save(); - Log::debug(sprintf('Cleaned up transaction #%d and #%d', $transaction->id, $opposing->id)); + Log::debug(sprintf('Currency for account "%s" is %s, and currency for account "%s" is also + %s, so %s #%d (#%d and #%d) has been verified to be to %s exclusively.', + $opposing->account->name, $opposingCurrency->code, + $transaction->account->name, $transaction->transactionCurrency->code, + $journal->transactionType->type, $journal->id, + $transaction->id, $opposing->id, $currency->code)); return; } From 45cd19d1e3860c78424211f1f8e412208ed06aed Mon Sep 17 00:00:00 2001 From: James Cole Date: Sat, 21 Apr 2018 20:27:35 +0200 Subject: [PATCH 058/117] Fix #1363 --- .../Account/ReconcileController.php | 7 ++--- .../accounts/reconcile/transactions.twig | 29 ++++++++++++------- 2 files changed, 21 insertions(+), 15 deletions(-) diff --git a/app/Http/Controllers/Account/ReconcileController.php b/app/Http/Controllers/Account/ReconcileController.php index a844c703f5..a78eda07b5 100644 --- a/app/Http/Controllers/Account/ReconcileController.php +++ b/app/Http/Controllers/Account/ReconcileController.php @@ -190,7 +190,7 @@ class ReconcileController extends Controller } $currencyId = (int)$this->accountRepos->getMetaValue($account, 'currency_id'); $currency = $this->currencyRepos->findNull($currencyId); - if (0 === $currencyId) { + if (null === $currency) { $currency = app('amount')->getDefaultCurrency(); // @codeCoverageIgnore } @@ -217,7 +217,6 @@ class ReconcileController extends Controller $transactionsUri = route('accounts.reconcile.transactions', [$account->id, '%start%', '%end%']); $overviewUri = route('accounts.reconcile.overview', [$account->id, '%start%', '%end%']); $indexUri = route('accounts.reconcile', [$account->id, '%start%', '%end%']); - return view( 'accounts.reconcile.index', compact( 'account', 'currency', 'subTitleIcon', 'start', 'end', 'subTitle', 'startBalance', 'endBalance', 'transactionsUri', @@ -350,7 +349,7 @@ class ReconcileController extends Controller $currencyId = (int)$this->accountRepos->getMetaValue($account, 'currency_id'); $currency = $this->currencyRepos->findNull($currencyId); - if (0 === $currencyId) { + if (0 === $currency) { $currency = app('amount')->getDefaultCurrency(); // @codeCoverageIgnore } @@ -369,7 +368,7 @@ class ReconcileController extends Controller $collector->setAccounts(new Collection([$account])) ->setRange($selectionStart, $selectionEnd)->withBudgetInformation()->withOpposingAccount()->withCategoryInformation(); $transactions = $collector->getJournals(); - $html = view('accounts.reconcile.transactions', compact('account', 'transactions', 'start', 'end', 'selectionStart', 'selectionEnd'))->render(); + $html = view('accounts.reconcile.transactions', compact('account', 'transactions','currency', 'start', 'end', 'selectionStart', 'selectionEnd'))->render(); return response()->json(['html' => $html, 'startBalance' => $startBalance, 'endBalance' => $endBalance]); } diff --git a/resources/views/accounts/reconcile/transactions.twig b/resources/views/accounts/reconcile/transactions.twig index 446c0b436f..dc315196a6 100644 --- a/resources/views/accounts/reconcile/transactions.twig +++ b/resources/views/accounts/reconcile/transactions.twig @@ -25,9 +25,9 @@  
    - - {{ trans('firefly.start_of_reconcile_period', {period: start.formatLocalized(monthAndDayFormat) }) }} - + + {{ trans('firefly.start_of_reconcile_period', {period: start.formatLocalized(monthAndDayFormat) }) }} +   @@ -43,9 +43,9 @@   - - {{ trans('firefly.end_of_reconcile_period', {period: end.formatLocalized(monthAndDayFormat) }) }} - + + {{ trans('firefly.end_of_reconcile_period', {period: end.formatLocalized(monthAndDayFormat) }) }} +   @@ -82,14 +82,21 @@ {{ transaction|transactionAmount }} + {% if currency.id == transaction.transaction_currency_id %} + {% set transactionAmount = transaction.transaction_amount %} + {% else %} + {% set transactionAmount = transaction.transaction_foreign_amount %} + {% endif %} + + {% if transaction.reconciled %} {{ transaction|transactionReconciled }} + class="cleared" data-id="{{ transaction.id }}" value="{{ transactionAmount }}"> {% else %} + value="{{ transactionAmount }}" data-id="{{ transaction.id }}" disabled class="reconcile_checkbox"> {% endif %} - - {{ trans('firefly.start_of_reconcile_period', {period: start.formatLocalized(monthAndDayFormat) }) }} - + + {{ trans('firefly.start_of_reconcile_period', {period: start.formatLocalized(monthAndDayFormat) }) }} +   From 479648e7c181998dbde179e69f2fff7f16adce21 Mon Sep 17 00:00:00 2001 From: James Cole Date: Sat, 21 Apr 2018 20:28:30 +0200 Subject: [PATCH 059/117] Fix #1352 --- app/Services/Bunq/Object/UserCompany.php | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/app/Services/Bunq/Object/UserCompany.php b/app/Services/Bunq/Object/UserCompany.php index 1ed89f6faa..13508afdb5 100644 --- a/app/Services/Bunq/Object/UserCompany.php +++ b/app/Services/Bunq/Object/UserCompany.php @@ -98,6 +98,13 @@ class UserCompany extends BunqObject */ public function __construct(array $data) { + if (\count($data) === 0 || (isset($data['id']) && (int)$data['id'] === 0)) { + $this->id = 0; + $this->created = new Carbon; + $this->updated = new Carbon; + + return; + } $this->id = (int)$data['id']; $this->created = Carbon::createFromFormat('Y-m-d H:i:s.u', $data['created']); $this->updated = Carbon::createFromFormat('Y-m-d H:i:s.u', $data['updated']); From 8dd765ee89067cd7edd5832510f62b913c937676 Mon Sep 17 00:00:00 2001 From: James Cole Date: Sat, 21 Apr 2018 20:28:41 +0200 Subject: [PATCH 060/117] Remove deprecated method. --- app/Support/Steam.php | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/app/Support/Steam.php b/app/Support/Steam.php index d6d998b9ff..e3ab8d1d72 100644 --- a/app/Support/Steam.php +++ b/app/Support/Steam.php @@ -27,6 +27,7 @@ use Crypt; use DB; use FireflyIII\Models\Account; use FireflyIII\Models\Transaction; +use FireflyIII\Repositories\Account\AccountRepositoryInterface; use Illuminate\Contracts\Encryption\DecryptException; use Illuminate\Support\Collection; @@ -51,7 +52,11 @@ class Steam if ($cache->has()) { return $cache->get(); // @codeCoverageIgnore } - $currencyId = (int)$account->getMeta('currency_id'); + // + /** @var AccountRepositoryInterface $repository */ + $repository = app(AccountRepositoryInterface::class); + $currencyId = (int)$repository->getMetaValue($account, 'currency_id'); + // use system default currency: if (0 === $currencyId) { $currency = app('amount')->getDefaultCurrencyByUser($account->user); @@ -71,6 +76,7 @@ class Steam ->where('transactions.foreign_currency_id', $currencyId) ->where('transactions.transaction_currency_id', '!=', $currencyId) ->sum('transactions.foreign_amount'); + $balance = bcadd($nativeBalance, $foreignBalance); $virtual = null === $account->virtual_balance ? '0' : (string)$account->virtual_balance; $balance = bcadd($balance, $virtual); From 1129001bc678c8b151c41edff7b1e2e51bbc3d2b Mon Sep 17 00:00:00 2001 From: James Cole Date: Sat, 21 Apr 2018 20:29:44 +0200 Subject: [PATCH 061/117] Possible solution for #1353 --- app/Support/Preferences.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/Support/Preferences.php b/app/Support/Preferences.php index 932b534c6e..38825077c6 100644 --- a/app/Support/Preferences.php +++ b/app/Support/Preferences.php @@ -139,10 +139,10 @@ class Preferences } catch (Exception $e) { Log::debug(sprintf('Could not delete preference #%d', $preference->id)); } - $preference = false; + $preference = null; } - if ($preference) { + if (null !== $preference) { Cache::forever($fullName, $preference); return $preference; From 77fa2bcc3961968a8ff3c10a26a566d8fd6aa4c3 Mon Sep 17 00:00:00 2001 From: James Cole Date: Sat, 21 Apr 2018 20:30:07 +0200 Subject: [PATCH 062/117] Call test at wrong position [skip ci] --- test.sh | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/test.sh b/test.sh index fd76d7e758..1530cf6f4b 100755 --- a/test.sh +++ b/test.sh @@ -135,10 +135,12 @@ else else echo "Must run PHPUnit with coverage" fi + + echo "./vendor/bin/phpunit $verbalflag --configuration $configfile $featuretestclass $unittestclass $apitestclass $testsuite" + ./vendor/bin/phpunit $verbalflag --configuration $configfile $featuretestclass $unittestclass $apitestclass $testsuite + fi -echo "./vendor/bin/phpunit $verbalflag --configuration $configfile $featuretestclass $unittestclass $apitestclass $testsuite" -./vendor/bin/phpunit $verbalflag --configuration $configfile $featuretestclass $unittestclass $apitestclass $testsuite # restore current config: if [ -f $BACKUPENV ]; then From 769b4819b2ddf8c7e9408f1538c18d86ebe8e843 Mon Sep 17 00:00:00 2001 From: James Cole Date: Sat, 21 Apr 2018 20:30:36 +0200 Subject: [PATCH 063/117] Add timezone to Docker file. --- docker-compose.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/docker-compose.yml b/docker-compose.yml index 3363a4094d..b11f7a38e1 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -11,6 +11,7 @@ services: - FF_DB_PASSWORD=firefly_db_secret - FF_APP_KEY=S0m3R@nd0mStr1ngOf32Ch@rsEx@ctly - FF_APP_ENV=local + - TZ=Europe/Amsterdam image: jc5x/firefly-iii links: - firefly_iii_db From 592901b143f1e4b755d83e6b3eab5448afc49868 Mon Sep 17 00:00:00 2001 From: James Cole Date: Sat, 21 Apr 2018 20:36:42 +0200 Subject: [PATCH 064/117] Code for @1346 --- .env.docker | 2 +- app/Http/Middleware/Range.php | 15 +++++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/.env.docker b/.env.docker index 05f2035445..28b1973148 100644 --- a/.env.docker +++ b/.env.docker @@ -22,7 +22,7 @@ LOG_CHANNEL=${LOG_CHANNEL} # Database credentials. Make sure the database exists. I recommend a dedicated user for Firefly III # If you use SQLite, set connection to `sqlite` and remove the database, username and password settings. -DB_CONNECTION=mysql +DB_CONNECTION=${FF_DB_CONNECTION} DB_HOST=${FF_DB_HOST} DB_PORT=${FF_DB_PORT} DB_DATABASE=${FF_DB_NAME} diff --git a/app/Http/Middleware/Range.php b/app/Http/Middleware/Range.php index f7c935ac75..2df70e8f2b 100644 --- a/app/Http/Middleware/Range.php +++ b/app/Http/Middleware/Range.php @@ -55,6 +55,9 @@ class Range // set more view variables: $this->configureList(); + + // flash a big fat warning when users use SQLite in Docker + $this->loseItAll($request); } return $next($request); @@ -99,6 +102,18 @@ class Range View::share('defaultCurrency', $defaultCurrency); } + /** + * @param Request $request + */ + private function loseItAll(Request $request) + { + if (getenv('DB_CONNECTION') === 'sqlite' && getenv('IS_DOCKER') === true) { + $request->session()->flash( + 'error', 'You seem to be using SQLite in a Docker container. Don\'t do this. If the container restarts all your data will be gone.' + ); + } + } + /** * */ From 352171e33978c994844819fb4697d70091dae5d8 Mon Sep 17 00:00:00 2001 From: James Cole Date: Sat, 21 Apr 2018 20:48:18 +0200 Subject: [PATCH 065/117] New language strings [skip ci] --- resources/lang/de_DE/firefly.php | 39 ++++- resources/lang/de_DE/form.php | 6 +- resources/lang/de_DE/import.php | 1 + resources/lang/de_DE/intro.php | 7 +- resources/lang/de_DE/list.php | 1 + resources/lang/es_ES/firefly.php | 39 ++++- resources/lang/es_ES/form.php | 4 + resources/lang/es_ES/import.php | 1 + resources/lang/es_ES/intro.php | 7 +- resources/lang/es_ES/list.php | 1 + resources/lang/fr_FR/firefly.php | 47 ++++- resources/lang/fr_FR/form.php | 4 + resources/lang/fr_FR/import.php | 1 + resources/lang/fr_FR/intro.php | 7 +- resources/lang/fr_FR/list.php | 3 +- resources/lang/id_ID/firefly.php | 39 ++++- resources/lang/id_ID/form.php | 4 + resources/lang/id_ID/import.php | 1 + resources/lang/id_ID/intro.php | 7 +- resources/lang/id_ID/list.php | 1 + resources/lang/it_IT/breadcrumbs.php | 10 +- resources/lang/it_IT/config.php | 12 +- resources/lang/it_IT/demo.php | 4 +- resources/lang/it_IT/firefly.php | 245 +++++++++++++++------------ resources/lang/it_IT/form.php | 18 +- resources/lang/it_IT/import.php | 27 +-- resources/lang/it_IT/intro.php | 51 +++--- resources/lang/it_IT/list.php | 9 +- resources/lang/it_IT/validation.php | 2 +- resources/lang/nl_NL/firefly.php | 39 ++++- resources/lang/nl_NL/form.php | 4 + resources/lang/nl_NL/import.php | 1 + resources/lang/nl_NL/intro.php | 5 +- resources/lang/nl_NL/list.php | 1 + resources/lang/pl_PL/firefly.php | 39 ++++- resources/lang/pl_PL/form.php | 4 + resources/lang/pl_PL/import.php | 1 + resources/lang/pl_PL/intro.php | 5 +- resources/lang/pl_PL/list.php | 1 + resources/lang/pt_BR/firefly.php | 39 ++++- resources/lang/pt_BR/form.php | 4 + resources/lang/pt_BR/import.php | 1 + resources/lang/pt_BR/intro.php | 7 +- resources/lang/pt_BR/list.php | 1 + resources/lang/ru_RU/firefly.php | 39 ++++- resources/lang/ru_RU/form.php | 4 + resources/lang/ru_RU/import.php | 1 + resources/lang/ru_RU/intro.php | 7 +- resources/lang/ru_RU/list.php | 1 + resources/lang/tr_TR/firefly.php | 39 ++++- resources/lang/tr_TR/form.php | 4 + resources/lang/tr_TR/import.php | 1 + resources/lang/tr_TR/intro.php | 7 +- resources/lang/tr_TR/list.php | 1 + 54 files changed, 627 insertions(+), 227 deletions(-) diff --git a/resources/lang/de_DE/firefly.php b/resources/lang/de_DE/firefly.php index b3b20f1807..c161110767 100644 --- a/resources/lang/de_DE/firefly.php +++ b/resources/lang/de_DE/firefly.php @@ -267,7 +267,10 @@ return [ 'move_rule_group_down' => 'Regelgruppe nach unten verschieben', 'save_rules_by_moving' => 'Speichern Sie diese Regel(n), indem Sie sie in eine andere Gruppe verschieben:', 'make_new_rule' => 'Erstelle neue Regel in der Regelgruppe ":title"', + 'rule_is_strict' => 'strikte Regel', + 'rule_is_not_strict' => 'nicht-strenge Regel', 'rule_help_stop_processing' => 'Wenn Sie dieses Kontrollkästchen aktivieren, werden spätere Regeln in dieser Gruppe nicht ausgeführt.', + 'rule_help_strict' => 'In strengen Regeln müssen ALLE Auslöser ausgelöst werden, damit die Aktion(en) ausgeführt werden können. In nicht strengen Regeln genügt JEDER Auslöser, um die Aktion(en) auszuführen.', 'rule_help_active' => 'Inaktive Regeln werden nie ausgeführt.', 'stored_new_rule' => 'Speichere neue Regel mit Titel ":title"', 'deleted_rule' => 'Lösche Regel mit Titel ":title"', @@ -345,6 +348,8 @@ return [ 'rule_trigger_budget_is' => 'Kostenrahmen ist „:trigger_value”', 'rule_trigger_tag_is_choice' => '(Ein) Schlagwort ist …', 'rule_trigger_tag_is' => 'Ein Schlagwort ist ":trigger_value"', + 'rule_trigger_currency_is_choice' => 'Buchungswährung ist …', + 'rule_trigger_currency_is' => 'Buchungswährung ist „:trigger_value”', 'rule_trigger_has_attachments_choice' => 'Hat zumindest so viele Anhänge', 'rule_trigger_has_attachments' => 'Hat zumindest :trigger_value Anhäng(e)', 'rule_trigger_store_journal' => 'Wenn eine Transaktion erstellt wird', @@ -404,10 +409,20 @@ return [ 'rule_action_clear_notes_choice' => 'Alle Notizen entfernen', 'rule_action_clear_notes' => 'Alle Notizen entfernen', 'rule_action_set_notes_choice' => 'Notizen festlegen auf …', + 'rule_action_link_to_bill_choice' => 'Mit einer Rechnung verknüpfen …', + 'rule_action_link_to_bill' => 'Mit Rechnung „:action_value” verknüpfen …', 'rule_action_set_notes' => 'Notizen auf „:action_value” festlegen', 'rules_have_read_warning' => 'Haben Sie die Warnung gelesen?', 'apply_rule_warning' => 'Zur Beachtung: Das Ausführen einer Regel (Gruppe) für eine große Auswahl von Buchungen kann sehr lange dauern, und es kann zu einer Zeitüberschreitung kommen. Wenn dies der Fall ist, wird die Regel (-Gruppe) nur auf eine unbekannte Teilmenge Ihrer Buchungen angewendet. Dies könnte Ihre Finanzverwaltung komplett zerstören. Bitte seien Sie vorsichtig.', + 'rulegroup_for_bills_title' => 'Gruppenregel für Rechnungen', + 'rulegroup_for_bills_description' => 'Eine spezielle Gruppenregel für alle Regeln, die Rechnungen betreffen.', + 'rule_for_bill_title' => 'Automatisch erstellte Regel für die Rechnung „:name”', + 'rule_for_bill_description' => 'Diese Regel wurde automatisch erstellt, um zu versuchen, die Rechnung „:name” abzugleichen.', + 'create_rule_for_bill' => 'Neue Regel für Rechnung „:name” erstellen', + 'create_rule_for_bill_txt' => 'Sie haben gerade eine neue Rechnung namens „:name” erstellt, herzlichen Glückwunsch! Firefly III kann automatisch neue Abbuchungen dieser Rechnung zuordnen. Zum Beispiel, wenn Sie Ihre Miete bezahlen, wird die Rechnung „Miete” an den Kostenbeitrag gebunden. Auf diese Weise kann Firefly III Ihnen genau zeigen, welche Rechnungen fällig sind und welche nicht. Firefly III hat einige sinnvolle Vorgaben für Sie ausgefüllt. Bitte stellen Sie sicher, dass diese korrekt sind. Wenn diese Werte korrekt sind, verknüpft Firefly III automatisch die korrekte Abbuchung mit der richtigen Rechnung. Bitte überprüfen Sie die Auslöser, um zu sehen, ob sie korrekt sind, und fügen Sie einige hinzu, wenn sie falsch sind.', + 'new_rule_for_bill_title' => 'Regel für Rechnung „:name”', + 'new_rule_for_bill_description' => 'Diese Regel kennzeichnet Buchungen für die Rechnung „:name”.', // tags 'store_new_tag' => 'Neues Schlagwort speichern', @@ -625,8 +640,8 @@ Sollen zusätzlich Ihre Girokonten angezeigt werden?', 'over_budget_warn' => ' Normalerweise veranschlagen Sie ca. :amount pro Tag. Aktuell sind es aber :over_amount pro Tag.', // bills: - 'matching_on' => 'Reagiert auf', - 'between_amounts' => 'zwischen :low und :high.', + 'match_between_amounts' => 'Rechnung passt zu Transaktionen zwischen :low und :high.', + 'bill_related_rules' => 'Regeln im Bezug auf diese Rechnung', 'repeats' => 'Wiederholungen', 'connected_journals' => 'Verknüpfte Buchungen', 'auto_match_on' => 'Automatisch von Firefly III zugeordnet', @@ -636,19 +651,20 @@ Sollen zusätzlich Ihre Girokonten angezeigt werden?', 'deleted_bill' => 'Rechnung „:name” gelöscht', 'edit_bill' => 'Rechnung „:name” bearbeiten', 'more' => 'Weitere', - 'rescan_old' => 'Ältere Buchungen überprüfen', + 'rescan_old' => 'Regeln für alle Buchungen erneut ausführen', 'update_bill' => 'Aktualisieren Sie eine Rechnung', 'updated_bill' => 'Rechnung „:name” aktualisiert', 'store_new_bill' => 'Neue Rechnung speichern', 'stored_new_bill' => 'Neue Rechnung „:name” gespeichert', 'cannot_scan_inactive_bill' => 'Inaktive Rechnungen können nicht gescannt werden.', - 'rescanned_bill' => 'Alles gescannt.', + 'rescanned_bill' => 'Alle neu eingelesen und :total Buchung(en) mit dieser Rechnung verknüpft.', 'average_bill_amount_year' => 'Durchschnittliche Rechnungssumme (:year)', 'average_bill_amount_overall' => 'Durchschnittliche Rechnungssumme (gesamt)', 'bill_is_active' => 'Rechnung ist aktiv', 'bill_expected_between' => 'Erwartet zwischen :start und :end', 'bill_will_automatch' => 'Rechnung wird automatisch mit passenden Buchungen verknüpft', 'skips_over' => 'überschreitet', + 'bill_store_error' => 'Beim Speichern Ihrer neuen Rechnung ist ein unerwarteter Fehler aufgetreten. Bitte überprüfen Sie die Protokolldateien.', // accounts: 'details_for_asset' => 'Informationen zum Bestandskonto „:name”', @@ -785,6 +801,7 @@ Sollen zusätzlich Ihre Girokonten angezeigt werden?', 'opt_group_sharedAsset' => 'Gemeinsame Bestandskonten', 'opt_group_ccAsset' => 'Kreditkarten', 'notes' => 'Notizen', + 'unknown_journal_error' => 'Die Buchung konnte nicht gespeichert werden. Bitte überprüfen Sie die Protokolldateien.', // new user: 'welcome' => 'Willkommen bei Firefly III!', @@ -794,6 +811,10 @@ Sollen zusätzlich Ihre Girokonten angezeigt werden?', 'savings_balance_text' => 'Firefly III erstellt automatisch ein Sparkonto für Sie. Standardmäßig befindet sich kein Geld auf Ihrem Sparkonto, aber wenn Sie Firefly III das Guthaben mitteilen, wird es als solches gespeichert.', 'finish_up_new_user' => 'Das war\'s! Sie können fortfahren, indem Sie Absenden drücken. Sie werden zur Startseite von Firefly III gebracht.', 'stored_new_accounts_new_user' => 'Yay! Ihre neuen Konten wurden gespeichert.', + 'set_preferred_language' => 'Wenn Sie Firefly III in einer anderen Sprache verwenden möchten, geben Sie dies bitte hier an.', + 'language' => 'Sprache', + 'new_savings_account' => ':bank_name-Sparkonto', + 'cash_wallet' => 'Geldbörse', // home page: 'yourAccounts' => 'Deine Konten', @@ -942,6 +963,7 @@ Sollen zusätzlich Ihre Girokonten angezeigt werden?', 'account_role_sharedAsset' => 'Gemeinsames Bestandskonto', 'account_role_savingAsset' => 'Sparkonto', 'account_role_ccAsset' => 'Kreditkarte', + 'account_role_cashWalletAsset' => 'Geldbörse', 'budget_chart_click' => 'Klicken Sie auf einen Namen des Kostenrahmen in der obigen Tabelle, um ein Diagramm anzuzeigen.', 'category_chart_click' => 'Klicken Sie auf einen Kategorienamen in der obigen Tabelle, um ein Diagramm zu sehen.', 'in_out_accounts' => 'Einnahmen und Ausgaben je Kombination', @@ -1001,6 +1023,7 @@ Sollen zusätzlich Ihre Girokonten angezeigt werden?', 'events' => 'Ereignisse', 'target_amount' => 'Zielbetrag', 'start_date' => 'Startdatum', + 'no_start_date' => 'No start date', 'target_date' => 'Zieldatum', 'no_target_date' => 'Kein Zieldatum', 'table' => 'Tabelle', @@ -1137,6 +1160,14 @@ Sollen zusätzlich Ihre Girokonten angezeigt werden?', 'import_index_title' => 'Daten in Firefly III importieren', 'import_index_sub_title' => 'Index', 'import_general_index_intro' => 'Willkommen beim Importassistenten von Firefly III. Es gibt einige Möglichkeiten, Daten in Firefly III zu importieren, die hier als Schaltflächen angezeigt werden.', + 'upload_error' => 'Die hochgeladene Datei konnte nicht verarbeitet werden. Möglicherweise handelt es sich um einen ungültigen Dateityp oder eine ungültige Kodierung. Die Protokolldateien enthalten weitere Informationen.', + 'reset_import_settings_title' => 'Reset import configuration', + 'reset_import_settings_text' => 'You can use these links to reset your import settings for specific providers. This is useful when bad settings stop you from importing data.', + 'reset_settings_bunq' => 'Remove bunq API key, local external IP address and bunq related RSA keys.', + 'reset_settings_spectre' => 'Remove Spectre client ID, service secret and app secret. This will also remove your Spectre keypair. Remember to update the new one.', + 'settings_reset_for_bunq' => 'Bunq settings reset.', + 'settings_reset_for_spectre' => 'Spectre settings reset.', + // sandstorm.io errors and messages: 'sandstorm_not_available' => 'Diese Funktion ist nicht verfügbar, wenn Sie Firefly III in einer Sandstorm.io-Umgebung verwenden.', diff --git a/resources/lang/de_DE/form.php b/resources/lang/de_DE/form.php index 1483646bdf..f64c383047 100644 --- a/resources/lang/de_DE/form.php +++ b/resources/lang/de_DE/form.php @@ -1,5 +1,6 @@ 'Mindestbetrag', 'amount_max' => 'Höchstbetrag', 'match' => 'Reagiert auf', + 'strict' => 'Strenger Modus', 'repeat_freq' => 'Wiederholungen', 'journal_currency_id' => 'Währung', 'currency_id' => 'Währung', + 'transaction_currency_id' => 'Währung', + 'external_ip' => 'Die externe IP-Adresse Ihres Servers', 'attachments' => 'Anhänge', 'journal_amount' => 'Betrag', 'journal_source_account_name' => 'Kreditor (Quelle)', @@ -155,7 +159,7 @@ return [ 'piggyBank_areYouSure' => 'Möchten Sie das Sparschwein „:name” wirklich löschen?', 'journal_areYouSure' => 'Sind Sie sicher, dass Sie die Überweisung mit dem Namen ":description" löschen möchten?', 'mass_journal_are_you_sure' => 'Sind Sie sicher, dass Sie diese Überweisung löschen möchten?', - 'tag_areYouSure' => 'Möchten Sie das Schlagwort „:name” wirklich löschen?', + 'tag_areYouSure' => 'Möchten Sie das Schlagwort „:tag” wirklich löschen?', 'journal_link_areYouSure' => 'Sind Sie sicher, dass Sie die Verknüpfung zwischen :source und :destination löschen möchten?', 'linkType_areYouSure' => 'Möchten Sie den Verknüpfungstyp „:name” („:inward”/„:outward”) wirklich löschen?', 'permDeleteWarning' => 'Das Löschen von Dingen in Firefly III ist dauerhaft und kann nicht rückgängig gemacht werden.', diff --git a/resources/lang/de_DE/import.php b/resources/lang/de_DE/import.php index 73f51d52fd..5a37033820 100644 --- a/resources/lang/de_DE/import.php +++ b/resources/lang/de_DE/import.php @@ -164,6 +164,7 @@ return [ // bunq 'bunq_prerequisites_title' => 'Voraussetzungen für einen Import von bunq', 'bunq_prerequisites_text' => 'Um aus „bunq” importieren zu können, benötigen Sie einen API-Schlüssel. Sie können diesen über die App bekommen. Bitte beachten Sie, dass sich die Importfunktion von „bunq” noch im BETA-Stadium befindet. Es wurde nur gegen die Sandbox-API getestet.', + 'bunq_prerequisites_text_ip' => '„Bunq” benötigt Ihre öffentlich zugängliche IP-Adresse. Firefly III versuchte, diese mithilfe des ipify-Diensts auszufüllen. Stellen Sie sicher, dass diese IP-Adresse korrekt ist, da sonst der Import fehlschlägt.', 'bunq_do_import' => 'Ja, von diesem Konto importieren', 'bunq_accounts_title' => 'Bunq-Konten', 'bunq_accounts_text' => 'Dies sind jene Konten, die mit Ihrem „bunq”-Konto verknüpft sind. Bitte wählen Sie die Konten aus, von denen Sie importieren möchten, und in welches Konto die Buchungen importiert werden sollen.', diff --git a/resources/lang/de_DE/intro.php b/resources/lang/de_DE/intro.php index b4330dd585..8ebc5d6e6a 100644 --- a/resources/lang/de_DE/intro.php +++ b/resources/lang/de_DE/intro.php @@ -1,5 +1,6 @@ 'Hinzufügungen oder Entfernungen sind hier ebenfalls aufgeführt.', // bill index + 'bills_index_rules' => 'Hier sehen Sie, welche Regeln prüfen, ob diese Rechnung betroffen ist.', 'bills_index_paid_in_period' => 'Dieses Feld zeigt an, wann die Rechnung zuletzt bezahlt wurde.', 'bills_index_expected_in_period' => 'Dieses Feld zeigt für jede Rechnung an, ob und wann die nächste Rechnung erwartet wird.', @@ -100,11 +102,12 @@ return [ 'bills_show_billChart' => 'Diese Grafik zeigt die mit dieser Rechnung verknüpften Transaktionen.', // create bill + 'bills_create_intro' => 'Verwendet Rechnungen, um den Gesamtbetrag zu ermitteln, den Sie in jedem Zeitraum zahlen müssen. Denken Sie an Ausgaben wie Miete, Versicherung oder Hypothekenzahlungen.', 'bills_create_name' => 'Verwenden Sie einen aussagekräftigen Namen wie "Miete" oder "Krankenversicherung".', - 'bills_create_match' => 'Um Transaktionen abzugleichen, verwenden Sie Begriffe aus diesen Transaktionen oder dem betreffenden Aufwandskonto. Alle Wörter müssen übereinstimmen.', + //'bills_create_match' => 'To match transactions, use terms from those transactions or the expense account involved. All words must match.', 'bills_create_amount_min_holder' => 'Wählen Sie einen Mindest- und Höchstbetrag für diese Rechnung aus.', 'bills_create_repeat_freq_holder' => 'Die meisten Rechnungen wiederholen sich monatlich, aber Sie können hier eine andere Frequenz einstellen.', - 'bills_create_skip_holder' => 'Wenn eine Rechnung z.B. alle 2 Wochen wiederholt wird, sollte das Feld „überspringen” auf „1” gesetzt werden, um alle 2 Wochen zu überspringen.', + 'bills_create_skip_holder' => 'Wenn eine Rechnung alle 2 Wochen wiederholt wird, sollte das Feld „Überspringen” auf „1” festgelegt werden, um jede zweite Woche zu überspringen.', // rules index 'rules_index_intro' => 'Mit Firefly III können Sie Regeln verwalten, die automatisch auf alle Transaktionen angewendet werden, die Sie erstellen oder bearbeiten.', diff --git a/resources/lang/de_DE/list.php b/resources/lang/de_DE/list.php index a6059655b4..9d68888d00 100644 --- a/resources/lang/de_DE/list.php +++ b/resources/lang/de_DE/list.php @@ -33,6 +33,7 @@ return [ 'name' => 'Name', 'role' => 'Rolle', 'currentBalance' => 'Aktueller Kontostand', + 'linked_to_rules' => 'Verlinkte Regeln', 'active' => 'Aktiv?', 'lastActivity' => 'Letzte Aktivität', 'balanceDiff' => 'Saldendifferenz', diff --git a/resources/lang/es_ES/firefly.php b/resources/lang/es_ES/firefly.php index 1e128fbd9b..401f6b129b 100644 --- a/resources/lang/es_ES/firefly.php +++ b/resources/lang/es_ES/firefly.php @@ -267,7 +267,10 @@ return [ 'move_rule_group_down' => 'Mover el grupo de reglas hacia abajo', 'save_rules_by_moving' => 'Guardar esta(s) regla(s) moviéndola(s) a otro grupo:', 'make_new_rule' => 'Hacer nueva regla en grupo de regla ":title"', + 'rule_is_strict' => 'strict rule', + 'rule_is_not_strict' => 'non-strict rule', 'rule_help_stop_processing' => 'Al marcar esta casilla, las reglas posteriores de este grupo no se ejecutarán.', + 'rule_help_strict' => 'In strict rules ALL triggers must fire for the action(s) to be executed. In non-strict rules, ANY trigger is enough for the action(s) to be executed.', 'rule_help_active' => 'Las reglas inactivas nunca se ejecutan.', 'stored_new_rule' => 'Guardar la nueva regla con titulo ":title"', 'deleted_rule' => 'Regla eliminada con titulo ":title"', @@ -345,6 +348,8 @@ return [ 'rule_trigger_budget_is' => 'Presupuesto es ":trigger_value"', 'rule_trigger_tag_is_choice' => '(una) etiqueta es..', 'rule_trigger_tag_is' => 'Una etiqueta es ":trigger_value"', + 'rule_trigger_currency_is_choice' => 'Transaction currency is..', + 'rule_trigger_currency_is' => 'Transaction currency is ":trigger_value"', 'rule_trigger_has_attachments_choice' => 'Tiene al menos tantos archivos adjuntos', 'rule_trigger_has_attachments' => 'Tiene al menos :trigger_value anexo (s)', 'rule_trigger_store_journal' => 'Cuando la transacción es creada', @@ -404,10 +409,20 @@ return [ 'rule_action_clear_notes_choice' => 'Eliminar cualquier nota', 'rule_action_clear_notes' => 'Eliminar cualquier nota', 'rule_action_set_notes_choice' => 'Establecer notas para..', + 'rule_action_link_to_bill_choice' => 'Link to a bill..', + 'rule_action_link_to_bill' => 'Link to bill ":action_value"', 'rule_action_set_notes' => 'Establecer notas para:action_value', 'rules_have_read_warning' => '¿Has leído la advertencia?', 'apply_rule_warning' => 'Advertencia: Ejecutando una regla (grupo) en una gran selección de transacciones podría tomar años, y podría exceder el tiempo de espera. Si lo hace, la regla (grupo) solo se aplicara a un subconjunto desconocido de sus transacciones. Esto podría dejar a su administración financiera en ruinas. por favor tenga cuidado.', + 'rulegroup_for_bills_title' => 'Rule group for bills', + 'rulegroup_for_bills_description' => 'A special rule group for all the rules that involve bills.', + 'rule_for_bill_title' => 'Auto-generated rule for bill ":name"', + 'rule_for_bill_description' => 'This rule is auto-generated to try to match bill ":name".', + 'create_rule_for_bill' => 'Create a new rule for bill ":name"', + 'create_rule_for_bill_txt' => 'You have just created a new bill called ":name", congratulations! Firefly III can automagically match new withdrawals to this bill. For example, whenever you pay your rent, the bill "rent" will be linked to the expense. This way, Firefly III can accurately show you which bills are due and which ones aren\'t. In order to do so, a new rule must be created. Firefly III has filled in some sensible defaults for you. Please make sure these are correct. If these values are correct, Firefly III will automatically link the correct withdrawal to the correct bill. Please check out the triggers to see if they are correct, and add some if they\'re wrong.', + 'new_rule_for_bill_title' => 'Rule for bill ":name"', + 'new_rule_for_bill_description' => 'This rule marks transactions for bill ":name".', // tags 'store_new_tag' => 'Almacenar nueva etiqueta', @@ -624,8 +639,8 @@ return [ 'over_budget_warn' => ' Normally you budget about :amount per day. This is :over_amount per day.', // bills: - 'matching_on' => 'Emparejar en', - 'between_amounts' => 'entre :low y :high.', + 'match_between_amounts' => 'Bill matches transactions between :low and :high.', + 'bill_related_rules' => 'Rules related to this bill', 'repeats' => 'Repeticiones', 'connected_journals' => 'Transacciones conectadas', 'auto_match_on' => 'Automáticamente igualado por Firefly III', @@ -635,19 +650,20 @@ return [ 'deleted_bill' => 'Eliminar factura ":name"', 'edit_bill' => 'Editar factura ":name"', 'more' => 'Mas', - 'rescan_old' => 'Volver a analizar transacciones viejas', + 'rescan_old' => 'Run rules again, on all transactions', 'update_bill' => 'Actualizar factura', 'updated_bill' => 'Actualizar factura ":name"', 'store_new_bill' => 'Almacenar nueva factura', 'stored_new_bill' => 'Almacenar nueva factura ":name"', 'cannot_scan_inactive_bill' => 'Las facturas inactivas no pueden ser escaneadas.', - 'rescanned_bill' => 'Volver a escanear todo.', + 'rescanned_bill' => 'Rescanned everything, and linked :total transaction(s) to the bill.', 'average_bill_amount_year' => 'Monto promedio de la factura (:year)', 'average_bill_amount_overall' => 'Monto promedio de la factura (sobretodo)', 'bill_is_active' => 'Bill esta activo', 'bill_expected_between' => 'Esperado entre :start y :end', 'bill_will_automatch' => 'Bill se vinculara automáticamente a transacciones coincidentes', 'skips_over' => 'salta sobre', + 'bill_store_error' => 'An unexpected error occurred while storing your new bill. Please check the log files', // accounts: 'details_for_asset' => 'Detalles para la cuenta de activos ":name"', @@ -784,6 +800,7 @@ return [ 'opt_group_sharedAsset' => 'Cuenta de activos compartidas', 'opt_group_ccAsset' => 'Tarjetas de credito', 'notes' => 'Notas', + 'unknown_journal_error' => 'Could not store the transaction. Please check the log files.', // new user: 'welcome' => 'Bienvenido a Firefly III!', @@ -794,6 +811,10 @@ return [ defecto. No abra dinero en su cuenta de ahorros. pero si le dice a Firefly III el saldo se almacenara como tal.', 'finish_up_new_user' => 'Eso es! Usted puede continuar presionando. Usted sera llevado al indice de Firefly III.', 'stored_new_accounts_new_user' => 'Hurra! Sus nuevas cuentas han sido almacenadas.', + 'set_preferred_language' => 'If you prefer to use Firefly III in another language, please indicate so here.', + 'language' => 'Language', + 'new_savings_account' => ':bank_name savings account', + 'cash_wallet' => 'Cash wallet', // home page: 'yourAccounts' => 'Tus cuentas', @@ -942,6 +963,7 @@ return [ 'account_role_sharedAsset' => 'Compartir cuenta de ingresos', 'account_role_savingAsset' => 'Cuentas de ahorros', 'account_role_ccAsset' => 'Tarjeta de Crédito', + 'account_role_cashWalletAsset' => 'Cash wallet', 'budget_chart_click' => 'Por favor de click el nombre del presupuesto en la tabla de arriba para ver el cuadro.', 'category_chart_click' => 'Por favor de click en el nombre de categoría en la tabla de arriba para ver el cuadro.', 'in_out_accounts' => 'Ganado y gastado por combinación', @@ -1001,6 +1023,7 @@ return [ 'events' => 'Eventos', 'target_amount' => 'Cantidad objetivo', 'start_date' => 'Fecha de inicio', + 'no_start_date' => 'No start date', 'target_date' => 'Fecha objetivo', 'no_target_date' => 'Sin fecha de objetivo', 'table' => 'Mesa', @@ -1137,6 +1160,14 @@ return [ 'import_index_title' => 'Importar datos a Firefly III', 'import_index_sub_title' => 'Índice', 'import_general_index_intro' => 'Bienvenido a la rutina de importación de Firefly III. Hay algunas formas de importar datos a Firefly III, que se muestran aquí como botones.', + 'upload_error' => 'The file you have uploaded could not be processed. Possibly it is of an invalid file type or encoding. The log files will have more information.', + 'reset_import_settings_title' => 'Reset import configuration', + 'reset_import_settings_text' => 'You can use these links to reset your import settings for specific providers. This is useful when bad settings stop you from importing data.', + 'reset_settings_bunq' => 'Remove bunq API key, local external IP address and bunq related RSA keys.', + 'reset_settings_spectre' => 'Remove Spectre client ID, service secret and app secret. This will also remove your Spectre keypair. Remember to update the new one.', + 'settings_reset_for_bunq' => 'Bunq settings reset.', + 'settings_reset_for_spectre' => 'Spectre settings reset.', + // sandstorm.io errors and messages: 'sandstorm_not_available' => 'Esta función no esta disponible cuando usted esta utilizando Firefly III dentro de un ambiente Sandstorm.io.', diff --git a/resources/lang/es_ES/form.php b/resources/lang/es_ES/form.php index 2f2cf6d6aa..b19b567da5 100644 --- a/resources/lang/es_ES/form.php +++ b/resources/lang/es_ES/form.php @@ -1,5 +1,6 @@ 'Importe mínimo', 'amount_max' => 'Importe máximo', 'match' => 'Encuentros en', + 'strict' => 'Strict mode', 'repeat_freq' => 'Repetición', 'journal_currency_id' => 'Divisa', 'currency_id' => 'Divisa', + 'transaction_currency_id' => 'Currency', + 'external_ip' => 'Your server\'s external IP', 'attachments' => 'Adjuntos', 'journal_amount' => 'Importe', 'journal_source_account_name' => 'Cuenta de ingresos (origen)', diff --git a/resources/lang/es_ES/import.php b/resources/lang/es_ES/import.php index 0df9bf02b0..fcba709e8d 100644 --- a/resources/lang/es_ES/import.php +++ b/resources/lang/es_ES/import.php @@ -164,6 +164,7 @@ return [ // bunq 'bunq_prerequisites_title' => 'Pre requisitos para una importación de bunq', 'bunq_prerequisites_text' => 'In order to import from bunq, you need to obtain an API key. You can do this through the app. Please note that the import function for bunq is in BETA. It has only been tested against the sandbox API.', + 'bunq_prerequisites_text_ip' => 'Bunq requires your externally facing IP address. Firefly III has tried to fill this in using the ipify service. Make sure this IP address is correct, or the import will fail.', 'bunq_do_import' => 'Yes, import from this account', 'bunq_accounts_title' => 'Bunq accounts', 'bunq_accounts_text' => 'These are the accounts associated with your bunq account. Please select the accounts from which you want to import, and in which account the transactions must be imported.', diff --git a/resources/lang/es_ES/intro.php b/resources/lang/es_ES/intro.php index a606cf11f5..108538f286 100644 --- a/resources/lang/es_ES/intro.php +++ b/resources/lang/es_ES/intro.php @@ -1,5 +1,6 @@ 'Cualquier adición o eliminación también se ponen en lista aquí.', // bill index + 'bills_index_rules' => 'Here you see which rules will check if this bill is hit', 'bills_index_paid_in_period' => 'Este campo indica cuando la factura fue pagada por última vez.', 'bills_index_expected_in_period' => 'Este campo indica para cada factura si se espera que llegue la próxima factura.', @@ -100,11 +102,12 @@ return [ 'bills_show_billChart' => 'Este gráfico muestra las transacciones vinculadas con esta factura.', // create bill + 'bills_create_intro' => 'Use bills to track the amount of money you\'re due every period. Think about expenses like rent, insurance or mortgage payments.', 'bills_create_name' => 'Use un nombre descriptivo como "alquiler" o "seguro de salud".', - 'bills_create_match' => 'Para hacer coincidir transacciones, use términos de esas transacciones o de la cuenta de gastos involucrada. Todas las palabras deben coincidir.', + //'bills_create_match' => 'To match transactions, use terms from those transactions or the expense account involved. All words must match.', 'bills_create_amount_min_holder' => 'Seleccione un monto mínimo y uno máximo para esta factura.', 'bills_create_repeat_freq_holder' => 'Muchas facturas se repiten mensualmente, pero usted puede establecer otra frecuencia aquí.', - 'bills_create_skip_holder' => 'Si una factura se repite cada 2 semanas por ejemplo, el campo "omitir" debe establecerse en "1" para omitir cada otra semana.', + 'bills_create_skip_holder' => 'If a bill repeats every 2 weeks, the "skip"-field should be set to "1" to skip every other week.', // rules index 'rules_index_intro' => 'Firefly III le permite administrar reglas, que automáticamente se aplicaran para cualquier transacción que cree o edite.', diff --git a/resources/lang/es_ES/list.php b/resources/lang/es_ES/list.php index 280df678e8..58c3813e8f 100644 --- a/resources/lang/es_ES/list.php +++ b/resources/lang/es_ES/list.php @@ -33,6 +33,7 @@ return [ 'name' => 'Nombre', 'role' => 'Rol', 'currentBalance' => 'Balance actual', + 'linked_to_rules' => 'Relevant rules', 'active' => '¿Está Activo?', 'lastActivity' => 'Actividad más reciente', 'balanceDiff' => 'Diferencia de equilibrio', diff --git a/resources/lang/fr_FR/firefly.php b/resources/lang/fr_FR/firefly.php index 09f94ed303..f0f379cf20 100644 --- a/resources/lang/fr_FR/firefly.php +++ b/resources/lang/fr_FR/firefly.php @@ -267,7 +267,10 @@ return [ 'move_rule_group_down' => 'Descendre le groupe de règles', 'save_rules_by_moving' => 'Enregistrer ces règles en les déplaçant vers un autre groupe de règles :', 'make_new_rule' => 'Créer une nouvelle règle dans le groupe de règles ":title"', + 'rule_is_strict' => 'strict rule', + 'rule_is_not_strict' => 'non-strict rule', 'rule_help_stop_processing' => 'Lorsque vous cochez cette case, les règles suivantes de ce groupe ne seront pas exécutées.', + 'rule_help_strict' => 'In strict rules ALL triggers must fire for the action(s) to be executed. In non-strict rules, ANY trigger is enough for the action(s) to be executed.', 'rule_help_active' => 'Les règles inactives ne se déclencheront jamais.', 'stored_new_rule' => 'Nouvelle règle créée avec le titre ":title"', 'deleted_rule' => 'Règle supprimée avec le titre ":title"', @@ -345,6 +348,8 @@ return [ 'rule_trigger_budget_is' => 'Le budget est ":trigger_value"', 'rule_trigger_tag_is_choice' => '(A) le tag est..', 'rule_trigger_tag_is' => 'Un tag est ":trigger_value"', + 'rule_trigger_currency_is_choice' => 'La devise de la transaction est ..', + 'rule_trigger_currency_is' => 'La devise de la transaction est ":trigger_value"', 'rule_trigger_has_attachments_choice' => 'À au moins autant de pièces jointes', 'rule_trigger_has_attachments' => 'À au moins :trigger_value pièce(s) jointe(s)', 'rule_trigger_store_journal' => 'Lorsqu’une transaction est créée', @@ -404,10 +409,20 @@ return [ 'rule_action_clear_notes_choice' => 'Supprimer les notes', 'rule_action_clear_notes' => 'Supprimer les notes', 'rule_action_set_notes_choice' => 'Remplacer les notes par..', + 'rule_action_link_to_bill_choice' => 'Lien vers une facture..', + 'rule_action_link_to_bill' => 'Lien vers la facture ":action_value"', 'rule_action_set_notes' => 'Remplacer les notes par ":action_value"', 'rules_have_read_warning' => 'Avez-vous lu les avertissements ?', 'apply_rule_warning' => 'Avertissement : exécuter une règle ou un groupe de règles sur un grand nombre de transactions peut prendre beaucoup de temps, et pourrait entraîner un time-out. Si c\'est le cas, alors la règle ou le groupe de règles ne serait appliqué que sur une partie indéterminée de vos transactions. Cela peut engendrer des erreurs sur votre gestion financière. S\'il vous plaît, faites attention.', + 'rulegroup_for_bills_title' => 'Groupe de règles pour les factures', + 'rulegroup_for_bills_description' => 'Un groupe de règles spécial pour toutes les règles impliquant des factures.', + 'rule_for_bill_title' => 'Règle générée automatiquement pour la facture ":name"', + 'rule_for_bill_description' => 'Cette règle est générée automatiquement pour essayer de faire correspondre la facture ":name".', + 'create_rule_for_bill' => 'Créer une nouvelle règle pour la facture ":name"', + 'create_rule_for_bill_txt' => 'Vous venez de créer une nouvelle facture appelée ":name", félicitations! Firefly III peut automagiquement faire correspondre de nouvelles dépenses à cette facture. Par exemple, chaque fois que vous payez votre loyer, la facture "loyer" sera liée à la dépense. De cette façon, Firefly III peut vous montrer exactement quelles factures sont dues et lesquelles ne le sont pas. Pour ce faire, une nouvelle règle doit être créée. Firefly III a rempli certaines valeurs par défaut raisonnables pour vous. S\'il vous plaît assurez-vous que ceux-ci sont corrects. Si ces valeurs sont correctes, Firefly III liera automatiquement la bonne dépense à la bonne facture. S\'il vous plaît vérifier les déclencheurs pour voir si elles sont correctes, et en ajouter si elles sont fausses.', + 'new_rule_for_bill_title' => 'Règle pour la facture ":name"', + 'new_rule_for_bill_description' => 'Cette règle marque les transactions pour la facture ":name".', // tags 'store_new_tag' => 'Créer un nouveau tag', @@ -621,11 +636,11 @@ return [ 'available_amount_indication' => 'Utilisez ces montants pour avoir une indication de ce que pourrait être votre budget total.', 'suggested' => 'Suggéré', 'average_between' => 'Moyenne entre :start et :end', - 'over_budget_warn' => ' Normally you budget about :amount per day. This is :over_amount per day.', + 'over_budget_warn' => ' Normalement vous budgétez :amount par jour. Là c\'est :over_amount par jour.', // bills: - 'matching_on' => 'Correspond à', - 'between_amounts' => 'entre :low et :high.', + 'match_between_amounts' => 'Bill matches transactions between :low and :high.', + 'bill_related_rules' => 'Rules related to this bill', 'repeats' => 'Répétitions', 'connected_journals' => 'Opérations liées', 'auto_match_on' => 'Automatiquement mis en correspondance par Firefly III', @@ -635,19 +650,20 @@ return [ 'deleted_bill' => 'Facture ":name" supprimée', 'edit_bill' => 'Modifier la facture : ":name"', 'more' => 'Plus', - 'rescan_old' => 'Réanalyser les anciennes opérations', + 'rescan_old' => 'Run rules again, on all transactions', 'update_bill' => 'Mettre à jour la facture', 'updated_bill' => 'Facture ":name" mise à jour', 'store_new_bill' => 'Créer une nouvelle facture', 'stored_new_bill' => 'Nouvelle facture ":name" créée', 'cannot_scan_inactive_bill' => 'Les factures inactives ne peuvent pas être analysées.', - 'rescanned_bill' => 'Réanalyser tout.', + 'rescanned_bill' => 'Rescanned everything, and linked :total transaction(s) to the bill.', 'average_bill_amount_year' => 'Montant moyen des factures ( :year)', 'average_bill_amount_overall' => 'Montant moyen de la facture (global)', 'bill_is_active' => 'Facture en cours', 'bill_expected_between' => 'Attendu entre le :start et le :end', 'bill_will_automatch' => 'La facture sera automatiquement liée aux transactions correspondantes', 'skips_over' => 'saute', + 'bill_store_error' => 'Une erreur inattendue s\'est produite lors du stockage de votre nouvelle facture. Veuillez vérifier les fichiers journaux', // accounts: 'details_for_asset' => 'Détails pour le compte d’actif ":name"', @@ -784,6 +800,7 @@ return [ 'opt_group_sharedAsset' => 'Comptes d\'actifs partagés', 'opt_group_ccAsset' => 'Cartes de crédit', 'notes' => 'Notes', + 'unknown_journal_error' => 'Impossible de stocker la transaction. Veuillez vérifier les fichiers journaux.', // new user: 'welcome' => 'Bienvenue sur Firefly III!', @@ -793,6 +810,10 @@ return [ 'savings_balance_text' => 'Firefly III créera automatiquement un compte d\'épargne pour vous. Par défaut, il n\'y aura pas d\'argent dans votre compte d\'épargne, mais si vous le dites à Firefly III, le solde sera stocké en tant que tel.', 'finish_up_new_user' => 'C\'est tout ! Vous pouvez continuer en appuyant sur Envoyer. Vous passerez à l\'index de Firefly III.', 'stored_new_accounts_new_user' => 'Super ! Vos nouveaux comptes ont été créés.', + 'set_preferred_language' => 'If you prefer to use Firefly III in another language, please indicate so here.', + 'language' => 'Language', + 'new_savings_account' => ':bank_name savings account', + 'cash_wallet' => 'Cash wallet', // home page: 'yourAccounts' => 'Vos comptes', @@ -831,12 +852,12 @@ return [ 'moneyManagement' => 'Gérer les comptes', 'piggyBanks' => 'Tirelires', 'bills' => 'Factures', - 'withdrawal' => 'Retrait', + 'withdrawal' => 'Dépense', 'opening_balance' => 'Solde d\'ouverture', 'deposit' => 'Dépôt', 'account' => 'Compte', 'transfer' => 'Transfert', - 'Withdrawal' => 'Retrait', + 'Withdrawal' => 'Dépense', 'Deposit' => 'Dépôt', 'Transfer' => 'Transfert', 'bill' => 'Facture', @@ -941,6 +962,7 @@ return [ 'account_role_sharedAsset' => 'Compte d\'actif partagé', 'account_role_savingAsset' => 'Compte d’épargne', 'account_role_ccAsset' => 'Carte de crédit', + 'account_role_cashWalletAsset' => 'Cash wallet', 'budget_chart_click' => 'Cliquez sur le nom du budget dans le tableau ci-dessus pour voir un graphique.', 'category_chart_click' => 'Cliquez sur un nom de catégorie dans le tableau ci-dessus pour voir un graphique.', 'in_out_accounts' => 'Gagné et dépensé par compte', @@ -1000,6 +1022,7 @@ return [ 'events' => 'Evènements', 'target_amount' => 'Montant cible', 'start_date' => 'Date de début', + 'no_start_date' => 'No start date', 'target_date' => 'Date cible', 'no_target_date' => 'Aucune date butoir', 'table' => 'Tableau', @@ -1086,7 +1109,7 @@ return [ 'invalid_link_selection' => 'Impossible de lier ces transactions', 'journals_linked' => 'Ces transactions sont liées.', 'journals_error_linked' => 'Ces transactions sont déjà liées.', - 'journals_link_to_self' => 'You cannot link a transaction to itself', + 'journals_link_to_self' => 'Vous ne pouvez pas lier une transaction à elle-même', 'journal_links' => 'Liens de transaction', 'this_withdrawal' => 'Ce retrait', 'this_deposit' => 'Ce dépôt', @@ -1136,6 +1159,14 @@ return [ 'import_index_title' => 'Importer des données dans Firefly III', 'import_index_sub_title' => 'Index', 'import_general_index_intro' => 'Bienvenue dans la routine d\'importation de Firefly III. Il existe différentes façons d\'importer des données dans Firefly III, affichées ici sous forme de boutons.', + 'upload_error' => 'Le fichier que vous avez téléchargé n\'a pas pu être traité. Peut-être qu\'il s\'agit d\'un type de fichier ou d\'un encodage invalide. Plus d\'informations dans les fichiers journaux.', + 'reset_import_settings_title' => 'Reset import configuration', + 'reset_import_settings_text' => 'You can use these links to reset your import settings for specific providers. This is useful when bad settings stop you from importing data.', + 'reset_settings_bunq' => 'Remove bunq API key, local external IP address and bunq related RSA keys.', + 'reset_settings_spectre' => 'Remove Spectre client ID, service secret and app secret. This will also remove your Spectre keypair. Remember to update the new one.', + 'settings_reset_for_bunq' => 'Bunq settings reset.', + 'settings_reset_for_spectre' => 'Spectre settings reset.', + // sandstorm.io errors and messages: 'sandstorm_not_available' => 'Cette fonction n\'est pas disponible lorsque vous utilisez Firefly III dans un environnement Sandstorm.io.', diff --git a/resources/lang/fr_FR/form.php b/resources/lang/fr_FR/form.php index 6d0e50ff53..22f929ce5f 100644 --- a/resources/lang/fr_FR/form.php +++ b/resources/lang/fr_FR/form.php @@ -1,5 +1,6 @@ 'Montant minimum', 'amount_max' => 'Montant maximum', 'match' => 'Correspondre à', + 'strict' => 'Strict mode', 'repeat_freq' => 'Répétitions', 'journal_currency_id' => 'Devise', 'currency_id' => 'Devise', + 'transaction_currency_id' => 'Currency', + 'external_ip' => 'Your server\'s external IP', 'attachments' => 'Documents joints', 'journal_amount' => 'Montant', 'journal_source_account_name' => 'Compte de recettes (source)', diff --git a/resources/lang/fr_FR/import.php b/resources/lang/fr_FR/import.php index 1216706002..d09a0d8d24 100644 --- a/resources/lang/fr_FR/import.php +++ b/resources/lang/fr_FR/import.php @@ -164,6 +164,7 @@ return [ // bunq 'bunq_prerequisites_title' => 'Prerequisites for an import from bunq', 'bunq_prerequisites_text' => 'In order to import from bunq, you need to obtain an API key. You can do this through the app. Please note that the import function for bunq is in BETA. It has only been tested against the sandbox API.', + 'bunq_prerequisites_text_ip' => 'Bunq requires your externally facing IP address. Firefly III has tried to fill this in using the ipify service. Make sure this IP address is correct, or the import will fail.', 'bunq_do_import' => 'Yes, import from this account', 'bunq_accounts_title' => 'Bunq accounts', 'bunq_accounts_text' => 'These are the accounts associated with your bunq account. Please select the accounts from which you want to import, and in which account the transactions must be imported.', diff --git a/resources/lang/fr_FR/intro.php b/resources/lang/fr_FR/intro.php index 1499a1a9f2..2b4ed6d7fb 100644 --- a/resources/lang/fr_FR/intro.php +++ b/resources/lang/fr_FR/intro.php @@ -1,5 +1,6 @@ 'Des ajouts ou suppressions sont également répertoriées ici.', // bill index + 'bills_index_rules' => 'Here you see which rules will check if this bill is hit', 'bills_index_paid_in_period' => 'Ce champ indique quand la facture a été payée pour la dernière fois.', 'bills_index_expected_in_period' => 'Ce champ indique pour chaque facture si et quand la facture suivante est attendue.', @@ -100,11 +102,12 @@ return [ 'bills_show_billChart' => 'Ce tableau montre les transactions liées à cette facture.', // create bill + 'bills_create_intro' => 'Use bills to track the amount of money you\'re due every period. Think about expenses like rent, insurance or mortgage payments.', 'bills_create_name' => 'Utilisez un nom équivoque tel que "Loyer" ou "Assurance maladie".', - 'bills_create_match' => 'Pour faire correspondre les transactions, utilisez les termes de ces transactions ou le compte de dépenses impliqué. Tous les mots doivent correspondre.', + //'bills_create_match' => 'To match transactions, use terms from those transactions or the expense account involved. All words must match.', 'bills_create_amount_min_holder' => 'Sélectionnez un montant minimum et maximum pour cette facture.', 'bills_create_repeat_freq_holder' => 'La plupart des factures sont mensuelles, mais vous pouvez définir une autre fréquence ici.', - 'bills_create_skip_holder' => 'Si une facture se répète toutes les 2 semaines par exemple, le champ "sauter" doit être réglé sur "1" pour sauter une semaine sur deux.', + 'bills_create_skip_holder' => 'If a bill repeats every 2 weeks, the "skip"-field should be set to "1" to skip every other week.', // rules index 'rules_index_intro' => 'Firefly III vous permet de gérer les règles, qui seront automagiquement appliquées à toute transaction que vous créez ou modifiez.', diff --git a/resources/lang/fr_FR/list.php b/resources/lang/fr_FR/list.php index 25d3a1eed6..f7a39162b3 100644 --- a/resources/lang/fr_FR/list.php +++ b/resources/lang/fr_FR/list.php @@ -33,6 +33,7 @@ return [ 'name' => 'Nom', 'role' => 'Rôle', 'currentBalance' => 'Solde courant', + 'linked_to_rules' => 'Relevant rules', 'active' => 'Actif ?', 'lastActivity' => 'Activité récente', 'balanceDiff' => 'Différence d\'équilibre', @@ -110,5 +111,5 @@ return [ 'sepa-cc' => 'Code de compensation SEPA', 'sepa-ep' => 'Objectif externe SEPA', 'sepa-ci' => 'Identifiant SEPA Creditor', - 'account_at_bunq' => 'Account with bunq', + 'account_at_bunq' => 'Compte avec bunq', ]; diff --git a/resources/lang/id_ID/firefly.php b/resources/lang/id_ID/firefly.php index 361e491eaf..2c3fef517c 100644 --- a/resources/lang/id_ID/firefly.php +++ b/resources/lang/id_ID/firefly.php @@ -267,7 +267,10 @@ return [ 'move_rule_group_down' => 'Pindahkan grup aturan ke bawah', 'save_rules_by_moving' => 'Simpan aturan ini dengan memindahkannya ke grup aturan lain:', 'make_new_rule' => 'Buat aturan baru di grup aturan ":title"', + 'rule_is_strict' => 'strict rule', + 'rule_is_not_strict' => 'non-strict rule', 'rule_help_stop_processing' => 'Saat Anda mencentang kotak ini, nanti aturan dalam grup ini tidak akan dijalankan.', + 'rule_help_strict' => 'In strict rules ALL triggers must fire for the action(s) to be executed. In non-strict rules, ANY trigger is enough for the action(s) to be executed.', 'rule_help_active' => 'Aturan tidak aktif tidak akan pernah menyala.', 'stored_new_rule' => 'Aturan baru yang tersimpan dengan judul ":title"', 'deleted_rule' => 'Aturan yang dihapus dengan judul ":title"', @@ -345,6 +348,8 @@ return [ 'rule_trigger_budget_is' => 'Anggaran adalah ":trigger_value"', 'rule_trigger_tag_is_choice' => '(A) tag adalah..', 'rule_trigger_tag_is' => 'Tag adalah ":trigger_value"', + 'rule_trigger_currency_is_choice' => 'Transaction currency is..', + 'rule_trigger_currency_is' => 'Transaction currency is ":trigger_value"', 'rule_trigger_has_attachments_choice' => 'Paling tidak banyak keterikatan ini', 'rule_trigger_has_attachments' => 'Paling tidak:trigger_value attachment (s)', 'rule_trigger_store_journal' => 'Saat transaksi dibuat', @@ -404,10 +409,20 @@ return [ 'rule_action_clear_notes_choice' => 'Hapus catatan apapun', 'rule_action_clear_notes' => 'Hapus catatan apapun', 'rule_action_set_notes_choice' => 'Tetapkan catatan ke..', + 'rule_action_link_to_bill_choice' => 'Link to a bill..', + 'rule_action_link_to_bill' => 'Link to bill ":action_value"', 'rule_action_set_notes' => 'Tetapkan catatan ke ":action_value"', 'rules_have_read_warning' => 'Sudahkah anda membaca peringatannya?', 'apply_rule_warning' => 'Peringatan: menjalankan aturan (grup) pada banyak pilihan transaksi bisa memakan waktu lama, dan bisa time-out. Jika ya, aturan (grup) hanya akan diterapkan ke subkumpulan transaksi yang tidak diketahui. Ini mungkin akan membuat administrasi keuangan Anda berantakan. Tolong hati-hati.', + 'rulegroup_for_bills_title' => 'Rule group for bills', + 'rulegroup_for_bills_description' => 'A special rule group for all the rules that involve bills.', + 'rule_for_bill_title' => 'Auto-generated rule for bill ":name"', + 'rule_for_bill_description' => 'This rule is auto-generated to try to match bill ":name".', + 'create_rule_for_bill' => 'Create a new rule for bill ":name"', + 'create_rule_for_bill_txt' => 'You have just created a new bill called ":name", congratulations! Firefly III can automagically match new withdrawals to this bill. For example, whenever you pay your rent, the bill "rent" will be linked to the expense. This way, Firefly III can accurately show you which bills are due and which ones aren\'t. In order to do so, a new rule must be created. Firefly III has filled in some sensible defaults for you. Please make sure these are correct. If these values are correct, Firefly III will automatically link the correct withdrawal to the correct bill. Please check out the triggers to see if they are correct, and add some if they\'re wrong.', + 'new_rule_for_bill_title' => 'Rule for bill ":name"', + 'new_rule_for_bill_description' => 'This rule marks transactions for bill ":name".', // tags 'store_new_tag' => 'Simpan tag baru', @@ -624,8 +639,8 @@ return [ 'over_budget_warn' => ' Normally you budget about :amount per day. This is :over_amount per day.', // bills: - 'matching_on' => 'Cocok di', - 'between_amounts' => 'antara :low dan :high.', + 'match_between_amounts' => 'Bill matches transactions between :low and :high.', + 'bill_related_rules' => 'Rules related to this bill', 'repeats' => 'Berulang', 'connected_journals' => 'Transaksi yang terhubung', 'auto_match_on' => 'Automatically matched by Firefly III', @@ -635,19 +650,20 @@ return [ 'deleted_bill' => 'Tagihan yang dihapus ":name"', 'edit_bill' => 'Edit tagihan ":name"', 'more' => 'Lebih', - 'rescan_old' => 'Rescan transaksi lama', + 'rescan_old' => 'Run rules again, on all transactions', 'update_bill' => 'Perbarui tagihan', 'updated_bill' => 'Diperbarui tagihan ":name"', 'store_new_bill' => 'Simpan tagihan baru', 'stored_new_bill' => 'Stored tagihan baru ":name"', 'cannot_scan_inactive_bill' => 'Tagihan tidak aktif tidak dapat dipindai.', - 'rescanned_bill' => 'Rescanned semuanya.', + 'rescanned_bill' => 'Rescanned everything, and linked :total transaction(s) to the bill.', 'average_bill_amount_year' => 'Jumlah tagihan rata-rata (:year)', 'average_bill_amount_overall' => 'Jumlah tagihan rata-rata (keseluruhan)', 'bill_is_active' => 'Tagihan aktif', 'bill_expected_between' => 'Diharapkan antara :start dan :end', 'bill_will_automatch' => 'Tagihan akan secara otomatis terhubung ke transaksi yang sesuai', 'skips_over' => 'melompati', + 'bill_store_error' => 'An unexpected error occurred while storing your new bill. Please check the log files', // accounts: 'details_for_asset' => 'Rincian akun aset ":name"', @@ -784,6 +800,7 @@ return [ 'opt_group_sharedAsset' => 'Akun aset bersama', 'opt_group_ccAsset' => 'Kartu kredit', 'notes' => 'Notes', + 'unknown_journal_error' => 'Could not store the transaction. Please check the log files.', // new user: 'welcome' => 'Welcome to Firefly III!', @@ -793,6 +810,10 @@ return [ 'savings_balance_text' => 'Firefly III secara otomatis akan membuat rekening tabungan untuk Anda. Secara default, tidak akan ada uang di rekening tabungan Anda, tapi jika Anda memberi tahu Firefly III, saldo itu akan disimpan seperti itu.', 'finish_up_new_user' => 'Itu dia! Anda dapat melanjutkan dengan menekan Kirim. Anda akan dibawa ke indeks Firefly III.', 'stored_new_accounts_new_user' => 'Yay! Akun baru Anda telah disimpan.', + 'set_preferred_language' => 'If you prefer to use Firefly III in another language, please indicate so here.', + 'language' => 'Language', + 'new_savings_account' => ':bank_name savings account', + 'cash_wallet' => 'Cash wallet', // home page: 'yourAccounts' => 'Akun anda', @@ -941,6 +962,7 @@ return [ 'account_role_sharedAsset' => 'Akun aset bersama', 'account_role_savingAsset' => 'Rekening tabungan', 'account_role_ccAsset' => 'Kartu kredit', + 'account_role_cashWalletAsset' => 'Cash wallet', 'budget_chart_click' => 'Silahkan klik nama anggaran pada tabel di atas untuk melihat grafik.', 'category_chart_click' => 'Silahkan klik pada nama kategori pada tabel di atas untuk melihat grafik.', 'in_out_accounts' => 'Diperoleh dan dihabiskan per kombinasi', @@ -1000,6 +1022,7 @@ return [ 'events' => 'Acara', 'target_amount' => 'Jumlah target', 'start_date' => 'Mulai tanggal', + 'no_start_date' => 'No start date', 'target_date' => 'Tanggal target', 'no_target_date' => 'Tidak ada tanggal target', 'table' => 'Meja', @@ -1136,6 +1159,14 @@ return [ 'import_index_title' => 'Impor data ke Firefly III', 'import_index_sub_title' => 'Indeks', 'import_general_index_intro' => 'Welcome to Firefly III\'s import routine. There are a few ways of importing data into Firefly III, displayed here as buttons.', + 'upload_error' => 'The file you have uploaded could not be processed. Possibly it is of an invalid file type or encoding. The log files will have more information.', + 'reset_import_settings_title' => 'Reset import configuration', + 'reset_import_settings_text' => 'You can use these links to reset your import settings for specific providers. This is useful when bad settings stop you from importing data.', + 'reset_settings_bunq' => 'Remove bunq API key, local external IP address and bunq related RSA keys.', + 'reset_settings_spectre' => 'Remove Spectre client ID, service secret and app secret. This will also remove your Spectre keypair. Remember to update the new one.', + 'settings_reset_for_bunq' => 'Bunq settings reset.', + 'settings_reset_for_spectre' => 'Spectre settings reset.', + // sandstorm.io errors and messages: 'sandstorm_not_available' => 'Fungsi ini tidak tersedia saat Anda menggunakan Firefly III di dalam lingkungan Sandstorm.io.', diff --git a/resources/lang/id_ID/form.php b/resources/lang/id_ID/form.php index 91bd88422e..17650c0aa0 100644 --- a/resources/lang/id_ID/form.php +++ b/resources/lang/id_ID/form.php @@ -1,5 +1,6 @@ 'Jumlah minimal', 'amount_max' => 'Jumlah maksimum', 'match' => 'Cocok di', + 'strict' => 'Strict mode', 'repeat_freq' => 'Berulang', 'journal_currency_id' => 'Mata uang', 'currency_id' => 'Mata uang', + 'transaction_currency_id' => 'Currency', + 'external_ip' => 'Your server\'s external IP', 'attachments' => 'Lampiran', 'journal_amount' => 'Jumlah', 'journal_source_account_name' => 'Akun pendapatan (sumber)', diff --git a/resources/lang/id_ID/import.php b/resources/lang/id_ID/import.php index 762939879f..38f8e67d04 100644 --- a/resources/lang/id_ID/import.php +++ b/resources/lang/id_ID/import.php @@ -164,6 +164,7 @@ return [ // bunq 'bunq_prerequisites_title' => 'Prasyarat untuk impor dari bunq', 'bunq_prerequisites_text' => 'In order to import from bunq, you need to obtain an API key. You can do this through the app. Please note that the import function for bunq is in BETA. It has only been tested against the sandbox API.', + 'bunq_prerequisites_text_ip' => 'Bunq requires your externally facing IP address. Firefly III has tried to fill this in using the ipify service. Make sure this IP address is correct, or the import will fail.', 'bunq_do_import' => 'Yes, import from this account', 'bunq_accounts_title' => 'Bunq accounts', 'bunq_accounts_text' => 'These are the accounts associated with your bunq account. Please select the accounts from which you want to import, and in which account the transactions must be imported.', diff --git a/resources/lang/id_ID/intro.php b/resources/lang/id_ID/intro.php index 34ba249aad..2c47c0c340 100644 --- a/resources/lang/id_ID/intro.php +++ b/resources/lang/id_ID/intro.php @@ -1,5 +1,6 @@ 'Setiap tambahan atau kepindahan juga tercantum di sini.', // bill index + 'bills_index_rules' => 'Here you see which rules will check if this bill is hit', 'bills_index_paid_in_period' => 'Bagian ini menunjukkan kapan tagihan terakhir dibayarkan.', 'bills_index_expected_in_period' => 'Bagian ini menunjukkan setiap tagihan jika dan kapan tagihan berikutnya diperkirakan akan dibayar.', @@ -100,11 +102,12 @@ return [ 'bills_show_billChart' => 'Bagan ini menunjukkan transaksi yang terkait dengan tagihan ini.', // create bill + 'bills_create_intro' => 'Use bills to track the amount of money you\'re due every period. Think about expenses like rent, insurance or mortgage payments.', 'bills_create_name' => 'Gunakan nama yang deskriptif seperti "Rent" atau "Health insurance".', - 'bills_create_match' => 'Untuk mencocokan transaksi, gunakan persyaratan dari transaksi tersebut atau akun biaya yang terlibat. Semua kata harus sesuai.', + //'bills_create_match' => 'To match transactions, use terms from those transactions or the expense account involved. All words must match.', 'bills_create_amount_min_holder' => 'Pilih jumlah minimum dan maksimum untuk tagihan ini.', 'bills_create_repeat_freq_holder' => 'Sebagian besar tagihan diulang setiap bulannya, tapi anda bisa mengatur frekuensi lain di sini.', - 'bills_create_skip_holder' => 'Jika tagihan berulang setiap 2 minggu misalnya, bagian "lewati" harus ditetapkan ke "1" untuk melewati setiap minggu lainnya.', + 'bills_create_skip_holder' => 'If a bill repeats every 2 weeks, the "skip"-field should be set to "1" to skip every other week.', // rules index 'rules_index_intro' => 'Firefly III memungkinkan anda mengatur peraturan-peraturan, yang otomatis akan diterapkan pada transaksi yang anda buat atau edit.', diff --git a/resources/lang/id_ID/list.php b/resources/lang/id_ID/list.php index fed38bf0ff..d0e4d1986b 100644 --- a/resources/lang/id_ID/list.php +++ b/resources/lang/id_ID/list.php @@ -33,6 +33,7 @@ return [ 'name' => 'Nama', 'role' => 'Peran', 'currentBalance' => 'Saldo saat ini', + 'linked_to_rules' => 'Relevant rules', 'active' => 'Aktif?', 'lastActivity' => 'Aktifitas terakhir', 'balanceDiff' => 'Perbedaan saldo', diff --git a/resources/lang/it_IT/breadcrumbs.php b/resources/lang/it_IT/breadcrumbs.php index ca9632bbdb..a9074e4372 100644 --- a/resources/lang/it_IT/breadcrumbs.php +++ b/resources/lang/it_IT/breadcrumbs.php @@ -30,11 +30,11 @@ return [ 'profile' => 'Profilo', 'changePassword' => 'Cambia la tua password', 'change_email' => 'Cambia il tuo indirizzo email', - 'bills' => 'Fatture', - 'newBill' => 'Nuova fattura', - 'edit_bill' => 'Modifica fattura ":name"', - 'delete_bill' => 'Elimina fattura ":name"', - 'reports' => 'Stampe', + 'bills' => 'Bollette', + 'newBill' => 'Nuova bolletta', + 'edit_bill' => 'Modifica bolletta ":name"', + 'delete_bill' => 'Elimina bolletta ":name"', + 'reports' => 'Resoconti', 'search_result' => 'Risultati di ricerca per ":query"', 'withdrawal_list' => 'Spese', 'deposit_list' => 'Entrate, entrate e depositi', diff --git a/resources/lang/it_IT/config.php b/resources/lang/it_IT/config.php index c58a708ea1..bc0a5ab62c 100644 --- a/resources/lang/it_IT/config.php +++ b/resources/lang/it_IT/config.php @@ -27,14 +27,14 @@ return [ 'month_and_day' => '%e %B %Y', 'date_time' => '%e %B %Y, @ %T', 'specific_day' => '%e %B %Y', - 'week_in_year' => 'Week %W, %Y', + 'week_in_year' => 'Settimana %W, %Y', 'year' => '%Y', 'half_year' => '%B %Y', - 'month_js' => 'MMMM YYYY', + 'month_js' => 'MMMM AAAA', 'month_and_day_js' => 'Do MMMM YYYY', 'date_time_js' => 'Do MMMM YYYY, @ HH:mm:ss', - 'specific_day_js' => 'D MMMM YYYY', - 'week_in_year_js' => '[Week] w, YYYY', - 'year_js' => 'YYYY', - 'half_year_js' => 'Q YYYY', + 'specific_day_js' => 'G MMMM AAAA', + 'week_in_year_js' => '[Week] s, AAAA', + 'year_js' => 'AAAA', + 'half_year_js' => 'T AAAA', ]; diff --git a/resources/lang/it_IT/demo.php b/resources/lang/it_IT/demo.php index 064ef212c7..b17e9ce513 100644 --- a/resources/lang/it_IT/demo.php +++ b/resources/lang/it_IT/demo.php @@ -23,10 +23,10 @@ declare(strict_types=1); return [ 'no_demo_text' => 'Spiacenti, non esiste un testo dimostrativo aggiuntivo per questa pagina.', 'see_help_icon' => 'Tuttavia, il -icon in alto a destra potrebbe dirti di più.', - 'index' => 'Benvenuto in Firefly III! In questa pagina ottieni una rapida panoramica delle tue finanze. Per ulteriori informazioni, controlla Account e → Account asset e, naturalmente, i budget e rapporti. O semplicemente dare un occhiata in giro e vedere dove finisci.', + 'index' => 'Benvenuto in Firefly III! In questa pagina ottieni una rapida panoramica delle tue finanze. Per ulteriori informazioni, controlla Account e → Account asset e, naturalmente, i budget e i resoconti. O semplicemente dai un\'occhiata in giro e vedi dove finisci.', 'accounts-index' => 'I conti degli asset sono i tuoi conti bancari personali. I conti spese sono gli account a cui si spendono soldi, come negozi e amici. I conti delle entrate sono conti da cui ricevi denaro, come il tuo lavoro, il governo o altre fonti di reddito. In questa pagina puoi modificarli o rimuoverli.', 'budgets-index' => 'Questa pagina ti mostra una panoramica dei tuoi budget. La barra in alto mostra l\'importo disponibile per essere preventivato. Questo può essere personalizzato per qualsiasi periodo facendo clic sull\'importo a destra. La quantità che hai effettivamente speso è mostrata nella barra sottostante. Di seguito sono indicate le spese per budget e ciò che hai preventivato per loro.', - 'reports-index-start' => 'Firefly III supporta un certo numero di tipi di stampe. Leggi facendo clic sul -icon in alto a destra.', + 'reports-index-start' => 'Firefly III supporta un certo numero di tipi di resoconto. Leggi facendo clic sull\'icona in alto a destra.', 'reports-index-examples' => 'Assicurati di dare un occhiata a questi esempi: una panoramica finanziaria mensile , una panoramica finanziaria annuale e una panoramica del budget .', 'currencies-index' => 'Firefly III supporta più valute. Sebbene sia impostato su Euro, può essere impostato sul dollaro USA e su molte altre valute. Come puoi vedere, è stata inclusa una piccola selezione di valute, ma puoi aggiungere la tua se lo desideri. Tuttavia, la modifica della valuta predefinita non cambierà la valuta delle transazioni esistenti: Firefly III supporta un uso di più valute allo stesso tempo.', 'transactions-index' => 'Queste spese, depositi e trasferimenti non sono particolarmente fantasiosi. Sono stati generati automaticamente.', diff --git a/resources/lang/it_IT/firefly.php b/resources/lang/it_IT/firefly.php index 33bac95932..7e6b6ef5b5 100644 --- a/resources/lang/it_IT/firefly.php +++ b/resources/lang/it_IT/firefly.php @@ -49,7 +49,7 @@ return [ 'go_to_asset_accounts' => 'Visualizza i tuoi movimenti', 'go_to_budgets' => 'Vai ai tuoi budget', 'go_to_categories' => 'Vai alle tue categorie', - 'go_to_bills' => 'Vai alle tue fatture', + 'go_to_bills' => 'Vai alle tue bollette', 'go_to_expense_accounts' => 'Vedi i tuoi conti spese', 'go_to_revenue_accounts' => 'Vedi i tuoi conti entrate', 'go_to_piggies' => 'Vai ai tuoi salvadanai', @@ -59,8 +59,8 @@ return [ 'new_asset_account' => 'Nuova attività conto', 'new_expense_account' => 'Nuova spesa conto', 'new_revenue_account' => 'Nuova entrata conto', - 'new_budget' => 'Nuovo bilancio', - 'new_bill' => 'Nuova fattura', + 'new_budget' => 'Nuovo budget', + 'new_bill' => 'Nuova bolletta', 'block_account_logout' => 'Sei stato disconnesso. Gli account bloccati non possono utilizzare questo sito. Ti sei registrato con un indirizzo email valido?', 'flash_success' => 'Successo!', 'flash_info' => 'Messaggio', @@ -87,7 +87,7 @@ return [ 'warning_much_data' => ':days di caricamento dei dati potrebbero richiedere un pò di tempo.', 'registered' => 'Ti sei registrato con successo!', 'Default asset account' => 'Attività conto predefinito', - 'no_budget_pointer' => 'Sembra che tu non abbia ancora i Bilanci Preventivi. Dovresti crearne alcuni nella pagina bilanci. I bilanci possono aiutarti a tenere traccia delle spese.', + 'no_budget_pointer' => 'Sembra che tu non abbia ancora dei budget. Dovresti crearne alcuni nella pagina budget. I budget possono aiutarti a tenere traccia delle spese.', 'Savings account' => 'Conti risparmio', 'Credit card' => 'Carta di Credito', 'source_accounts' => 'Origine conto(i)', @@ -99,21 +99,21 @@ return [ 'intro_boxes_after_refresh' => 'Le caselle di introduzione riappariranno quando si aggiorna la pagina.', 'show_all_no_filter' => 'Mostra tutte le transazioni senza raggrupparle per data.', 'expenses_by_category' => 'Spese per Categorie', - 'expenses_by_budget' => 'Spese per bilancio', + 'expenses_by_budget' => 'Spese per budget', 'income_by_category' => 'Reddito per categoria', 'expenses_by_asset_account' => 'Spese per attività conto', 'expenses_by_expense_account' => 'Spese per conto spese', 'cannot_redirect_to_account' => 'Spiacente ma Firefly III non può reindirizzarti alla pagina corretta.', 'sum_of_expenses' => 'Totale spese', 'sum_of_income' => 'Totale reddito', - 'spent_in_specific_budget' => 'Speso nel bilancio ":budget"', - 'sum_of_expenses_in_budget' => 'Spesa totale nel bilancio ":budget"', + 'spent_in_specific_budget' => 'Speso nel budget ":budget"', + 'sum_of_expenses_in_budget' => 'Spesa totale nel budget ":budget"', 'left_in_budget_limit' => 'Lasciato a spendere in base al budget', 'current_period' => 'Periodo corrente', 'show_the_current_period_and_overview' => 'Mostra il periodo e la panoramica correnti', 'pref_languages_locale' => 'Affinché una lingua diversa dall\'inglese funzioni correttamente, il sistema operativo deve essere dotato delle corrette informazioni locali. Se questi non sono presenti, i dati di valuta, le date e gli importi potrebbero essere formattati in modo errato.', - 'budget_in_period' => 'Tutte le transazioni per il bilancio ":name" fra :start e :end', - 'chart_budget_in_period' => 'Grafico di tutte le transazioni per Bilancio ":name" fra :start e :end', + 'budget_in_period' => 'Tutte le transazioni per il budget ":name" fra :start e :end', + 'chart_budget_in_period' => 'Grafico di tutte le transazioni per il budget ":name" fra :start e :end', 'chart_account_in_period' => 'Grafico di tutte le transazioni per Conto ":name" fra :start E :end', 'chart_category_in_period' => 'Grafico di tutte le transazioni per Categorie ":name" fra :start e :end', 'chart_category_all' => 'Grafico di tutte le transazioni per Categoria ":name"', @@ -130,8 +130,8 @@ return [ 'intro_skip_label' => 'Salta', 'intro_done_label' => 'Fatto', 'between_dates_breadcrumb' => 'Fra :start e :end', - 'all_journals_without_budget' => 'Tutte le transazioni fuori bilancio', - 'journals_without_budget' => 'Transazioni senza Bilancio', + 'all_journals_without_budget' => 'Tutte le transazioni senza un budget', + 'journals_without_budget' => 'Transazioni senza budget', 'all_journals_without_category' => 'Tutte le transazioni senza una categoria', 'journals_without_category' => 'Transazioni senza categoria', 'all_journals_for_account' => 'Tutte le transazioni per il conto :name', @@ -149,8 +149,8 @@ return [ 'all_journals_for_tag' => 'Tutte le transazioni per Etichetta ":tag"', 'title_transfer_between' => 'Tutti i trasferimenti fra :start e :end', 'all_journals_for_category' => 'Turre le transazioni per categoria :name', - 'all_journals_for_budget' => 'Tutte le transazione per bilancio :name', - 'chart_all_journals_for_budget' => 'Grafico di tutte le transazioni per Bilancio :name', + 'all_journals_for_budget' => 'Tutte le transazione per budget :name', + 'chart_all_journals_for_budget' => 'Grafico di tutte le transazioni per budget :name', 'journals_in_period_for_category' => 'Tutte le transazioni per Categoria :name fra :start e :end', 'journals_in_period_for_tag' => 'Tutte le transazioni per Etichetta :tag fra :start e :end', 'not_available_demo_user' => 'La funzione a cui tenti di accedere non è disponibile per gli utenti demo.', @@ -171,9 +171,9 @@ return [ 'want_to_login' => 'Voglio accedere', 'button_register' => 'Registrare', 'authorization' => 'Autorizzazione', - 'active_bills_only' => 'active bills only', - 'average_per_bill' => 'average per bill', - 'expected_total' => 'expected total', + 'active_bills_only' => 'solo bollette attive', + 'average_per_bill' => 'media per bolletta', + 'expected_total' => 'totale previsto', // API access 'authorization_request' => 'Firefly III v:version Richiesta Autorizzazione', 'authorization_request_intro' => ':client sta richiedendo l\'autorizzazione per accedere alla tua amministrazione finanziaria. Desideri autorizzare :client ad accedere a questi record?', @@ -267,7 +267,10 @@ return [ 'move_rule_group_down' => 'Sposta il gruppo di regole in basso', 'save_rules_by_moving' => 'Salva questa(e) regola(e) spostandola(e) in un altro gruppo di regole:', 'make_new_rule' => 'Crea una nuova regola nel gruppo di regole ":title"', + 'rule_is_strict' => 'regola severa', + 'rule_is_not_strict' => 'regola non severa', 'rule_help_stop_processing' => 'Quando selezioni questa casella, le regole successive in questo gruppo non verranno eseguite.', + 'rule_help_strict' => 'Nelle regole severe TUTTI i trigger devono venire azionati perché l\'azione venga eseguita. Nelle regole non severe, è sufficiente UN QUALSIASI trigger perché l\'azione venga eseguita.', 'rule_help_active' => 'Le regole non attive non spareranno mai.', 'stored_new_rule' => 'Nuova regola memorizzata con titolo ":title"', 'deleted_rule' => 'Regola eliminata con titolo ":title"', @@ -303,7 +306,7 @@ return [ 'execute' => 'Eseguire', 'apply_rule_group_selection' => 'Applica il gruppo di regole ":title" a una selezione delle tue transazioni', 'apply_rule_group_selection_intro' => 'Gruppi di regole come ":title" sono normalmente applicati solo a transazioni nuove o aggiornate, ma puoi dire a Firefly III di eseguire tutte le regole in questo gruppo su una selezione delle tue transazioni esistenti. Questo può essere utile quando hai aggiornato un gruppo di regole e hai bisogno delle modifiche da applicare a tutte le tue altre transazioni.', - 'applied_rule_group_selection' => 'Rule group ":title" has been applied to your selection.', + 'applied_rule_group_selection' => 'Il gruppo di regole ":title" è stato applicato alla selezione.', // actions and triggers 'rule_trigger_user_action' => 'L\'azione dell\'utente è ":trigger_value"', @@ -341,10 +344,12 @@ return [ 'rule_trigger_description_contains' => 'La descrizione contiene ":trigger_value"', 'rule_trigger_description_is_choice' => 'La descrizione è..', 'rule_trigger_description_is' => 'La descrizione è ":trigger_value"', - 'rule_trigger_budget_is_choice' => 'Il bilancio è..', - 'rule_trigger_budget_is' => 'Il bilancio è ":trigger_value"', + 'rule_trigger_budget_is_choice' => 'Il budget è...', + 'rule_trigger_budget_is' => 'Il budget è ":trigger_value"', 'rule_trigger_tag_is_choice' => '(A) tag è..', 'rule_trigger_tag_is' => 'Un tag è ":trigger_value"', + 'rule_trigger_currency_is_choice' => 'La valuta della transazione è...', + 'rule_trigger_currency_is' => 'La valuta della transazione è ":trigger_value"', 'rule_trigger_has_attachments_choice' => 'Ha almeno questo molti allegati', 'rule_trigger_has_attachments' => 'Almeno :trigger_value allegato (i)', 'rule_trigger_store_journal' => 'Quando viene creata una transazione', @@ -353,10 +358,10 @@ return [ 'rule_trigger_has_no_category' => 'La transazione non ha categoria', 'rule_trigger_has_any_category_choice' => 'Ha una (qualsiasi) categoria', 'rule_trigger_has_any_category' => 'La transazione ha una (qualsiasi) categoria', - 'rule_trigger_has_no_budget_choice' => 'Non ha bilancio', - 'rule_trigger_has_no_budget' => 'La transazione non ha bilancio', - 'rule_trigger_has_any_budget_choice' => 'Ha un (qualsiasi) bilancio', - 'rule_trigger_has_any_budget' => 'La transazione ha un (qualsiasi) bilancio', + 'rule_trigger_has_no_budget_choice' => 'Non ha un budget', + 'rule_trigger_has_no_budget' => 'La transazione non ha un budget', + 'rule_trigger_has_any_budget_choice' => 'Ha un budget (qualsiasi)', + 'rule_trigger_has_any_budget' => 'La transazione ha un budget (qualsiasi)', 'rule_trigger_has_no_tag_choice' => 'Non ha etichetta(e)', 'rule_trigger_has_no_tag' => 'La transazione non ha etichetta(e)', 'rule_trigger_has_any_tag_choice' => 'Ha una o più etichette (qualsiasi)', @@ -375,8 +380,8 @@ return [ 'rule_trigger_notes_end' => 'Le note finiscono con ":trigger_value"', 'rule_action_set_category' => 'Imposta categoria a ":action_value"', 'rule_action_clear_category' => 'Cancella categoria', - 'rule_action_set_budget' => 'Imposta il bilancio su ":action_value"', - 'rule_action_clear_budget' => 'Cancella bilancio', + 'rule_action_set_budget' => 'Imposta il budget su ":action_value"', + 'rule_action_clear_budget' => 'Cancella budget', 'rule_action_add_tag' => 'Aggiungi etichetta ":action_value"', 'rule_action_remove_tag' => 'Rimuovi etichetta ":action_value"', 'rule_action_remove_all_tags' => 'Rimuovi tutte le etichette', @@ -385,8 +390,8 @@ return [ 'rule_action_prepend_description' => 'Anteporre descrizione con ":action_value"', 'rule_action_set_category_choice' => 'Imposta categoria a..', 'rule_action_clear_category_choice' => 'Cancella qualsiasi categoria', - 'rule_action_set_budget_choice' => 'Imposta il bilancio su..', - 'rule_action_clear_budget_choice' => 'Cancella qualsiasi bilancio', + 'rule_action_set_budget_choice' => 'Imposta il budget su...', + 'rule_action_clear_budget_choice' => 'Cancella qualsiasi budget', 'rule_action_add_tag_choice' => 'Aggiungi etichetta..', 'rule_action_remove_tag_choice' => 'Rimuovi etichetta..', 'rule_action_remove_all_tags_choice' => 'Rimuovi tutte le etichette', @@ -404,10 +409,20 @@ return [ 'rule_action_clear_notes_choice' => 'Rimuovi eventuali note', 'rule_action_clear_notes' => 'Rimuovi eventuali note', 'rule_action_set_notes_choice' => 'Imposta le note su..', + 'rule_action_link_to_bill_choice' => 'Collega ad una bolletta...', + 'rule_action_link_to_bill' => 'Collegamento alla bolletta ":action_value"', 'rule_action_set_notes' => 'Imposta le note su ":action_value"', 'rules_have_read_warning' => 'Hai letto l\'avvertimento?', 'apply_rule_warning' => 'Avvertenza: l\'esecuzione di una regola (gruppo) su una vasta selezione di transazioni potrebbe richiedere anni e potrebbe scadere. In caso affermativo, la regola (gruppo) verrà applicata solo a un sottoinsieme sconosciuto delle tue transazioni. Questo potrebbe lasciare la tua amministrazione finanziaria a brandelli. Fate attenzione.', + 'rulegroup_for_bills_title' => 'Gruppo di regole per le bollette', + 'rulegroup_for_bills_description' => 'Un gruppo di regole speciale per tutte le regole che coinvolgono le bollette.', + 'rule_for_bill_title' => 'Regole generata automaticamente per la bolletta ":name"', + 'rule_for_bill_description' => 'Questa regola è generata automaticamente per l\'abbinamento con la bolletta ":name".', + 'create_rule_for_bill' => 'Crea una nuova regola per la bolletta ":name"', + 'create_rule_for_bill_txt' => 'Contratulazioni, hai appena creato una nuova bolletta chiamata ":name"! Firefly III può automagicamente abbinare le nuove uscite a questa bolletta. Per esempio, ogni volta che paghi l\'affitto la bolletta "affitto" verrà collegata a questa spesa. In questo modo Firefly III può visualizzare con accuratezza quali bollette sono in scadenza e quali no. Per far ciò è necessario creare una nuova regola. Firefly III ha inserito al posto tuo alcuni dettagli ragionevoli. Assicurati che questi siano corretti. Se questi valori sono corretti, Firefly III automaticamente collegherà la spesa giusta alla bolletta giusta. Controlla che i trigger siano corretti e aggiungene altri se sono sbagliati.', + 'new_rule_for_bill_title' => 'Regola per la bolletta ":name"', + 'new_rule_for_bill_description' => 'Questa regola contrassegna le transazioni per la bolletta ":name".', // tags 'store_new_tag' => 'Salva la nuova etichetta', @@ -447,7 +462,7 @@ return [ 'pref_two_factor_auth_code' => 'Verificare il codice', 'pref_two_factor_auth_code_help' => 'Esegui la scansione del codice QR con un\'applicazione sul tuo telefono come Authy o Google Authenticator e inserisci il codice generato.', 'pref_two_factor_auth_reset_code' => 'Reimposta il codice di verifica', - 'pref_two_factor_auth_disable_2fa' => 'Disable 2FA', + 'pref_two_factor_auth_disable_2fa' => 'Disattiva 2FA', 'pref_save_settings' => 'Salva le impostazioni', 'saved_preferences' => 'Preferenze salvate!', 'preferences_general' => 'Generale', @@ -472,7 +487,7 @@ return [ 'pref_optional_tj_process_date' => 'Data di lavorazione', 'pref_optional_tj_due_date' => 'Scadenza', 'pref_optional_tj_payment_date' => 'Data di pagamento', - 'pref_optional_tj_invoice_date' => 'Data fattura', + 'pref_optional_tj_invoice_date' => 'Data bolletta', 'pref_optional_tj_internal_reference' => 'Riferimento interno', 'pref_optional_tj_notes' => 'Note', 'pref_optional_tj_attachments' => 'Allegati', @@ -577,7 +592,7 @@ return [ 'create_new_expense' => 'Crea un nuovo conto di spesa', 'create_new_revenue' => 'Crea un nuovo conto di entrate', 'create_new_piggy_bank' => 'Crea un nuovo salvadanaio', - 'create_new_bill' => 'Crea una nuova fattura', + 'create_new_bill' => 'Crea una nuova bolletta', // currencies: 'create_currency' => 'Crea una nuova valuta', @@ -599,55 +614,56 @@ return [ 'options' => 'Opzioni', // budgets: - 'create_new_budget' => 'Crea nuovo bilancio', - 'store_new_budget' => 'Salva il nuovo bilancio', - 'stored_new_budget' => 'Nuovo bilancio salvato ":name"', + 'create_new_budget' => 'Crea nuovo budget', + 'store_new_budget' => 'Salva il nuovo budget', + 'stored_new_budget' => 'Nuovo budget salvato ":name"', 'available_between' => 'Disponibile tra :start e :end', - 'transactionsWithoutBudget' => 'Spese senza bilancio', - 'transactions_no_budget' => 'Spese senza bilancio tra :start e :end', + 'transactionsWithoutBudget' => 'Spese senza budget', + 'transactions_no_budget' => 'Spese senza budget tra :start e :end', 'spent_between' => 'Speso tra :start e :end', - 'createBudget' => 'Nuovo bilancio', - 'inactiveBudgets' => 'Bilanci disattivati', - 'without_budget_between' => 'Transazioni senza un bilancio tra :start e :end', - 'delete_budget' => 'Elimina Bilancio ":name"', - 'deleted_budget' => 'Bilancio eliminato ":name"', - 'edit_budget' => 'Modifica Bilancio ":name"', - 'updated_budget' => 'Bilancio aggiornato ":name"', + 'createBudget' => 'Nuovo budget', + 'inactiveBudgets' => 'Budget disattivati', + 'without_budget_between' => 'Transazioni senza un budget tra :start e :end', + 'delete_budget' => 'Elimina budget ":name"', + 'deleted_budget' => 'Budget eliminato ":name"', + 'edit_budget' => 'Modifica budget ":name"', + 'updated_budget' => 'Budget aggiornato ":name"', 'update_amount' => 'Importo aggiornato', - 'update_budget' => 'Bilancio aggiornato', + 'update_budget' => 'Budget aggiornato', 'update_budget_amount_range' => 'Aggiornamento (previsto) importo disponibile tra :start and :end', 'budget_period_navigator' => 'Navigatore periodico', 'info_on_available_amount' => 'Cosa ho a disposizione?', 'available_amount_indication' => 'Utilizza questi importi per ottenere un\'indicazione di quale potrebbe essere il tuo budget totale.', 'suggested' => 'Consigliato', 'average_between' => 'Media tra :start e :end', - 'over_budget_warn' => ' Normally you budget about :amount per day. This is :over_amount per day.', + 'over_budget_warn' => 'Normalmente il tuo budget giornaliero è :amount. Questo è :over_amount al giorno.', // bills: - 'matching_on' => 'Accoppiamento', - 'between_amounts' => 'fra :low e :high.', + 'match_between_amounts' => 'La bolletta abbina le transazioni tra :low e :high.', + 'bill_related_rules' => 'Regole relative a questa bolletta', 'repeats' => 'Ripeti', 'connected_journals' => 'Transazioni connesse', 'auto_match_on' => 'Abbinato automaticamente da Firefly III', 'auto_match_off' => 'Non abbinato automaticamente a Firefly III', 'next_expected_match' => 'Prossima partita prevista', - 'delete_bill' => 'Elimina fattura ":name"', - 'deleted_bill' => 'Fattura eliminata ":name"', - 'edit_bill' => 'Modifica fattura ":name"', + 'delete_bill' => 'Elimina bolletta ":name"', + 'deleted_bill' => 'Bolletta eliminata ":name"', + 'edit_bill' => 'Modifica bolletta ":name"', 'more' => 'Altro', - 'rescan_old' => 'Riscansiona vecchie transazioni', - 'update_bill' => 'Aggiorna fattura', - 'updated_bill' => 'Fattura aggiornata ":name"', - 'store_new_bill' => 'Salva la nuova fattura', - 'stored_new_bill' => 'Nuova fattura memorizzata ":name"', - 'cannot_scan_inactive_bill' => 'Le fatture non attive non possono essere scansionate.', - 'rescanned_bill' => 'Riscritto tutto.', - 'average_bill_amount_year' => 'Importo medio della fattura (:year)', - 'average_bill_amount_overall' => 'Importo medio della fattura (totale)', - 'bill_is_active' => 'Fattura attiva', + 'rescan_old' => 'Esegui nuovamente le regole su tutte le transazioni', + 'update_bill' => 'Aggiorna bolletta', + 'updated_bill' => 'Bolletta aggiornata ":name"', + 'store_new_bill' => 'Salva la nuova bolletta', + 'stored_new_bill' => 'Nuova bolletta memorizzata ":name"', + 'cannot_scan_inactive_bill' => 'Le bollette non attive non possono essere scansionate.', + 'rescanned_bill' => 'È stato riscansionato tutto e :total transazioni sono state collegate alla bolletta.', + 'average_bill_amount_year' => 'Importo medio della bolletta (:year)', + 'average_bill_amount_overall' => 'Importo medio della bolletta (totale)', + 'bill_is_active' => 'Bolletta attiva', 'bill_expected_between' => 'Previsto tra :start e :end', - 'bill_will_automatch' => 'La ricevuta verrà automaticamente collegata alle transazioni corrispondenti', + 'bill_will_automatch' => 'La bolletta verrà automaticamente collegata alle transazioni corrispondenti', 'skips_over' => 'salta sopra', + 'bill_store_error' => 'Si è verificato un errore imprevisto durante la memorizzazione della nuova bolletta. Controlla i file di log', // accounts: 'details_for_asset' => 'Dettagli per conto attività ":name"', @@ -680,7 +696,7 @@ return [ 'reconcile_account' => 'Riconciliazione conto ":account"', 'delete_reconciliation' => 'Elimina riconciliazione', 'update_reconciliation' => 'Aggiorna riconciliazione', - 'amount_cannot_be_zero' => 'The amount cannot be zero', + 'amount_cannot_be_zero' => 'L\'importo non può essere zero', 'end_of_reconcile_period' => 'Fine periodo riconciliazione: :period', 'start_of_reconcile_period' => 'Inizio periodo riconciliazione: :period', 'start_balance' => 'Saldo inizio', @@ -707,7 +723,7 @@ return [ 'no_data_for_chart' => 'Non ci sono (ancora) abbastanza informazioni per generare questo grafico.', 'select_more_than_one_account' => 'Si prega di selezionare più di un conto', 'select_more_than_one_category' => 'Si prega di selezionare più di una categoria', - 'select_more_than_one_budget' => 'Si prega di selezionare più di un bilancio', + 'select_more_than_one_budget' => 'Si prega di selezionare più di un budget', 'select_more_than_one_tag' => 'Si prega di selezionare più di una etichetta', 'account_default_currency' => 'Se selezioni un\'altra valuta, le nuove transazioni di questo conto avranno questa valuta predefinita.', 'reconcile_has_more' => 'Il tuo conto Firefly III ha più denaro irispetto a quanto afferma la tua banca. Ci sono diverse opzioni Si prega di scegliere cosa fare. Quindi, premere "Conferma riconciliazione".', @@ -766,10 +782,10 @@ return [ 'mass_delete_journals' => 'Elimina un numero di transazioni', 'mass_edit_journals' => 'Modifica un numero di transazioni', 'mass_bulk_journals' => 'Modifica in blocco un numero di transazioni', - 'mass_bulk_journals_explain' => 'Se non si desidera modificare le transazioni una alla volta utilizzando la funzione di modifica di massa, è possibile aggiornarle in una volta sola. Basta selezionare la categoria, le etichette o il bilancio preferiti nei campi sottostanti e tutte le transazioni nella tabella verranno aggiornate.', - 'bulk_set_new_values' => 'Usa gli inserimenti qui sotto per impostare nuovi valori. Se li lasci vuoti, saranno resi vuoti per tutti. Inoltre, si noti che solo i prelievi avranno un bilancio.', + 'mass_bulk_journals_explain' => 'Se non si desidera modificare le transazioni una alla volta utilizzando la funzione di modifica di massa, è possibile aggiornarle in una volta sola. Basta selezionare le categorie, le etichette o i budget preferiti nei campi sottostanti e tutte le transazioni nella tabella verranno aggiornate.', + 'bulk_set_new_values' => 'Usa gli inserimenti qui sotto per impostare nuovi valori. Se li lasci vuoti, saranno resi vuoti per tutti. Inoltre, si noti che solo i prelievi avranno un budget.', 'no_bulk_category' => 'Non aggiornare la categoria', - 'no_bulk_budget' => 'Non aggiornare il bilancio', + 'no_bulk_budget' => 'Non aggiornare il budget', 'no_bulk_tags' => 'Non aggiornare la(e) etichetta(e)', 'bulk_edit' => 'Modifica collettiva', 'cannot_edit_other_fields' => 'Non puoi modificare in massa altri campi oltre a quelli qui, perché non c\'è spazio per mostrarli. Segui il link e modificali uno per uno, se è necessario modificare questi campi.', @@ -784,6 +800,7 @@ return [ 'opt_group_sharedAsset' => 'Conti risorse condivise', 'opt_group_ccAsset' => 'Carte di credito', 'notes' => 'Note', + 'unknown_journal_error' => 'Impossibile memorizzare la transazione. Controllare i file di log.', // new user: 'welcome' => 'Benvenuto in Firefly III!', @@ -793,6 +810,10 @@ return [ 'savings_balance_text' => 'Firefly III creerà automaticamente un conto di risparmio per te. Per impostazione predefinita, non ci saranno soldi nel tuo conto di risparmio, ma se comunichi a Firefly III il saldo verrà archiviato come tale.', 'finish_up_new_user' => 'Questo è tutto! Puoi continuare premendo Invia. Verrai indirizzato all\'indice di Firefly III.', 'stored_new_accounts_new_user' => 'I tuoi nuovi conti sono stati salvati.', + 'set_preferred_language' => 'Se preferisci usare Firefly III in un\'altra lingua, impostala qui.', + 'language' => 'Lingua', + 'new_savings_account' => 'Conto di risparmio :bank_name', + 'cash_wallet' => 'Contanti', // home page: 'yourAccounts' => 'I tuoi conti', @@ -801,10 +822,10 @@ return [ 'newWithdrawal' => 'Nuova uscita', 'newDeposit' => 'Nuovo deposito', 'newTransfer' => 'Nuovo giroconto', - 'bills_to_pay' => 'Fatture da pagare', + 'bills_to_pay' => 'Bollette da pagare', 'per_day' => 'Al giorno', 'left_to_spend_per_day' => 'Spese al giorno', - 'bills_paid' => 'Fatture pagate', + 'bills_paid' => 'Bollette pagate', // menu and titles, should be recycled as often as possible: 'currency' => 'Valuta', @@ -823,14 +844,14 @@ return [ 'Initial balance account' => 'Saldo iniziale conto', 'budgets' => 'Bilanci', 'tags' => 'Etichette', - 'reports' => 'Stampe', + 'reports' => 'Resoconti', 'transactions' => 'Transazioni', 'expenses' => 'Spese', 'income' => 'Reddito / Entrata', 'transfers' => 'Trasferimenti', 'moneyManagement' => 'Gestione danaro', 'piggyBanks' => 'Salvadanai', - 'bills' => 'Fatture', + 'bills' => 'Bollette', 'withdrawal' => 'Uscite', 'opening_balance' => 'Saldo di apertura', 'deposit' => 'Entrata', @@ -839,7 +860,7 @@ return [ 'Withdrawal' => 'Spesa', 'Deposit' => 'Entrata', 'Transfer' => 'Giroconto', - 'bill' => 'Fattura', + 'bill' => 'Bolletta', 'yes' => 'Si', 'no' => 'No', 'amount' => 'Conto', @@ -852,20 +873,20 @@ return [ 'errors' => 'Errori', // reports: - 'report_default' => 'Stampa predefinita delle tue finanze tra :start e :end', + 'report_default' => 'Resoconto predefinito delle tue finanze tra :start e :end', 'report_audit' => 'Panoramica cronologica delle transazioni tra :start e :end', - 'report_category' => 'Stampa categoria tra :start e :end', - 'report_account' => 'Stampa Conti spese / entrate tra :start e :end', - 'report_budget' => 'Stampa Bilancio tra :start e :end', - 'report_tag' => 'Stampa etichetta tra :start e :end', + 'report_category' => 'Resoconto categoria tra :start e :end', + 'report_account' => 'Resoconto conto spese/entrate tra :start e :end', + 'report_budget' => 'Resoconto budget tra :start e :end', + 'report_tag' => 'Resoconto etichetta tra :start e :end', 'quick_link_reports' => 'Collegamenti veloci', - 'quick_link_default_report' => 'Stampa finanze predefinita', + 'quick_link_default_report' => 'Resoconto finanziario predefinito', 'quick_link_audit_report' => 'Panoramica cronologica delle transazioni', 'report_this_month_quick' => 'Mese corrente - tutti i conti', 'report_this_year_quick' => 'Anno corrente - tutti i conti', 'report_this_fiscal_year_quick' => 'Anno fiscale corrente - tutti i conti', 'report_all_time_quick' => 'Sempre tutti i conti', - 'reports_can_bookmark' => 'Ricorda che le stampe possono essere aggiunte ai segnalibri.', + 'reports_can_bookmark' => 'Ricorda che i resoconti possono essere aggiunti ai segnalibri.', 'incomeVsExpenses' => 'Entrate verso spese', 'accountBalances' => 'Saldo dei conti', 'balanceStart' => 'Saldo inizio periodo', @@ -873,7 +894,7 @@ return [ 'splitByAccount' => 'Dividi per conto', 'coveredWithTags' => 'Coperto con etichetta', 'leftUnbalanced' => 'Sbilanciato a sinistra', - 'leftInBudget' => 'Rimasto nel bilancio', + 'leftInBudget' => 'Rimasto nel budget', 'sumOfSums' => 'Somma dei conti', 'noCategory' => '(nessuna categoria)', 'notCharged' => 'Non caricato (ancora)', @@ -885,14 +906,14 @@ return [ 'topX' => 'Superiore :number', 'show_full_list' => 'Mostra elenco completo', 'show_only_top' => 'Mostra solo in alto :number', - 'report_type' => 'Tipo stampa', - 'report_type_default' => 'Stampa finanze predefinita', + 'report_type' => 'Tipo resoconto', + 'report_type_default' => 'Resoconto finanziario predefinito', 'report_type_audit' => 'Panoramica cronologica delle transazioni (controllo)', - 'report_type_category' => 'Stampa categoria', - 'report_type_budget' => 'Stampa bilancio', - 'report_type_tag' => 'Stampa etichetta', - 'report_type_account' => 'Stampa conto spese / entrate', - 'more_info_help' => 'Ulteriori informazioni su questi tipi distampe sono disponibili nelle pagine della guida. Premi l\'icona (?) Nell\'angolo in alto a destra.', + 'report_type_category' => 'Resoconto categoria', + 'report_type_budget' => 'Resoconto budget', + 'report_type_tag' => 'Resoconto etichetta', + 'report_type_account' => 'Resoconto conto spese/entrate', + 'more_info_help' => 'Ulteriori informazioni su questi tipi di resoconti sono disponibili nelle pagine della guida. Premi l\'icona (?) nell\'angolo in alto a destra.', 'report_included_accounts' => 'Conti inclusi', 'report_date_range' => 'Date intervallo', 'report_preset_ranges' => 'Intervalli preimpostati', @@ -901,20 +922,20 @@ return [ 'income_entry' => 'Entrate del conto ":name" tra :start e :end', 'expense_entry' => 'Spese per il conto ":name" tra :start e :end', 'category_entry' => 'Spese nella categoria ":name" tra :start e :end', - 'budget_spent_amount' => 'Spese di bilancio ":budget" tra :start e :end', - 'balance_amount' => 'Spese nel bilancio ":budget" pagate dal conto ":account" tra :start e :end', + 'budget_spent_amount' => 'Spese nel budget ":budget" tra :start e :end', + 'balance_amount' => 'Spese nel budget ":budget" pagate dal conto ":account" tra :start e :end', 'no_audit_activity' => 'Nessuna attività è stata registrata nel conto :account_name tra :start e :end.', 'audit_end_balance' => 'Il saldo del conto di :account_name alla fine di :end era: :balance', 'reports_extra_options' => 'Opzioni extra', - 'report_has_no_extra_options' => 'Questa stampa non ha opzioni extra', - 'reports_submit' => 'Mostra stampa', - 'end_after_start_date' => 'La data della fine della stampa deve essere successiva alla data di inizio.', + 'report_has_no_extra_options' => 'Questo resoconto non ha opzioni extra', + 'reports_submit' => 'Mostra resoconto', + 'end_after_start_date' => 'La data della fine del resoconto deve essere successiva alla data di inizio.', 'select_category' => 'Seleziona la(e) categoria (e)', - 'select_budget' => 'Seleziona il(i) bilancio(i).', + 'select_budget' => 'Seleziona i budget.', 'select_tag' => 'Seleziona etichetta(e).', 'income_per_category' => 'Reddito per categoria', 'expense_per_category' => 'Spese per categoria', - 'expense_per_budget' => 'Spese per bilancio', + 'expense_per_budget' => 'Spese per budget', 'income_per_account' => 'Reddito per conto', 'expense_per_account' => 'Spese per conto', 'expense_per_tag' => 'Spese per etichetta', @@ -941,19 +962,20 @@ return [ 'account_role_sharedAsset' => 'Conto attività condiviso', 'account_role_savingAsset' => 'Conto risparmio', 'account_role_ccAsset' => 'Carta di credito', - 'budget_chart_click' => 'Fai clic su un nome del bilancio nella tabella sopra per vedere un grafico.', + 'account_role_cashWalletAsset' => 'Portafoglio', + 'budget_chart_click' => 'Fai clic su un nome di un budget nella tabella sopra per vedere un grafico.', 'category_chart_click' => 'Fare clic sul nome di una categoria nella tabella sopra per vedere un grafico.', 'in_out_accounts' => 'Guadagnati e spesi per combinazione', 'in_out_per_category' => 'Guadagnati e spesi per categoria', - 'out_per_budget' => 'Speso per bilancio', + 'out_per_budget' => 'Speso per budget', 'select_expense_revenue' => 'Seleziona conto spese / entrate', // charts: 'chart' => 'Grafico', 'month' => 'Mese', - 'budget' => 'Bilancio', + 'budget' => 'Budget', 'spent' => 'Speso', - 'spent_in_budget' => 'Speso in bilancio', + 'spent_in_budget' => 'Speso nel budget', 'left_to_spend' => 'Altro da spendere', 'earned' => 'Guadagnato', 'overspent' => 'Speso troppo', @@ -1000,6 +1022,7 @@ return [ 'events' => 'Eventi', 'target_amount' => 'Importo obiettivo', 'start_date' => 'Data inizio', + 'no_start_date' => 'No start date', 'target_date' => 'Data fine', 'no_target_date' => 'Nessuna data fine', 'table' => 'Tabella', @@ -1039,8 +1062,8 @@ return [ 'user_data_information' => 'Dati utente', 'user_information' => 'Informazioni Utente', 'total_size' => 'dimensione totale', - 'budget_or_budgets' => 'bilancio(i)', - 'budgets_with_limits' => 'bilancio(i) con importo configurato', + 'budget_or_budgets' => 'budget', + 'budgets_with_limits' => 'budget con importo configurato', 'nr_of_rules_in_total_groups' => 'regola(e) :count_rules in gruppo(i) :count_groups', 'tag_or_tags' => 'etichetta(e)', 'configuration_updated' => 'La configurazione è stata aggiornata', @@ -1086,7 +1109,7 @@ return [ 'invalid_link_selection' => 'Impossibile collegare queste transazioni', 'journals_linked' => 'Le transazioni sono collegate.', 'journals_error_linked' => 'Queste transazioni sono già collegate.', - 'journals_link_to_self' => 'You cannot link a transaction to itself', + 'journals_link_to_self' => 'Non puoi collegare una transazione con se stessa', 'journal_links' => 'Collegamenti di transazione', 'this_withdrawal' => 'Questa spesa', 'this_deposit' => 'Questa entrata', @@ -1136,6 +1159,14 @@ return [ 'import_index_title' => 'Importa i dati in Firefly III', 'import_index_sub_title' => 'Indice', 'import_general_index_intro' => 'Benvenuti nella routine di importazione di Firefly III. Esistono alcuni modi per importare dati in Firefly III, visualizzati qui come pulsanti.', + 'upload_error' => 'Il file che hai caricato non può essere elaborato. Probabilmente è un tipo di file o una codifica non valida. I file di log avranno maggiori informazioni.', + 'reset_import_settings_title' => 'Reset import configuration', + 'reset_import_settings_text' => 'You can use these links to reset your import settings for specific providers. This is useful when bad settings stop you from importing data.', + 'reset_settings_bunq' => 'Remove bunq API key, local external IP address and bunq related RSA keys.', + 'reset_settings_spectre' => 'Remove Spectre client ID, service secret and app secret. This will also remove your Spectre keypair. Remember to update the new one.', + 'settings_reset_for_bunq' => 'Bunq settings reset.', + 'settings_reset_for_spectre' => 'Spectre settings reset.', + // sandstorm.io errors and messages: 'sandstorm_not_available' => 'Questa funzione non è disponibile quando si utilizza Firefly III in un ambiente Sandstorm.io.', @@ -1153,10 +1184,10 @@ return [ 'no_accounts_intro_revenue' => 'Non hai ancora un conto entrate. I conti delle entrate sono i luoghi in cui ricevi denaro, come il tuo stipendio e altre entrate.', 'no_accounts_imperative_revenue' => 'I conti entrate vengono creati automaticamente quando si creano le transazioni, ma è possibile crearne anche manualmente, se lo si desidera. Ne creiamo uno ora:', 'no_accounts_create_revenue' => 'Crea conto entrate', - 'no_budgets_title_default' => 'Creiamo un conto bilancio', - 'no_budgets_intro_default' => 'Non hai ancora i bilanci. I bilanci sono usati per organizzare le tue spese in gruppi logici, che puoi dare un indicazione per limitare le tue spese.', - 'no_budgets_imperative_default' => 'I bilanci sono gli strumenti di base della gestione finanziaria. Ne creiamo uno ora:', - 'no_budgets_create_default' => 'Crea bilancio', + 'no_budgets_title_default' => 'Creiamo un budget', + 'no_budgets_intro_default' => 'Non hai ancora budget. I budget sono usati per organizzare le tue spese in gruppi logici, ai quali puoi dare un tetto indicativo per limitare le tue spese.', + 'no_budgets_imperative_default' => 'I budget sono gli strumenti di base della gestione finanziaria. Creiamone uno ora:', + 'no_budgets_create_default' => 'Crea budget', 'no_categories_title_default' => 'Creaiamo una categoria!', 'no_categories_intro_default' => 'Non hai ancora categorie. Le categorie vengono utilizzate per mettere a punto le transazioni e etichettarle con la categoria designata.', 'no_categories_imperative_default' => 'Le categorie vengono create automaticamente quando si creano le transazioni, ma è possibile crearne anche manualmente. Ne creiamo una ora:', @@ -1181,8 +1212,8 @@ return [ 'no_piggies_intro_default' => 'Non hai ancora salvadanai. Puoi creare salvadanai per dividere i tuoi risparmi e tenere traccia di ciò per cui stai risparmiando.', 'no_piggies_imperative_default' => 'Hai cose per le quali stai risparmiando? Crea un salvadanaio e tieni traccia:', 'no_piggies_create_default' => 'Crea un nuovo salvadanaio', - 'no_bills_title_default' => 'Creiamo una fattura!', - 'no_bills_intro_default' => 'Non hai ancora nessuna fattura. Puoi creare fatture per tenere traccia delle spese regolari, come il tuo affitto o l\'assicurazione.', - 'no_bills_imperative_default' => 'Hai delle fatture regolari? Crea una fattura e tieni traccia dei tuoi pagamenti:', - 'no_bills_create_default' => 'Crea fattura', + 'no_bills_title_default' => 'Creiamo una bolletta!', + 'no_bills_intro_default' => 'Non hai ancora nessuna bolletta. Puoi creare bollette per tenere traccia delle spese regolari, come il tuo affitto o l\'assicurazione.', + 'no_bills_imperative_default' => 'Hai delle bollette regolari? Crea una bolletta e tieni traccia dei tuoi pagamenti:', + 'no_bills_create_default' => 'Crea bolletta', ]; diff --git a/resources/lang/it_IT/form.php b/resources/lang/it_IT/form.php index c8e80cd94a..c6e2274a58 100644 --- a/resources/lang/it_IT/form.php +++ b/resources/lang/it_IT/form.php @@ -1,5 +1,6 @@ 'Importo minimo', 'amount_max' => 'Importo massimo', 'match' => 'Partite su', + 'strict' => 'Modalità severa', 'repeat_freq' => 'Ripetizioni', 'journal_currency_id' => 'Valuta', 'currency_id' => 'Valuta', + 'transaction_currency_id' => 'Valuta', + 'external_ip' => 'L\'IP esterno del tuo server', 'attachments' => 'Allegati', 'journal_amount' => 'Importo', 'journal_source_account_name' => 'Conto entrate (origine)', @@ -53,7 +57,7 @@ return [ 'split_journal_explanation' => 'Dividi questa transazione in più parti', 'currency' => 'Valuta', 'account_id' => 'Conto attività', - 'budget_id' => 'Bilancio', + 'budget_id' => 'Budget', 'openingBalance' => 'Saldo di apertura', 'tagMode' => 'Modalità etichetta', 'tag_position' => 'Posizione etichetta', @@ -133,8 +137,8 @@ return [ 'include_old_uploads' => 'Includi dati importati', 'accounts' => 'Esporta le transazioni da questi conti', 'delete_account' => 'Elimina conto ":name"', - 'delete_bill' => 'Elimina fattura ":name"', - 'delete_budget' => 'Elimina bilancio ":name"', + 'delete_bill' => 'Elimina bolletta ":name"', + 'delete_budget' => 'Elimina budget ":name"', 'delete_category' => 'Elimina categoria ":name"', 'delete_currency' => 'Elimina valuta ":name"', 'delete_journal' => 'Elimina transazione con descrizione ":description"', @@ -149,7 +153,7 @@ return [ 'bill_areYouSure' => 'Sei sicuro di voler eliminare il conto ":name"?', 'rule_areYouSure' => 'Sei sicuro di voler eliminare la regola ":title"?', 'ruleGroup_areYouSure' => 'Sei sicuro di voler eliminare il gruppo regole ":title"?', - 'budget_areYouSure' => 'Sei sicuro di voler eliminare il bilancio ":name"?', + 'budget_areYouSure' => 'Sei sicuro di voler eliminare il budget ":name"?', 'category_areYouSure' => 'Sei sicuro di voler eliminare categoria ":name"?', 'currency_areYouSure' => 'Sei sicuro di voler eliminare la valuta ":name"?', 'piggyBank_areYouSure' => 'Sei sicuro di voler eliminare il salvadanaio ":name"?', @@ -166,8 +170,8 @@ return [ 'also_delete_connections' => 'L\'unica transazione collegata a questo tipo di collegamento perderà questa connessione. | Tutto :count le transazioni di conteggio collegate a questo tipo di collegamento perderanno la connessione.', 'also_delete_rules' => 'Anche l\'unica regola collegata a questo gruppo di regole verrà eliminata. | Tutto :count verranno eliminate anche le regole di conteggio collegate a questo gruppo di regole.', 'also_delete_piggyBanks' => 'Verrà eliminato anche l\'unico salvadanaio collegato a questo conto. | Tutti :count il conteggio del salvadanaio collegato a questo conto verrà eliminato.', - 'bill_keep_transactions' => 'L\'unica transazione connessa a questa fattura non verrà eliminata. | Tutto :count le transazioni del conto collegate a questa fattura non verranno cancellate.', - 'budget_keep_transactions' => 'L\'unica transazione collegata a questo bilancio non verrà eliminata. | Tutto :count le transazioni del conto collegate a questo bilancio non verranno cancellate.', + 'bill_keep_transactions' => 'L\'unica transazione connessa a questa bolletta non verrà eliminata. | Tutte le :count transazioni del conto collegate a questa bolletta non verranno cancellate.', + 'budget_keep_transactions' => 'L\'unica transazione collegata a questo budget non verrà eliminata. | Tutte le :count transazioni del conto collegate a questo budget non verranno cancellate.', 'category_keep_transactions' => 'L\'unica transazione collegata a questa categoria non verrà eliminata. | Tutto :count le transazioni del conto collegate a questa categoria non verranno cancellate.', 'tag_keep_transactions' => 'L\'unica transazione connessa a questa etichetta non verrà eliminata. | Tutto :count le transazioni del conto collegate a questa etichetta non verranno cancellate.', 'check_for_updates' => 'Controlla gli aggiornamenti', @@ -202,7 +206,7 @@ return [ 'due_date' => 'Data scadenza', 'payment_date' => 'Data pagamento', - 'invoice_date' => 'Data fattura', + 'invoice_date' => 'Data bolletta', 'internal_reference' => 'Referenze interne', 'inward' => 'Descrizione interna', 'outward' => 'Descrizione esterna', diff --git a/resources/lang/it_IT/import.php b/resources/lang/it_IT/import.php index d2b1454508..98baea5e85 100644 --- a/resources/lang/it_IT/import.php +++ b/resources/lang/it_IT/import.php @@ -75,13 +75,13 @@ return [ 'csv_initial_date_help' => 'Formato della data e ora nel tuo CSV. Segui il formato indica questa pagina. Il valore predefinito analizzerà le date che assomigliano a questo: :dateExample.', 'csv_initial_delimiter_help' => 'Scegli il delimitatore di campo che viene utilizzato nel file di input. Se non si è sicuri, la virgola è l\'opzione più sicura.', 'csv_initial_import_account_help' => 'Se il tuo file CSV NON contiene informazioni sui tuoi conti di attività, utilizza questo menu a discesa per selezionare a quale conto appartengono le transazioni nel CSV.', - 'csv_initial_submit' => 'Continue with step 3/4', + 'csv_initial_submit' => 'Continua con il passo 3/4', // file, new options: 'file_apply_rules_title' => 'Applica regole', 'file_apply_rules_description' => 'Applica le tue regole. Si noti che questo rallenta l\'importazione in modo significativo.', - 'file_match_bills_title' => 'Abbina le fatture', - 'file_match_bills_description' => 'Abbina le tue fatture ai prelievi di nuova creazione. Si noti che questo rallenta l\'importazione in modo significativo.', + 'file_match_bills_title' => 'Abbina le bollette', + 'file_match_bills_description' => 'Abbina le tue bollette ai prelievi di nuova creazione. Si noti che questo rallenta l\'importazione in modo significativo.', // file, roles config 'csv_roles_title' => 'Importa configurazione (3/4) - Definisci il ruolo di ogni colonna', @@ -120,8 +120,8 @@ return [ 'column_amount-comma-separated' => 'Importo (virgola come separatore decimale)', 'column_bill-id' => 'ID conto (matching FF3)', 'column_bill-name' => 'Nome conto', - 'column_budget-id' => 'ID Bilancio (matching FF3)', - 'column_budget-name' => 'Nome bilancio', + 'column_budget-id' => 'ID budget (matching FF3)', + 'column_budget-name' => 'Nome budget', 'column_category-id' => 'ID Categoria (matching FF3)', 'column_category-name' => 'Nome categoria', 'column_currency-code' => 'Codice valuta (ISO 4217)', @@ -133,12 +133,12 @@ return [ 'column_date-book' => 'Data prenotazione della transazione', 'column_date-process' => 'Data processo della transazione', 'column_date-transaction' => 'Data', - 'column_date-due' => 'Transaction due date', - 'column_date-payment' => 'Transaction payment date', - 'column_date-invoice' => 'Transaction invoice date', + 'column_date-due' => 'Data di scadenza della transazione', + 'column_date-payment' => 'Data di pagamento della transazione', + 'column_date-invoice' => 'Data di fatturazione della transazione', 'column_description' => 'Descrizione', 'column_opposing-iban' => 'Conto opposto (IBAN)', - 'column_opposing-bic' => 'Opposing account (BIC)', + 'column_opposing-bic' => 'Conto della controparte (BIC)', 'column_opposing-id' => 'ID Conto opposto (matching FF3)', 'column_external-id' => 'ID esterno', 'column_opposing-name' => 'Conto opposto (nome)', @@ -156,7 +156,7 @@ return [ 'column_account-number' => 'Conto patrimonio (numero conto)', 'column_opposing-number' => 'Conto opposto (numero conto)', 'column_note' => 'Nota(e)', - 'column_internal-reference' => 'Internal reference', + 'column_internal-reference' => 'Riferimento interno', // prerequisites 'prerequisites' => 'Prerequisiti', @@ -164,9 +164,10 @@ return [ // bunq 'bunq_prerequisites_title' => 'Prerequisiti per un\'importazione da bunq', 'bunq_prerequisites_text' => 'Per importare da bunq, è necessario ottenere una chiave API. Puoi farlo attraverso l\'applicazione.', - 'bunq_do_import' => 'Yes, import from this account', - 'bunq_accounts_title' => 'Bunq accounts', - 'bunq_accounts_text' => 'These are the accounts associated with your bunq account. Please select the accounts from which you want to import, and in which account the transactions must be imported.', + 'bunq_prerequisites_text_ip' => 'Bunq richiede il tuo indirizzo IP esterno. Firefly III ha provato a riempire questo campo utilizzando il servizio ipify. Assicurati che questo indirizzo IP sia corretto altrimenti l\'importazione fallirà.', + 'bunq_do_import' => 'Sì, importa da questo conto', + 'bunq_accounts_title' => 'Conti Bunq', + 'bunq_accounts_text' => 'Questi sono i conti associati al tuo conto Bunq. Seleziona i conti dai quali vuoi effettuare l\'importazione e in quale conto devono essere importate le transazioni.', // Spectre 'spectre_title' => 'Importa usando uno Spectre', diff --git a/resources/lang/it_IT/intro.php b/resources/lang/it_IT/intro.php index d9e82ca8bd..df49a56afa 100644 --- a/resources/lang/it_IT/intro.php +++ b/resources/lang/it_IT/intro.php @@ -1,5 +1,6 @@ 'A volte può aiutare a fornire al tuo conto un saldo virtuale: un importo aggiuntivo sempre aggiunto o rimosso dal saldo effettivo.', // budgets index - 'budgets_index_intro' => 'I bilanci sono usati per gestire le tue finanze e formano una delle funzioni principali di Firefly III.', - 'budgets_index_set_budget' => 'Imposta il tuo bilancio totale per ogni periodo in modo che Firefly III possa dirti se hai messo a bilancio tutti i soldi disponibili.', + 'budgets_index_intro' => 'I budget sono usati per gestire le tue finanze e formano una delle funzioni principali di Firefly III.', + 'budgets_index_set_budget' => 'Imposta il tuo budget totale per ogni periodo in modo che Firefly III possa dirti se hai messo a bilancio tutti i soldi disponibili.', 'budgets_index_see_expenses_bar' => 'Le spese effettuate riempiranno lentamente questa barra.', - 'budgets_index_navigate_periods' => 'Naviga attraverso i periodi per impostare facilmente i bilanci in anticipo.', - 'budgets_index_new_budget' => 'Crea nuovi bilanci come meglio credi.', - 'budgets_index_list_of_budgets' => 'Usa questa tabella per impostare gli importi per ciascun bilancio e vedere l\'andamento.', - 'budgets_index_outro' => 'Per saperne di più sul bilancio, controlla l\'icona della guida nell\'angolo in alto a destra.', + 'budgets_index_navigate_periods' => 'Naviga attraverso i periodi per impostare facilmente i budget in anticipo.', + 'budgets_index_new_budget' => 'Crea nuovi budget come meglio credi.', + 'budgets_index_list_of_budgets' => 'Usa questa tabella per impostare gli importi per ciascun budget e vedere l\'andamento.', + 'budgets_index_outro' => 'Per saperne di più sui budget, controlla l\'icona della guida nell\'angolo in alto a destra.', // reports (index) - 'reports_index_intro' => 'Utilizza queste stampe per ottenere informazioni dettagliate sulle tue finanze.', - 'reports_index_inputReportType' => 'Scegli un tipo di stampa. Consulta le pagine della guida per vedere cosa ti mostra ciascuna stampa.', + 'reports_index_intro' => 'Utilizza questi resoconti per ottenere informazioni dettagliate sulle tue finanze.', + 'reports_index_inputReportType' => 'Scegli un tipo di resoconto. Consulta le pagine della guida per vedere cosa ti mostra ciascuna resoconto.', 'reports_index_inputAccountsSelect' => 'Puoi escludere o includere i conti attività come ritieni opportuno.', 'reports_index_inputDateRange' => 'L\'intervallo di date selezionato dipende interamente da te: da un giorno a 10 anni.', - 'reports_index_extra-options-box' => 'A seconda della stampao che hai selezionato, puoi selezionare filtri e opzioni aggiuntive qui. Guarda questa casella quando cambi i tipi di stampa.', + 'reports_index_extra-options-box' => 'A seconda del resoconto che hai selezionato, puoi selezionare filtri e opzioni aggiuntive qui. Guarda questa casella quando cambi i tipi di resoconto.', // reports (reports) - 'reports_report_default_intro' => 'Questa stampa ti fornirà una panoramica rapida e completa delle tue finanze. Se desideri vedere qualcos\'altro, per favore non esitare a contattarmi!', - 'reports_report_audit_intro' => 'Questa stampa ti fornirà approfondimenti dettagliati sui tuoi conti attività.', + 'reports_report_default_intro' => 'Questo resoconto ti fornirà una panoramica rapida e completa delle tue finanze. Se desideri vedere qualcos\'altro, per favore non esitare a contattarmi!', + 'reports_report_audit_intro' => 'Questo resoconto ti fornirà approfondimenti dettagliati sui tuoi conti attività.', 'reports_report_audit_optionsBox' => 'Utilizza queste caselle di controllo per mostrare o nascondere le colonne che ti interessano.', - 'reports_report_category_intro' => 'Questa stampa ti fornirà informazioni su una o più categorie.', + 'reports_report_category_intro' => 'Questo resoconto ti fornirà informazioni su una o più categorie.', 'reports_report_category_pieCharts' => 'Questi grafici ti daranno un\'idea delle spese e del reddito per categoria o per conto.', 'reports_report_category_incomeAndExpensesChart' => 'Questo grafico mostra le tue spese e il reddito per categoria.', - 'reports_report_tag_intro' => 'Questa stampa ti fornirà informazioni su uno o più etichette.', - 'reports_report_tag_pieCharts' => 'Questi grafici ti daranno un\'idea delle spese e del reddito per etichetta, conto, categoria o bilancio.', + 'reports_report_tag_intro' => 'Questo resoconto ti fornirà informazioni su uno o più etichette.', + 'reports_report_tag_pieCharts' => 'Questi grafici ti daranno un\'idea delle spese e del reddito per etichetta, conto, categoria o budget.', 'reports_report_tag_incomeAndExpensesChart' => 'Questo grafico mostra le tue spese e entrate per etichetta.', - 'reports_report_budget_intro' => 'Questa stampa ti fornirà informazioni su uno o più bilancio(i).', - 'reports_report_budget_pieCharts' => 'Questi grafici ti daranno un\'idea delle spese per bilancio o per conto.', - 'reports_report_budget_incomeAndExpensesChart' => 'Questo grafico mostra le tue spese per bilancio.', + 'reports_report_budget_intro' => 'Questo resoconto ti fornirà informazioni su uno o più budget.', + 'reports_report_budget_pieCharts' => 'Questi grafici ti daranno un\'idea delle spese per budget o per conto.', + 'reports_report_budget_incomeAndExpensesChart' => 'Questo grafico mostra le tue spese per budget.', // create transaction 'transactions_create_switch_box' => 'Usa questi pulsanti per cambiare rapidamente il tipo di transazione che desideri salvare.', 'transactions_create_ffInput_category' => 'Puoi scrivere liberamente in questo campo. Saranno suggerite categorie precedentemente create.', - 'transactions_create_withdrawal_ffInput_budget' => 'Collega il tuo prelievo a un bilancio per un migliore controllo finanziario.', + 'transactions_create_withdrawal_ffInput_budget' => 'Collega il tuo prelievo a un budget per un migliore controllo finanziario.', 'transactions_create_withdrawal_currency_dropdown_amount' => 'Usa questo menu a discesa quando il prelievo è in un\'altra valuta.', 'transactions_create_deposit_currency_dropdown_amount' => 'Usa questo menu a discesa quando il tuo deposito è in un\'altra valuta.', 'transactions_create_transfer_ffInput_piggy_bank_id' => 'Seleziona un salvadanaio e collega questo trasferimento ai tuoi risparmi.', @@ -91,20 +92,22 @@ return [ 'piggy-banks_show_piggyEvents' => 'Anche eventuali aggiunte o rimozioni sono elencate qui.', // bill index + 'bills_index_rules' => 'Qui puoi vedere quali regole verranno controllate se questa bolletta viene "toccata"', 'bills_index_paid_in_period' => 'Questo campo indica quando il conto è stato pagato l\'ultima volta.', - 'bills_index_expected_in_period' => 'Questo campo indica per ciascuna fattura se e quando ci si aspetta che la fattura successiva arrivi.', + 'bills_index_expected_in_period' => 'Questo campo indica per ciascuna bolletta se e quando ci si aspetta che la bolletta successiva arrivi.', // show bill - 'bills_show_billInfo' => 'Questa tabella mostra alcune informazioni generali su questa fattura.', - 'bills_show_billButtons' => 'Utilizzare questo pulsante per rieseguire la scansione delle vecchie transazioni in modo che corrispondano a questa fattura.', - 'bills_show_billChart' => 'Questo grafico mostra le transazioni collegate a questa fattura.', + 'bills_show_billInfo' => 'Questa tabella mostra alcune informazioni generali su questa bolletta.', + 'bills_show_billButtons' => 'Utilizzare questo pulsante per rieseguire la scansione delle vecchie transazioni in modo che corrispondano a questa bolletta.', + 'bills_show_billChart' => 'Questo grafico mostra le transazioni collegate a questa bolletta.', // create bill + 'bills_create_intro' => 'Usa le bollette per tenere traccia della quantità di denaro che devi pagare ogni periodo. Pensa alle spese come l\'affitto, l\'assicurazione o le rate del muto.', 'bills_create_name' => 'Utilizzare un nome descrittivo come "Affitto" o "Assicurazione sanitaria".', - 'bills_create_match' => 'Per abbinare le transazioni, utilizzare i termini di tali transazioni o il conto spese coinvolto. Tutte le parole devono corrispondere', + //'bills_create_match' => 'To match transactions, use terms from those transactions or the expense account involved. All words must match.', 'bills_create_amount_min_holder' => 'Seleziona un importo minimo e massimo per questo conto.', 'bills_create_repeat_freq_holder' => 'La maggior parte dei pagamenti si ripetono mensilmente, ma qui puoi impostare un\'altra frequenza.', - 'bills_create_skip_holder' => 'Ad esempio, se un conto si ripete ogni 2 settimane, il campo "Salta" dovrebbe essere impostato su "1" per saltare ogni altra settimana.', + 'bills_create_skip_holder' => 'Se una bolletta si ripete ogni 2 settimane, il campo "salta" deve essere impostato a "1" per saltare ogni volta una settimana.', // rules index 'rules_index_intro' => 'Firefly III ti consente di gestire le regole, che verranno automaticamente applicate a qualsiasi transazione creata o modificata.', diff --git a/resources/lang/it_IT/list.php b/resources/lang/it_IT/list.php index 524800b95b..0c058e1d10 100644 --- a/resources/lang/it_IT/list.php +++ b/resources/lang/it_IT/list.php @@ -33,6 +33,7 @@ return [ 'name' => 'Nome', 'role' => 'Ruolo', 'currentBalance' => 'Bilancio corrente', + 'linked_to_rules' => 'Regole rilevanti', 'active' => 'Attivo', 'lastActivity' => 'Ultima attività', 'balanceDiff' => 'Differenze bilancio', @@ -56,13 +57,13 @@ return [ 'process_date' => 'Data lavorazione', 'due_date' => 'Data scadenza', 'payment_date' => 'Data pagamento', - 'invoice_date' => 'Data fattura', + 'invoice_date' => 'Data bolletta', 'interal_reference' => 'Referenze interne', 'notes' => 'Note', 'from' => 'Da', 'piggy_bank' => 'Salvadanaio', 'to' => 'A', - 'budget' => 'Bilancio', + 'budget' => 'Budget', 'category' => 'Categoria', 'bill' => 'Conto', 'withdrawal' => 'Spesa', @@ -87,7 +88,7 @@ return [ 'categories_count' => 'Numero categorie', 'export_jobs_count' => 'Numero esportazioni', 'import_jobs_count' => 'Numero importazioni', - 'budget_count' => 'Numero bilanci', + 'budget_count' => 'Numero di budget', 'rule_and_groups_count' => 'Numero regole e gruppi regole', 'tags_count' => 'Numero etichette', 'tags' => 'Etichette', @@ -110,5 +111,5 @@ return [ 'sepa-cc' => 'SEPA Clearing Code', 'sepa-ep' => 'SEPA External Purpose', 'sepa-ci' => 'SEPA Creditor Identifier', - 'account_at_bunq' => 'Account with bunq', + 'account_at_bunq' => 'Conto con Bunq', ]; diff --git a/resources/lang/it_IT/validation.php b/resources/lang/it_IT/validation.php index 9dfe0dcbf4..03bd3f48b4 100644 --- a/resources/lang/it_IT/validation.php +++ b/resources/lang/it_IT/validation.php @@ -22,7 +22,7 @@ declare(strict_types=1); return [ 'iban' => 'Questo non è un IBAN valido.', - 'source_equals_destination' => 'The source account equals the destination account', + 'source_equals_destination' => 'Il conto di origine è uguale al conto di destinazione', 'unique_account_number_for_user' => 'Sembra che questo numero di conto sia già in uso.', 'unique_iban_for_user' => 'Sembra che questo IBAN sia già in uso.', 'deleted_user' => 'A causa dei vincoli di sicurezza, non è possibile registrarsi utilizzando questo indirizzo email.', diff --git a/resources/lang/nl_NL/firefly.php b/resources/lang/nl_NL/firefly.php index b4c056aa29..f54bc0f679 100644 --- a/resources/lang/nl_NL/firefly.php +++ b/resources/lang/nl_NL/firefly.php @@ -267,7 +267,10 @@ return [ 'move_rule_group_down' => 'Verplaats regelgroep omlaag', 'save_rules_by_moving' => 'Red deze regel(s) van de ondergang door ze te verplaatsen naar een andere regelgroep:', 'make_new_rule' => 'Maak een nieuwe regel in regelgroep ":title"', + 'rule_is_strict' => 'strikte regel', + 'rule_is_not_strict' => 'niet-strikte regel', 'rule_help_stop_processing' => 'Zet hier een vinkje om latere regels in deze groep te negeren.', + 'rule_help_strict' => 'Voor strikte regels geldt dat ALLE triggers overeen moeten komen. Voor niet-strikte regel is één trigger genoeg om de acties uit te laten voeren.', 'rule_help_active' => 'Niet actieve regels zullen nooit worden gecontroleerd.', 'stored_new_rule' => 'Nieuwe regel ":title" opgeslagen', 'deleted_rule' => 'Regel ":title" verwijderd', @@ -345,6 +348,8 @@ return [ 'rule_trigger_budget_is' => 'Budget is ":trigger_value"', 'rule_trigger_tag_is_choice' => '(Een) tag is..', 'rule_trigger_tag_is' => 'Een tag is ":trigger_value"', + 'rule_trigger_currency_is_choice' => 'Transactievaluta is..', + 'rule_trigger_currency_is' => 'Transactievaluta is ":trigger_value"', 'rule_trigger_has_attachments_choice' => 'Heeft minstens zoveel bijlagen', 'rule_trigger_has_attachments' => 'Heeft minstens :trigger_value bijlage(n)', 'rule_trigger_store_journal' => 'Als een transactie wordt gemaakt', @@ -404,10 +409,20 @@ return [ 'rule_action_clear_notes_choice' => 'Verwijder notitie', 'rule_action_clear_notes' => 'Verwijder notitie', 'rule_action_set_notes_choice' => 'Verander notitie in..', + 'rule_action_link_to_bill_choice' => 'Link naar een contract..', + 'rule_action_link_to_bill' => 'Link naar contract ":action_value"', 'rule_action_set_notes' => 'Verander notitie in ":action_value"', 'rules_have_read_warning' => 'Heb je de waarschuwing gelezen?', 'apply_rule_warning' => 'Let op! Het kan heel lang duren voor een regel(groep) is toegepast op een grote selectie transacties. Er kan een time-out optreden. Als dat gebeurt is de regel(groep) niet toegepast op alle transacties, en dat kan je administratie behoorlijk verprutsen. Wees dus voorzichtig.', + 'rulegroup_for_bills_title' => 'Regelgroep voor contracten', + 'rulegroup_for_bills_description' => 'Een speciale regelgroep voor alle regels die met contracten te maken hebben.', + 'rule_for_bill_title' => 'Automatisch gegenereerde regel voor contract ":name"', + 'rule_for_bill_description' => 'Deze regel is automatisch gegenereerd om te transacties te matchen met contract ":name".', + 'create_rule_for_bill' => 'Maak een nieuwe regel voor contract ":name"', + 'create_rule_for_bill_txt' => 'Je hebt een nieuw contract ":name" gemaakt, hoera! Firefly III can automagisch naar je uitgaven kijken en deze koppelen aan dit contract. Als je bijvoorbeeld je huur betaalt wordt de uitgave gekoppeld aan contract "huur". Op die manier laat Firefly III je zien welke rekeningen nog betaald moeten worden en welke niet. Om dat te doen moet er een regel gemaakt worden. Firefly III heeft vast wat handige waardes ingevuld. Dubbelcheck deze. Als ze kloppen zal Firefly III automatisch de juiste uitgave aan het juiste contract koppelen. Kijk dus goed of de triggers kloppen en corrigeer waar nodig.', + 'new_rule_for_bill_title' => 'Regel voor contract ":name"', + 'new_rule_for_bill_description' => 'Deze regel markeert uitgaven voor contract ":name".', // tags 'store_new_tag' => 'Sla tag op', @@ -624,8 +639,8 @@ return [ 'over_budget_warn' => ' Normaalgesproken budgetteer je :amount per dag. Nu sta je op :over_amount per dag.', // bills: - 'matching_on' => 'Wordt herkend', - 'between_amounts' => 'tussen :low en :high.', + 'match_between_amounts' => 'Contract past bij transacties tussen :low en :high.', + 'bill_related_rules' => 'Regels gerelateerd aan dit contract', 'repeats' => 'Herhaalt', 'connected_journals' => 'Verbonden transacties', 'auto_match_on' => 'Automatisch herkend door Firefly III', @@ -635,19 +650,20 @@ return [ 'deleted_bill' => 'Contract ":name" verwijderd', 'edit_bill' => 'Wijzig contract ":name"', 'more' => 'Meer', - 'rescan_old' => 'Scan oude transacties opnieuw', + 'rescan_old' => 'Voer regels opnieuw uit op alle transacties', 'update_bill' => 'Wijzig contract', 'updated_bill' => 'Contract ":name" geüpdatet', 'store_new_bill' => 'Sla nieuw contract op', 'stored_new_bill' => 'Nieuw contract ":name" opgeslagen', 'cannot_scan_inactive_bill' => 'Inactieve contracten kunnen niet worden gescand.', - 'rescanned_bill' => 'Alles is opnieuw gescand.', + 'rescanned_bill' => 'Alles opnieuw gescand, en :total transactie(s) zijn gekoppeld aan het contract.', 'average_bill_amount_year' => 'Gemiddeld contractbedrag (:year)', 'average_bill_amount_overall' => 'Gemiddeld contractbedrag (gehele periode)', 'bill_is_active' => 'Contract is actief', 'bill_expected_between' => 'Verwacht tussen :start en :end', 'bill_will_automatch' => 'Waar van toepassing wordt dit contract automatisch gekoppeld aan transacties', 'skips_over' => 'slaat over', + 'bill_store_error' => 'Er ging wat fout bij het opslaan van het contract. Kijk in de logbestanden', // accounts: 'details_for_asset' => 'Overzicht voor betaalrekening ":name"', @@ -784,6 +800,7 @@ return [ 'opt_group_sharedAsset' => 'Gedeelde betaalrekeningen', 'opt_group_ccAsset' => 'Creditcards', 'notes' => 'Notities', + 'unknown_journal_error' => 'Kon de transactie niet opslaan. Kijk in de logbestanden.', // new user: 'welcome' => 'Welkom bij Firefly III!', @@ -793,6 +810,10 @@ return [ 'savings_balance_text' => 'Firefly III maakt automatisch een spaarrekening voor je. Daar zit normaal geen geld in, maar je kan hier opgeven hoeveel er op staat.', 'finish_up_new_user' => 'That\'s it! Druk op Opslaan om door te gaan. Je gaat dan naar de homepage van Firefly III.', 'stored_new_accounts_new_user' => 'Hoera! Je nieuwe accounts zijn opgeslagen.', + 'set_preferred_language' => 'Als je Firefly III liever in een andere taal gebruikt, geef dat dan hier aan.', + 'language' => 'Taal', + 'new_savings_account' => ':bank_name spaarrekening', + 'cash_wallet' => 'Cash-rekening', // home page: 'yourAccounts' => 'Je betaalrekeningen', @@ -941,6 +962,7 @@ return [ 'account_role_sharedAsset' => 'Gedeelde betaalrekening', 'account_role_savingAsset' => 'Spaarrekening', 'account_role_ccAsset' => 'Credit card', + 'account_role_cashWalletAsset' => 'Cash', 'budget_chart_click' => 'Klik op een budgetnaam in de tabel hierboven om een ​​grafiek te zien.', 'category_chart_click' => 'Klik op een categorienaam in de tabel hierboven om een ​​grafiek te zien.', 'in_out_accounts' => 'Inkomsten en uitgaven per combinatie', @@ -1000,6 +1022,7 @@ return [ 'events' => 'Gebeurtenissen', 'target_amount' => 'Doelbedrag', 'start_date' => 'Startdatum', + 'no_start_date' => 'Geen startdatum', 'target_date' => 'Doeldatum', 'no_target_date' => 'Geen doeldatum', 'table' => 'Tabel', @@ -1136,6 +1159,14 @@ return [ 'import_index_title' => 'Gegevens importeren in Firefly III', 'import_index_sub_title' => 'Index', 'import_general_index_intro' => 'Dit is de import-routine van Firefly III. Er zijn verschillende manieren om gegevens te importeren in Firefly III, hier als knoppen weergegeven.', + 'upload_error' => 'Het bestand dat je hebt geüpload kan niet gebruikt worden. Het is wellicht het verkeerde type of de verkeerde encoding. In de logbestanden staat meer info.', + 'reset_import_settings_title' => 'Reset importconfiguratie', + 'reset_import_settings_text' => 'Gebruik deze links om importinstellingen voor specifieke providers te resetten. Handig als verkeerde instellingen voorkomen dat je verder kan.', + 'reset_settings_bunq' => 'Verwijdert de bunq API key, je externe IP adres zoals Firefly III die kent, en de voor bunq gegenereerde RSA sleutels.', + 'reset_settings_spectre' => 'Verwijdert je Spectre client ID, service secret en app secret. Dit verwijdert ook je Spectre keypair. Vergeet die niet te updaten.', + 'settings_reset_for_bunq' => 'Bunq-instellingen zijn gereset.', + 'settings_reset_for_spectre' => 'Spectre-instellingen zijn gereset.', + // sandstorm.io errors and messages: 'sandstorm_not_available' => 'Deze functie werkt niet als je Firefly III gebruikt in combinatie met Sandstorm.IO.', diff --git a/resources/lang/nl_NL/form.php b/resources/lang/nl_NL/form.php index ab1c58fece..e6d202f030 100644 --- a/resources/lang/nl_NL/form.php +++ b/resources/lang/nl_NL/form.php @@ -1,5 +1,6 @@ 'Minimumbedrag', 'amount_max' => 'Maximumbedrag', 'match' => 'Reageert op', + 'strict' => 'Strikte modus', 'repeat_freq' => 'Herhaling', 'journal_currency_id' => 'Valuta', 'currency_id' => 'Valuta', + 'transaction_currency_id' => 'Valuta', + 'external_ip' => 'Het externe IP-adres van je server', 'attachments' => 'Bijlagen', 'journal_amount' => 'Bedrag', 'journal_source_account_name' => 'Debiteur (bron)', diff --git a/resources/lang/nl_NL/import.php b/resources/lang/nl_NL/import.php index b77ad27912..08ff84dff2 100644 --- a/resources/lang/nl_NL/import.php +++ b/resources/lang/nl_NL/import.php @@ -164,6 +164,7 @@ return [ // bunq 'bunq_prerequisites_title' => 'Voorwaarden voor een import van bunq', 'bunq_prerequisites_text' => 'Om te importeren vanaf bunq moet je een API key hebben. Deze kan je aanvragen in de app. Denk er aan dat deze functie in BETA is. De code is alleen getest op de sandbox API.', + 'bunq_prerequisites_text_ip' => 'Bunq wilt graag je externe IP-adres weten. Firefly III heeft geprobeerd dit in te vullen met behulp van de ipify-dienst. Zorg dat je zeker weet dat dit IP-adres klopt, want anders zal de import niet werken.', 'bunq_do_import' => 'Ja, importeer van deze rekening', 'bunq_accounts_title' => 'Bunq rekeningen', 'bunq_accounts_text' => 'Dit zijn de rekeningen uit je bunq-account. Selecteer de rekeningen waaruit je wilt importeren, en welke betaalrekeningen deze transacties op terecht moeten komen.', diff --git a/resources/lang/nl_NL/intro.php b/resources/lang/nl_NL/intro.php index 381b02153a..19344b11b0 100644 --- a/resources/lang/nl_NL/intro.php +++ b/resources/lang/nl_NL/intro.php @@ -1,5 +1,6 @@ 'Eventuele stortingen (van en naar) worden hier ook vermeld.', // bill index + 'bills_index_rules' => 'Hier zie je welke regels een actie hebben voor dit contract', 'bills_index_paid_in_period' => 'Dit veld geeft aan wanneer het contract het laatst is betaald.', 'bills_index_expected_in_period' => 'Dit veld geeft aan voor elk contract of en wanneer je hem weer moet betalen.', @@ -100,8 +102,9 @@ return [ 'bills_show_billChart' => 'Deze grafiek toont de transacties gekoppeld aan dit contract.', // create bill + 'bills_create_intro' => 'Gebruik contracten om de hoeveelheid geld te volgen die je elke periode moet betalen. Denk aan uitgaven zoals huur, verzekering of hypotheekbetalingen.', 'bills_create_name' => 'Gebruik een beschrijvende naam zoals "huur" of "zorgverzekering".', - 'bills_create_match' => 'Om transacties te koppelen gebruik je termen uit de transacties of de bijbehorende crediteur. Alle termen moeten overeen komen.', + //'bills_create_match' => 'To match transactions, use terms from those transactions or the expense account involved. All words must match.', 'bills_create_amount_min_holder' => 'Stel ook een minimum- en maximumbedrag in.', 'bills_create_repeat_freq_holder' => 'De meeste contracten herhalen maandelijks, maar dat kan je eventueel veranderen.', 'bills_create_skip_holder' => 'Als een contract elke twee weken herhaalt, zet je het "skip"-veld op 1 om elke andere week over te slaan.', diff --git a/resources/lang/nl_NL/list.php b/resources/lang/nl_NL/list.php index df952495a6..d0104594ec 100644 --- a/resources/lang/nl_NL/list.php +++ b/resources/lang/nl_NL/list.php @@ -33,6 +33,7 @@ return [ 'name' => 'Naam', 'role' => 'Rol', 'currentBalance' => 'Huidig saldo', + 'linked_to_rules' => 'Relevante regels', 'active' => 'Actief?', 'lastActivity' => 'Laatste activiteit', 'balanceDiff' => 'Saldoverschil', diff --git a/resources/lang/pl_PL/firefly.php b/resources/lang/pl_PL/firefly.php index 09b0af0d86..680bfe22b1 100644 --- a/resources/lang/pl_PL/firefly.php +++ b/resources/lang/pl_PL/firefly.php @@ -267,7 +267,10 @@ return [ 'move_rule_group_down' => 'Przenieś grupę reguł w dół', 'save_rules_by_moving' => 'Zapisz te reguły, przenosząc je do innej grupy reguł:', 'make_new_rule' => 'Utwórz nową regułę w grupie reguł ":title"', + 'rule_is_strict' => 'ścisła reguła', + 'rule_is_not_strict' => 'swobodna reguła', 'rule_help_stop_processing' => 'Gdy zaznaczysz to pole, kolejne reguły w tej grupie nie będą wykonywane.', + 'rule_help_strict' => 'W ścisłych regułach WSZYSTKIE wyzwalacze muszą się aktywować aby akcje zostały wykonane. W swobodnych regułach DOWOLNY wyzwalacz wystarcza do wykonania akcji.', 'rule_help_active' => 'Nieaktywne reguły nigdy nie zostaną uruchomione.', 'stored_new_rule' => 'Zapisano regułę o nazwie ":title"', 'deleted_rule' => 'Usunięto regułę o nazwie ":title"', @@ -345,6 +348,8 @@ return [ 'rule_trigger_budget_is' => 'Budżet to ":trigger_value"', 'rule_trigger_tag_is_choice' => 'Tag to..', 'rule_trigger_tag_is' => 'Tag to ":trigger_value"', + 'rule_trigger_currency_is_choice' => 'Waluta transakcji to..', + 'rule_trigger_currency_is' => 'Waluta transakcji to ":trigger_value"', 'rule_trigger_has_attachments_choice' => 'Ma co najmniej podaną liczbę załączników', 'rule_trigger_has_attachments' => 'Ma co najmniej :trigger_value załącznik(ów)', 'rule_trigger_store_journal' => 'Po utworzeniu transakcji', @@ -404,10 +409,20 @@ return [ 'rule_action_clear_notes_choice' => 'Usuń wszystkie notatki', 'rule_action_clear_notes' => 'Usuń wszystkie notatki', 'rule_action_set_notes_choice' => 'Ustaw notatki na..', + 'rule_action_link_to_bill_choice' => 'Powiąż z rachunkiem..', + 'rule_action_link_to_bill' => 'Powiąż z rachunkiem ":action_value"', 'rule_action_set_notes' => 'Ustaw notatki na ":action_value"', 'rules_have_read_warning' => 'Czy przeczytałeś ostrzeżenie?', 'apply_rule_warning' => 'Ostrzeżenie: uruchomienie reguły (lub grupy reguł) na dużej liczbie transakcji może potrwać wieki i może przekroczyć limit czasu. W takiej sytuacji reguła (lub grupa reguł) zostanie zastosowana do nieznanego podzbioru Twoich transakcji. To może zostawić Twoją administrację finansową w strzępach. Proszę, bądź ostrożny.', + 'rulegroup_for_bills_title' => 'Grupa reguł dla rachunków', + 'rulegroup_for_bills_description' => 'Specjalna grupa reguł dla wszystkich reguł dotyczących rachunków.', + 'rule_for_bill_title' => 'Automatycznie wygenerowana reguła dla rachunku ":name"', + 'rule_for_bill_description' => 'Ta reguła została automatycznie wygenerowana, aby spróbować dopasować rachunek ":name".', + 'create_rule_for_bill' => 'Utwórz nową regułę dla rachunku ":name"', + 'create_rule_for_bill_txt' => 'Właśnie utworzyłeś nowy rachunek o nazwie ":name". Gratulacje! Firefly III może automagicznie dopasować nowe wypłaty do tego rachunku. Na przykład za każdym razem, gdy płacisz czynsz, rachunek "czynsz" zostanie powiązany z wydatkiem. W ten sposób Firefly III może dokładnie pokazać, które rachunki są jeszcze do zapłacenia, a które nie. W tym celu należy utworzyć nową regułę. Firefly III wypełnił dla Ciebie pewne rozsądne domyślne ustawienia. Upewnij się, że są poprawne. Jeśli są, Firefly III automatycznie połączy pasującą wypłatę z prawidłowym rachunkiem. Sprawdź wyzwalacze czy są poprawne i dodaj kolejne jeśli są błędne.', + 'new_rule_for_bill_title' => 'Reguła dla rachunku ":name"', + 'new_rule_for_bill_description' => 'Ta reguła oznacza transakcje jako powiązane z rachunkiem ":name".', // tags 'store_new_tag' => 'Zachowaj nowy tag', @@ -624,8 +639,8 @@ return [ 'over_budget_warn' => ' Zwykle budżetujesz około :amount dziennie. Obecna wartość to :over_amount dziennie.', // bills: - 'matching_on' => 'Pasuje do', - 'between_amounts' => 'między :low i :high.', + 'match_between_amounts' => 'Rachunek pasuje do transakcji między :low a :high.', + 'bill_related_rules' => 'Reguły powiązane z tym rachunkiem', 'repeats' => 'Powtarza się', 'connected_journals' => 'Powiązane transakcje', 'auto_match_on' => 'Automatycznie dopasowane przez Firefly III', @@ -635,19 +650,20 @@ return [ 'deleted_bill' => 'Usunięto rachunek ":name"', 'edit_bill' => 'Modyfikuj rachunek ":name"', 'more' => 'Więcej', - 'rescan_old' => 'Przeskanuj stare transakcje', + 'rescan_old' => 'Uruchom ponownie reguły na wszystkich transakcjach', 'update_bill' => 'Aktualizuj rachunek', 'updated_bill' => 'Zaktualizowano rachunek ":name"', 'store_new_bill' => 'Zapisz nowy rachunek', 'stored_new_bill' => 'Zapisano nowy rachunek ":name"', 'cannot_scan_inactive_bill' => 'Nieaktywne rachunki nie mogą być zeskanowane.', - 'rescanned_bill' => 'Zeskanowano wszystko.', + 'rescanned_bill' => 'Przeskanowano wszystko ponownie i powiązano nowe transakcje (:total) z rachunkiem.', 'average_bill_amount_year' => 'Średnia kwota rachunku (:year)', 'average_bill_amount_overall' => 'Średnia kwota rachunku (ogólnie)', 'bill_is_active' => 'Rachunek jest aktywny', 'bill_expected_between' => 'Oczekiwano między :start a :end', 'bill_will_automatch' => 'Rachunek będzie automatycznie powiązany z pasującymi transakcjami', 'skips_over' => 'pomija', + 'bill_store_error' => 'Wystąpił nieoczekiwany błąd podczas zapisywania nowego rachunku. Sprawdź pliki dziennika', // accounts: 'details_for_asset' => 'Szczegóły konta aktywów ":name"', @@ -784,6 +800,7 @@ return [ 'opt_group_sharedAsset' => 'Współdzielone konta aktywów', 'opt_group_ccAsset' => 'Karty kredytowe', 'notes' => 'Notatki', + 'unknown_journal_error' => 'Nie można zapisać transakcji. Sprawdź pliki dziennika.', // new user: 'welcome' => 'Witaj w Firefly III!', @@ -793,6 +810,10 @@ return [ 'savings_balance_text' => 'Firefly III automatycznie utworzy dla ciebie konto oszczędnościowe. Domyślnie na twoim koncie oszczędnościowym nie ma pieniędzy, ale jeśli chcesz, Firefly III może je tam przechowywać.', 'finish_up_new_user' => 'To wszystko! Możesz kontynuować, naciskając Zatwierdź. Zostaniesz przeniesiony do strony głównej Firefly III.', 'stored_new_accounts_new_user' => 'Yay! Twoje nowe konta zostały zapisane.', + 'set_preferred_language' => 'Jeśli wolisz używać Firefly III w innym języku, wskaż to tutaj.', + 'language' => 'Język', + 'new_savings_account' => 'Konto oszczędnościowe :bank_name', + 'cash_wallet' => 'Portfel gotówkowy', // home page: 'yourAccounts' => 'Twoje konta', @@ -941,6 +962,7 @@ return [ 'account_role_sharedAsset' => 'Współdzielone konto aktywów', 'account_role_savingAsset' => 'Konto oszczędnościowe', 'account_role_ccAsset' => 'Karta kredytowa', + 'account_role_cashWalletAsset' => 'Portfel gotówkowy', 'budget_chart_click' => 'Kliknij na nazwę budżetu w tabeli powyżej, aby zobaczyć wykres.', 'category_chart_click' => 'Kliknij na nazwę kategorii w tabeli powyżej, aby zobaczyć wykres.', 'in_out_accounts' => 'Zarobione oraz wydane wg kombinacji', @@ -1000,6 +1022,7 @@ return [ 'events' => 'Zdarzenia', 'target_amount' => 'Kwota docelowa', 'start_date' => 'Data rozpoczęcia', + 'no_start_date' => 'No start date', 'target_date' => 'Data docelowa', 'no_target_date' => 'Brak daty docelowej', 'table' => 'Tabela', @@ -1136,6 +1159,14 @@ return [ 'import_index_title' => 'Importuj dane do Firefly III', 'import_index_sub_title' => 'Indeks', 'import_general_index_intro' => 'Witamy w procedurze importu Firefly III. Istnieje kilka sposobów importowania danych do Firefly III.', + 'upload_error' => 'Przesłany plik nie może zostać przetworzony. Prawdopodobnie typ pliku lub kodowanie jest błędne. Pliki dziennika zawierają więcej informacji.', + 'reset_import_settings_title' => 'Reset import configuration', + 'reset_import_settings_text' => 'You can use these links to reset your import settings for specific providers. This is useful when bad settings stop you from importing data.', + 'reset_settings_bunq' => 'Remove bunq API key, local external IP address and bunq related RSA keys.', + 'reset_settings_spectre' => 'Remove Spectre client ID, service secret and app secret. This will also remove your Spectre keypair. Remember to update the new one.', + 'settings_reset_for_bunq' => 'Bunq settings reset.', + 'settings_reset_for_spectre' => 'Spectre settings reset.', + // sandstorm.io errors and messages: 'sandstorm_not_available' => 'Ta funkcja nie jest dostępna, gdy używasz Firefly III w środowisku Sandstorm.io.', diff --git a/resources/lang/pl_PL/form.php b/resources/lang/pl_PL/form.php index 8cb45c4613..d23b4529de 100644 --- a/resources/lang/pl_PL/form.php +++ b/resources/lang/pl_PL/form.php @@ -1,5 +1,6 @@ 'Minimalna kwota', 'amount_max' => 'Maksymalna kwota', 'match' => 'Dopasowanie', + 'strict' => 'Tryb ścisły', 'repeat_freq' => 'Powtarza się', 'journal_currency_id' => 'Waluta', 'currency_id' => 'Waluta', + 'transaction_currency_id' => 'Waluta', + 'external_ip' => 'Zewnętrzny adres IP Twojego serwera', 'attachments' => 'Załączniki', 'journal_amount' => 'Kwota', 'journal_source_account_name' => 'Konto przychodów (źródło)', diff --git a/resources/lang/pl_PL/import.php b/resources/lang/pl_PL/import.php index fca3a37578..f467b8922e 100644 --- a/resources/lang/pl_PL/import.php +++ b/resources/lang/pl_PL/import.php @@ -164,6 +164,7 @@ return [ // bunq 'bunq_prerequisites_title' => 'Wymagania wstępne dla importu z bunq', 'bunq_prerequisites_text' => 'Aby importować z Bunq, musisz uzyskać klucz API. Możesz to zrobić za pomocą aplikacji. Zwróć uwagę, że funkcja importu z Bunq jest w wersji BETA. Została przetestowana tylko przy użyciu testowej wersji API.', + 'bunq_prerequisites_text_ip' => 'Bunq musi znać zewnętrzny adres IP Twojego serwera. Firefly III próbował ustalić go używając usługi ipify. Upewnij się, że ten adres IP jest poprawny albo import się nie powiedzie.', 'bunq_do_import' => 'Tak, importuj z tego konta', 'bunq_accounts_title' => 'Konta Bunq', 'bunq_accounts_text' => 'Te konta są powiązane z Twoim kontem Bunq. Wybierz konta, z których chcesz importować transakcje i na które konto mają trafić.', diff --git a/resources/lang/pl_PL/intro.php b/resources/lang/pl_PL/intro.php index 9ca0a5a4cb..678cae900d 100644 --- a/resources/lang/pl_PL/intro.php +++ b/resources/lang/pl_PL/intro.php @@ -1,5 +1,6 @@ 'Wszelkie dodatki lub usunięcia są również tutaj wymienione.', // bill index + 'bills_index_rules' => 'Tutaj zobaczysz, które reguły sprawdzą dopasowanie transakcji do rachunku', 'bills_index_paid_in_period' => 'To pole wskazuje, kiedy rachunek został ostatnio opłacony.', 'bills_index_expected_in_period' => 'To pole wskazuje dla każdego rachunku, czy i kiedy oczekuje się następnego rachunku.', @@ -100,8 +102,9 @@ return [ 'bills_show_billChart' => 'Ten wykres pokazuje transakcje powiązane z tym rachunkiem.', // create bill + 'bills_create_intro' => 'Korzystaj z rachunków, aby śledzić kwotę pieniędzy, którą jesteś winny w każdym okresie. Pomyśl o takich wydatkach jak czynsz, ubezpieczenie czy spłata kredytu hipotecznego.', 'bills_create_name' => 'Użyj opisowej nazwy, takiej jak "Czynsz" lub "Ubezpieczenie zdrowotne".', - 'bills_create_match' => 'Aby dopasować transakcje, użyj zwrotów z tych transakcji lub konta wydatków. Wszystkie słowa muszą pasować.', + //'bills_create_match' => 'To match transactions, use terms from those transactions or the expense account involved. All words must match.', 'bills_create_amount_min_holder' => 'Wybierz minimalną i maksymalną kwotę dla tego rachunku.', 'bills_create_repeat_freq_holder' => 'Większość rachunków powtarza się co miesiąc, ale możesz ustawić inną częstotliwość tutaj.', 'bills_create_skip_holder' => 'Jeśli rachunek powtarza się co 2 tygodnie, pole "Pomiń" powinno być ustawione na "1", aby pominąć co drugi tydzień.', diff --git a/resources/lang/pl_PL/list.php b/resources/lang/pl_PL/list.php index 4305286f0b..ad6f683669 100644 --- a/resources/lang/pl_PL/list.php +++ b/resources/lang/pl_PL/list.php @@ -33,6 +33,7 @@ return [ 'name' => 'Nazwa', 'role' => 'Rola', 'currentBalance' => 'Bieżące saldo', + 'linked_to_rules' => 'Powiązane reguły', 'active' => 'Jest aktywny?', 'lastActivity' => 'Ostatnia aktywność', 'balanceDiff' => 'Różnica sald', diff --git a/resources/lang/pt_BR/firefly.php b/resources/lang/pt_BR/firefly.php index 99ffefcce5..02c0398eda 100644 --- a/resources/lang/pt_BR/firefly.php +++ b/resources/lang/pt_BR/firefly.php @@ -267,7 +267,10 @@ return [ 'move_rule_group_down' => 'Descer grupo de regras', 'save_rules_by_moving' => 'Salve essas regra(s), movendo-os para outro grupo de regra:', 'make_new_rule' => 'Fazer nova regra no grupo de regras ":title"', + 'rule_is_strict' => 'strict rule', + 'rule_is_not_strict' => 'non-strict rule', 'rule_help_stop_processing' => 'Quando você marcar essa caixa, regras posteriores deste grupo não serão executadas.', + 'rule_help_strict' => 'In strict rules ALL triggers must fire for the action(s) to be executed. In non-strict rules, ANY trigger is enough for the action(s) to be executed.', 'rule_help_active' => 'Regras inativas nunca serão disparadas.', 'stored_new_rule' => 'Armazenado a nova regra com o título ":title"', 'deleted_rule' => 'Regra excluída com o título ":title"', @@ -345,6 +348,8 @@ return [ 'rule_trigger_budget_is' => 'O orçamento é ":trigger_value"', 'rule_trigger_tag_is_choice' => '(A) tag é..', 'rule_trigger_tag_is' => 'A tag é ":trigger_value"', + 'rule_trigger_currency_is_choice' => 'Transaction currency is..', + 'rule_trigger_currency_is' => 'Transaction currency is ":trigger_value"', 'rule_trigger_has_attachments_choice' => 'Tem pelo menos essa quantidade de anexos', 'rule_trigger_has_attachments' => 'Tem pelo menos :trigger_value anexo(s)', 'rule_trigger_store_journal' => 'Quando uma transação é criada', @@ -404,10 +409,20 @@ return [ 'rule_action_clear_notes_choice' => 'Remover quaisquer notas', 'rule_action_clear_notes' => 'Remover quaisquer notas', 'rule_action_set_notes_choice' => 'Defina notas para..', + 'rule_action_link_to_bill_choice' => 'Link to a bill..', + 'rule_action_link_to_bill' => 'Link to bill ":action_value"', 'rule_action_set_notes' => 'Defina notas para ":action_value"', 'rules_have_read_warning' => 'Você leu o aviso?', 'apply_rule_warning' => 'Aviso: executar uma regra (grupo) em uma grande seleção de transações pode levar tempo, e pode atingir um tempo limite. Se o fizer, a regra (grupo) só será aplicada a um subconjunto desconhecido de suas transações. Isso pode deixar a sua administração financeira aos pedaços. Por favor, seja cuidadoso.', + 'rulegroup_for_bills_title' => 'Rule group for bills', + 'rulegroup_for_bills_description' => 'A special rule group for all the rules that involve bills.', + 'rule_for_bill_title' => 'Auto-generated rule for bill ":name"', + 'rule_for_bill_description' => 'This rule is auto-generated to try to match bill ":name".', + 'create_rule_for_bill' => 'Create a new rule for bill ":name"', + 'create_rule_for_bill_txt' => 'You have just created a new bill called ":name", congratulations! Firefly III can automagically match new withdrawals to this bill. For example, whenever you pay your rent, the bill "rent" will be linked to the expense. This way, Firefly III can accurately show you which bills are due and which ones aren\'t. In order to do so, a new rule must be created. Firefly III has filled in some sensible defaults for you. Please make sure these are correct. If these values are correct, Firefly III will automatically link the correct withdrawal to the correct bill. Please check out the triggers to see if they are correct, and add some if they\'re wrong.', + 'new_rule_for_bill_title' => 'Rule for bill ":name"', + 'new_rule_for_bill_description' => 'This rule marks transactions for bill ":name".', // tags 'store_new_tag' => 'Armazenar nova tag', @@ -624,8 +639,8 @@ return [ 'over_budget_warn' => ' Normally you budget about :amount per day. This is :over_amount per day.', // bills: - 'matching_on' => 'Corresponde em', - 'between_amounts' => 'entre :low e :high.', + 'match_between_amounts' => 'Bill matches transactions between :low and :high.', + 'bill_related_rules' => 'Rules related to this bill', 'repeats' => 'Repetições', 'connected_journals' => 'Transações conectadas', 'auto_match_on' => 'Automaticamente correspondente com Firefly III', @@ -635,19 +650,20 @@ return [ 'deleted_bill' => 'Fatura apagada ":name"', 'edit_bill' => 'Editar fatura ":name"', 'more' => 'Mais', - 'rescan_old' => 'Examinar novamente o transações antigas', + 'rescan_old' => 'Run rules again, on all transactions', 'update_bill' => 'Atualizar fatura', 'updated_bill' => 'Fatura atualizada ":name"', 'store_new_bill' => 'Armazenar nova fatura', 'stored_new_bill' => 'Nova fatura armazenada ":name"', 'cannot_scan_inactive_bill' => 'Faturas inativas não podem ser verificadas.', - 'rescanned_bill' => 'Tudo examinado novamente.', + 'rescanned_bill' => 'Rescanned everything, and linked :total transaction(s) to the bill.', 'average_bill_amount_year' => 'Média de fatura (:year)', 'average_bill_amount_overall' => 'Média de fatura (geral)', 'bill_is_active' => 'Fatura está ativa', 'bill_expected_between' => 'Esperado entre :start e :end', 'bill_will_automatch' => 'A fatura será automaticamente vinculada a transações correspondentes', 'skips_over' => 'ignorar', + 'bill_store_error' => 'An unexpected error occurred while storing your new bill. Please check the log files', // accounts: 'details_for_asset' => 'Detalhes para a conta de ativo ":name"', @@ -784,6 +800,7 @@ return [ 'opt_group_sharedAsset' => 'Contas de ativos compartilhadas', 'opt_group_ccAsset' => 'Cartões de crédito', 'notes' => 'Notas', + 'unknown_journal_error' => 'Could not store the transaction. Please check the log files.', // new user: 'welcome' => 'Bem Vindo ao Firefly III!', @@ -793,6 +810,10 @@ return [ 'savings_balance_text' => 'O Firefly III criará automaticamente uma conta de poupança para você. Por padrão, não haverá dinheiro na sua conta de poupança, mas se você contar o saldo ao Firefly III, ele será armazenado como tal.', 'finish_up_new_user' => 'É isso aí! Você pode continuar pressionando Enviar. Você será levado ao índice de Firefly III.', 'stored_new_accounts_new_user' => 'Yay! Suas novas contas foram armazenadas.', + 'set_preferred_language' => 'If you prefer to use Firefly III in another language, please indicate so here.', + 'language' => 'Language', + 'new_savings_account' => ':bank_name savings account', + 'cash_wallet' => 'Cash wallet', // home page: 'yourAccounts' => 'Suas contas', @@ -941,6 +962,7 @@ return [ 'account_role_sharedAsset' => 'Contas de ativos compartilhadas', 'account_role_savingAsset' => 'Conta poupança', 'account_role_ccAsset' => 'Cartão de crédito', + 'account_role_cashWalletAsset' => 'Cash wallet', 'budget_chart_click' => 'Clique no nome do orçamento na tabela acima para ver um gráfico.', 'category_chart_click' => 'Clique no nome da categoria na tabela acima para ver um gráfico.', 'in_out_accounts' => 'Ganhou e gastou por combinação', @@ -1000,6 +1022,7 @@ return [ 'events' => 'Eventos', 'target_amount' => 'Valor alvo', 'start_date' => 'Data de Início', + 'no_start_date' => 'No start date', 'target_date' => 'Data Alvo', 'no_target_date' => 'Nenhum data', 'table' => 'Tabela', @@ -1136,6 +1159,14 @@ return [ 'import_index_title' => 'Importar dados para o Firefly III', 'import_index_sub_title' => 'Índice', 'import_general_index_intro' => 'Bem-vindo à rotina de importação do Firefly III. Existem algumas maneiras de importar dados no Firefly III, exibidos aqui como botões.', + 'upload_error' => 'The file you have uploaded could not be processed. Possibly it is of an invalid file type or encoding. The log files will have more information.', + 'reset_import_settings_title' => 'Reset import configuration', + 'reset_import_settings_text' => 'You can use these links to reset your import settings for specific providers. This is useful when bad settings stop you from importing data.', + 'reset_settings_bunq' => 'Remove bunq API key, local external IP address and bunq related RSA keys.', + 'reset_settings_spectre' => 'Remove Spectre client ID, service secret and app secret. This will also remove your Spectre keypair. Remember to update the new one.', + 'settings_reset_for_bunq' => 'Bunq settings reset.', + 'settings_reset_for_spectre' => 'Spectre settings reset.', + // sandstorm.io errors and messages: 'sandstorm_not_available' => 'Esta função não está disponível quando você está usando o Firefly III dentro de um ambiente Sandstorm.io.', diff --git a/resources/lang/pt_BR/form.php b/resources/lang/pt_BR/form.php index f33c53817e..803c7dd402 100644 --- a/resources/lang/pt_BR/form.php +++ b/resources/lang/pt_BR/form.php @@ -1,5 +1,6 @@ 'Valor Mínimo', 'amount_max' => 'Valor Máximo', 'match' => 'Corresponde em', + 'strict' => 'Strict mode', 'repeat_freq' => 'Repetições', 'journal_currency_id' => 'Moeda', 'currency_id' => 'Moeda', + 'transaction_currency_id' => 'Currency', + 'external_ip' => 'Your server\'s external IP', 'attachments' => 'Anexos', 'journal_amount' => 'Quantia', 'journal_source_account_name' => 'Conta de receita (fonte)', diff --git a/resources/lang/pt_BR/import.php b/resources/lang/pt_BR/import.php index 699dc13613..b921c4434e 100644 --- a/resources/lang/pt_BR/import.php +++ b/resources/lang/pt_BR/import.php @@ -164,6 +164,7 @@ return [ // bunq 'bunq_prerequisites_title' => 'Pré-requisitos para uma importação de bunq', 'bunq_prerequisites_text' => 'In order to import from bunq, you need to obtain an API key. You can do this through the app. Please note that the import function for bunq is in BETA. It has only been tested against the sandbox API.', + 'bunq_prerequisites_text_ip' => 'Bunq requires your externally facing IP address. Firefly III has tried to fill this in using the ipify service. Make sure this IP address is correct, or the import will fail.', 'bunq_do_import' => 'Yes, import from this account', 'bunq_accounts_title' => 'Bunq accounts', 'bunq_accounts_text' => 'These are the accounts associated with your bunq account. Please select the accounts from which you want to import, and in which account the transactions must be imported.', diff --git a/resources/lang/pt_BR/intro.php b/resources/lang/pt_BR/intro.php index bc5d9f09b5..78dcfa7e3b 100644 --- a/resources/lang/pt_BR/intro.php +++ b/resources/lang/pt_BR/intro.php @@ -1,5 +1,6 @@ 'Todas as adições ou remoções também estão listadas aqui.', // bill index + 'bills_index_rules' => 'Here you see which rules will check if this bill is hit', 'bills_index_paid_in_period' => 'Este campo indica quando a conta foi paga pela última vez.', 'bills_index_expected_in_period' => 'Este campo indica, para cada conta, se e quando a próxima fatura é esperada para cair em conta.', @@ -100,11 +102,12 @@ return [ 'bills_show_billChart' => 'Este gráfico mostra as operações vinculadas a este projeto.', // create bill + 'bills_create_intro' => 'Use bills to track the amount of money you\'re due every period. Think about expenses like rent, insurance or mortgage payments.', 'bills_create_name' => 'Use um nome descritivo como "Aluguel" ou "Seguro de saúde".', - 'bills_create_match' => 'Para juntar ou combinar transações, use termos ou indexadores dessas transações, você também pode usar a conta de despesas envolvida. Todas as palavras usadas devem ter alguma correspondência.', + //'bills_create_match' => 'To match transactions, use terms from those transactions or the expense account involved. All words must match.', 'bills_create_amount_min_holder' => 'Selecione um valor mínimo e máximo para esta conta.', 'bills_create_repeat_freq_holder' => 'A maioria das contas são repetidas mensalmente, como no caso de pagamentos fixos mensais. Mas você pode definir outra frequência neste menu aqui.', - 'bills_create_skip_holder' => 'Se uma conta se repete a cada 2 semanas, por exemplo, o campo "ignorar" deve ser definido como "1" para ignorar todas as outras semanas.', + 'bills_create_skip_holder' => 'If a bill repeats every 2 weeks, the "skip"-field should be set to "1" to skip every other week.', // rules index 'rules_index_intro' => 'O Firefly III permite que você gerencie as regras, que serão automaticamente aplicadas a qualquer transação que você crie ou edite.', diff --git a/resources/lang/pt_BR/list.php b/resources/lang/pt_BR/list.php index 4a31b17fe2..b06db5f849 100644 --- a/resources/lang/pt_BR/list.php +++ b/resources/lang/pt_BR/list.php @@ -33,6 +33,7 @@ return [ 'name' => 'Nome', 'role' => 'Papel', 'currentBalance' => 'Saldo atual', + 'linked_to_rules' => 'Relevant rules', 'active' => 'Está ativo?', 'lastActivity' => 'Última atividade', 'balanceDiff' => 'Diferença de saldo', diff --git a/resources/lang/ru_RU/firefly.php b/resources/lang/ru_RU/firefly.php index f8d510ae6f..accdaceae7 100644 --- a/resources/lang/ru_RU/firefly.php +++ b/resources/lang/ru_RU/firefly.php @@ -267,7 +267,10 @@ return [ 'move_rule_group_down' => 'Переместить группу правил вниз', 'save_rules_by_moving' => 'Сохраните эти правила, переместив их в другую группу правил:', 'make_new_rule' => 'Создать новое правило в группе правил ":title"', + 'rule_is_strict' => 'strict rule', + 'rule_is_not_strict' => 'non-strict rule', 'rule_help_stop_processing' => 'Когда вы установите этот флажок, более поздние правила в этой группе не будут выполняться.', + 'rule_help_strict' => 'In strict rules ALL triggers must fire for the action(s) to be executed. In non-strict rules, ANY trigger is enough for the action(s) to be executed.', 'rule_help_active' => 'Неактивные правила никогда не срабатывают.', 'stored_new_rule' => 'Сохранено новое правило с названием ":title"', 'deleted_rule' => 'Удалено правило с названием ":title"', @@ -345,6 +348,8 @@ return [ 'rule_trigger_budget_is' => 'Бюджет = ":trigger_value"', 'rule_trigger_tag_is_choice' => 'Метка =', 'rule_trigger_tag_is' => 'Метка = ":trigger_value"', + 'rule_trigger_currency_is_choice' => 'Валюта операции - ', + 'rule_trigger_currency_is' => 'Валюта транзакции = ":trigger_value"', 'rule_trigger_has_attachments_choice' => 'Содержит несколько вложений', 'rule_trigger_has_attachments' => 'Содержит как минимум :trigger_value вложений', 'rule_trigger_store_journal' => 'Когда создается транзакция', @@ -404,10 +409,20 @@ return [ 'rule_action_clear_notes_choice' => 'Удалить любые заметки', 'rule_action_clear_notes' => 'Удалить любые заметки', 'rule_action_set_notes_choice' => 'Назначить примечания...', + 'rule_action_link_to_bill_choice' => 'Ссылка на счёт к оплате..', + 'rule_action_link_to_bill' => 'Ссылка на счёт к оплате ":action_value"', 'rule_action_set_notes' => 'Назначить примечания ":action_value"', 'rules_have_read_warning' => 'Вы прочитали предупреждение?', 'apply_rule_warning' => 'Предупреждение: запуск правила (группы) при большом числе выбранных транзакций может занять много времени, и это может привести к тайм-ауту. Если это произойдёт, правило (группа) будут применены к неизвестной части ваших транзакций. Это может серьёзно повредить вашему управлению финансами. Пожалуйста, будьте осторожны.', + 'rulegroup_for_bills_title' => 'Группа правил для счетов к оплате', + 'rulegroup_for_bills_description' => 'Специальная группа для правил, которые включают в себя счета к оплате.', + 'rule_for_bill_title' => 'Автоматически сгенерированное правило для счёта на оплату ":name"', + 'rule_for_bill_description' => 'Это правило было сгенерировано автоматически, чтобы попытаться сопоставить счёт на оплату ":name".', + 'create_rule_for_bill' => 'Создать новое правило для счёта к оплате ":name"', + 'create_rule_for_bill_txt' => 'Вы только что создали новый счёт на оплату под названием ":name", поздравляем! Firefly III может автоматически сопоставлять новые расходы с этим счётом. Например, всякий раз, когда вы платите арендную плату, счёт «аренда» будет связан с соответствующим расходом. Таким образом, Firefly III может точно показать вам, какие счета уже оплачены, а какие ещё нет. Для этого необходимо создать новое правило. Firefly III заполнил некоторые поля разумными значениями по умолчанию. Пожалуйста, убедитесь, что они верны. Если эти значения верны, Firefly III автоматически свяжет правильный расход с правильным счётом на оплату. Проверьте правила, чтобы убедиться, что они верны, и добавьте что-либо, если в правилах есть ошибка.', + 'new_rule_for_bill_title' => 'Правило для счёта на оплату ":name"', + 'new_rule_for_bill_description' => 'Это правило помечает транзакции для счёта на оплату ":name".', // tags 'store_new_tag' => 'Сохранить новую метку', @@ -624,8 +639,8 @@ return [ 'over_budget_warn' => ' Обычно ваш бюджет - около :amount в день. Это :over_amount в день.', // bills: - 'matching_on' => 'Совпадает с', - 'between_amounts' => 'между :low и :high.', + 'match_between_amounts' => 'Сравнение транзакций по счетам к оплате между :low и :high.', + 'bill_related_rules' => 'Rules related to this bill', 'repeats' => 'Повторы', 'connected_journals' => 'Связанные транзакции', 'auto_match_on' => 'Автоматически сверено Firefly III', @@ -635,19 +650,20 @@ return [ 'deleted_bill' => 'Удаленный счёт к оплате ":name"', 'edit_bill' => 'Отредактировать счёт к оплате ":name"', 'more' => 'Больше', - 'rescan_old' => 'Перепроверить старые транзакции', + 'rescan_old' => 'Run rules again, on all transactions', 'update_bill' => 'Обновить счёт на оплату', 'updated_bill' => 'Счёт на оплату ":name" обновлён', 'store_new_bill' => 'Сохранить новый счёт к оплате', 'stored_new_bill' => 'Новый счёт к оплате ":name" сохранён', 'cannot_scan_inactive_bill' => 'Неактивные счета не могут быть перепроверены.', - 'rescanned_bill' => 'Все счеты были перепроверены.', + 'rescanned_bill' => 'Rescanned everything, and linked :total transaction(s) to the bill.', 'average_bill_amount_year' => 'Средняя сумма счёта на оплату (:year)', 'average_bill_amount_overall' => 'Средняя сумма счёта на оплату (за всё время)', 'bill_is_active' => 'Счёт на оплату активен', 'bill_expected_between' => 'Ожидается между :start и :end', 'bill_will_automatch' => 'Счёт будет автоматически связан с подходящими транзакциями', 'skips_over' => 'пропустить', + 'bill_store_error' => 'При создании вашего нового счёта на оплату произошла неожиданная ошибка. Пожалуйста, проверьте log-файлы', // accounts: 'details_for_asset' => 'Детали по основному счёту ":name"', @@ -784,6 +800,7 @@ return [ 'opt_group_sharedAsset' => 'Общие основные счета', 'opt_group_ccAsset' => 'Кредитные карты', 'notes' => 'Заметки', + 'unknown_journal_error' => 'Не удалось сохранить транзакцию. Пожалуйста, проверьте log-файлы.', // new user: 'welcome' => 'Добро пожаловать в Firefly III!', @@ -793,6 +810,10 @@ return [ 'savings_balance_text' => 'Firefly III автоматически создаст сберегательный счёт для вас. По умолчанию на вашем сберегательном счёте не будет денег, но если вы укажете начальный баланс, он будет сохранен.', 'finish_up_new_user' => 'Это всё! Вы можете продолжить, нажав Подтвердить. Вы попадете на главную страницу Firefly III.', 'stored_new_accounts_new_user' => 'Ура! Ваши новые учётные записи сохранены.', + 'set_preferred_language' => 'If you prefer to use Firefly III in another language, please indicate so here.', + 'language' => 'Language', + 'new_savings_account' => ':bank_name savings account', + 'cash_wallet' => 'Cash wallet', // home page: 'yourAccounts' => 'Ваши счета', @@ -941,6 +962,7 @@ return [ 'account_role_sharedAsset' => 'Общий основной счёт', 'account_role_savingAsset' => 'Сберегательный счет', 'account_role_ccAsset' => 'Кредитная карта', + 'account_role_cashWalletAsset' => 'Cash wallet', 'budget_chart_click' => 'Щёлкните по названию бюджета в таблице выше, чтобы увидеть диаграмму.', 'category_chart_click' => 'Щёлкните по названию категории в таблице выше, чтобы увидеть диаграмму.', 'in_out_accounts' => 'Заработано и потрачено в сумме', @@ -1000,6 +1022,7 @@ return [ 'events' => 'События', 'target_amount' => 'Целевая сумма', 'start_date' => 'Дата начала', + 'no_start_date' => 'No start date', 'target_date' => 'Конечная дата', 'no_target_date' => 'Нет конечной даты', 'table' => 'Таблица', @@ -1136,6 +1159,14 @@ return [ 'import_index_title' => 'Импорт данных в Firefly III', 'import_index_sub_title' => 'Главная страница', 'import_general_index_intro' => 'Добро пожаловать в инструмент импорта Firefly III. Существует несколько способов импорта данных в Firefly III, отображаемых здесь в виде кнопок.', + 'upload_error' => 'Невозможно обработать загруженный вами файл. Возможно, это неправильный тип файла или кодировка. Дополнительная информация содержится в log-файлах.', + 'reset_import_settings_title' => 'Reset import configuration', + 'reset_import_settings_text' => 'You can use these links to reset your import settings for specific providers. This is useful when bad settings stop you from importing data.', + 'reset_settings_bunq' => 'Remove bunq API key, local external IP address and bunq related RSA keys.', + 'reset_settings_spectre' => 'Remove Spectre client ID, service secret and app secret. This will also remove your Spectre keypair. Remember to update the new one.', + 'settings_reset_for_bunq' => 'Bunq settings reset.', + 'settings_reset_for_spectre' => 'Spectre settings reset.', + // sandstorm.io errors and messages: 'sandstorm_not_available' => 'Эта функция недоступна, если вы используете Firefly III в среде Sandstorm.io.', diff --git a/resources/lang/ru_RU/form.php b/resources/lang/ru_RU/form.php index c3e18229f0..9215e5410d 100644 --- a/resources/lang/ru_RU/form.php +++ b/resources/lang/ru_RU/form.php @@ -1,5 +1,6 @@ 'Минимальная сумма', 'amount_max' => 'Максимальная сумма', 'match' => 'Ключи для связи', + 'strict' => 'Strict mode', 'repeat_freq' => 'Повторы', 'journal_currency_id' => 'Валюта', 'currency_id' => 'Валюта', + 'transaction_currency_id' => 'Валюта', + 'external_ip' => 'Внешний IP-адрес вашего сервера', 'attachments' => 'Вложения', 'journal_amount' => 'Сумма', 'journal_source_account_name' => 'Доходный счет (источник)', diff --git a/resources/lang/ru_RU/import.php b/resources/lang/ru_RU/import.php index 752551951a..344518bd57 100644 --- a/resources/lang/ru_RU/import.php +++ b/resources/lang/ru_RU/import.php @@ -164,6 +164,7 @@ return [ // bunq 'bunq_prerequisites_title' => 'Требования для импорта из bunq', 'bunq_prerequisites_text' => 'Чтобы импортировать из bunq, вам нужно получить ключ API. Вы можете сделать это через приложение. Обратите внимание, что функция импорта для bunq находится в бета-тестирования. Было протестировано только API песочницы (sandbox).', + 'bunq_prerequisites_text_ip' => 'Для работы с Bunq необходимо указать ваш внешний IP-адрес. Firefly III попытался узнать ваш адрес с помощью службы ipify. Убедитесь, что этот IP-адрес верен, иначе импорт не будет выполнен.', 'bunq_do_import' => 'Да, импортировать с этого счёта', 'bunq_accounts_title' => 'Счета Bunq', 'bunq_accounts_text' => 'Эти счета связаны с вашей учётной записью bunq. Выберите счета, данные о о которых вы хотите импортировать, и счёт, на который будут импортированы транзакции.', diff --git a/resources/lang/ru_RU/intro.php b/resources/lang/ru_RU/intro.php index 103d0efb13..40f7a5dd48 100644 --- a/resources/lang/ru_RU/intro.php +++ b/resources/lang/ru_RU/intro.php @@ -1,5 +1,6 @@ 'Все добавления или изъятия денег из копилки показаны здесь.', // bill index + 'bills_index_rules' => 'Здесь вы видите, на соответствие каким правилам будет проверяться этот счёт на оплату', 'bills_index_paid_in_period' => 'Это поле показывает, когда счёт был оплачен в последний раз.', 'bills_index_expected_in_period' => 'Это поле указывает для каждого счета, когда ожидается следующая оплата по нему.', @@ -100,11 +102,12 @@ return [ 'bills_show_billChart' => 'Эта диаграмма отражает все операции по текущему счёту.', // create bill + 'bills_create_intro' => 'Используйте счета, чтобы отслеживать суммы денег, которое вы должны заплатить за каждый период. Подумайте о расходах, таких как аренда, страхование или ипотечные платежи.', 'bills_create_name' => 'Используйте понятные названия, например «Аренда» или «Расходы на лечение».', - 'bills_create_match' => 'Чтобы сопоставлять транзакции, используйте поля этих транзакций или счета расходов. Все слова должны совпадать.', + //'bills_create_match' => 'To match transactions, use terms from those transactions or the expense account involved. All words must match.', 'bills_create_amount_min_holder' => 'Выберите минимальную и максимальную сумму для этого счета.', 'bills_create_repeat_freq_holder' => 'Обычно счета к оплате выставляются раз в месяц, но здесь вы можете указать другую периодичность.', - 'bills_create_skip_holder' => 'Если счёт выставляется, например, каждые 2 недели, в поле "пропустить" нужно поставить "1", чтобы пропускать все прочие недели.', + 'bills_create_skip_holder' => 'Если счёт выставляется каждые 2 недели, в поле "пропустить" нужно поставить "1", чтобы пропускать все прочие недели.', // rules index 'rules_index_intro' => 'Firefly III позволяет вам использовать правилами, которые автоматически применяются к любой транзакции, которую вы создаёте или редактируете.', diff --git a/resources/lang/ru_RU/list.php b/resources/lang/ru_RU/list.php index 705f58bde8..de0d9a1252 100644 --- a/resources/lang/ru_RU/list.php +++ b/resources/lang/ru_RU/list.php @@ -33,6 +33,7 @@ return [ 'name' => 'Имя', 'role' => 'Роль', 'currentBalance' => 'Текущий баланс', + 'linked_to_rules' => 'Подходящие правила', 'active' => 'Активен?', 'lastActivity' => 'Последняя активность', 'balanceDiff' => 'Разность баланса', diff --git a/resources/lang/tr_TR/firefly.php b/resources/lang/tr_TR/firefly.php index 9840b4ce6a..7bd17fc375 100644 --- a/resources/lang/tr_TR/firefly.php +++ b/resources/lang/tr_TR/firefly.php @@ -267,7 +267,10 @@ return [ 'move_rule_group_down' => 'Grup kuralını aşağı taşı', 'save_rules_by_moving' => 'Bu kuralları başka bir kural grubuna taşıyarak kaydedin:', 'make_new_rule' => '":title" kural grubunda yeni kural oluşturun', + 'rule_is_strict' => 'strict rule', + 'rule_is_not_strict' => 'non-strict rule', 'rule_help_stop_processing' => 'Bu kutuyu işaretlediğinizde, bu grupta sonraki kurallar yürütülemez.', + 'rule_help_strict' => 'In strict rules ALL triggers must fire for the action(s) to be executed. In non-strict rules, ANY trigger is enough for the action(s) to be executed.', 'rule_help_active' => 'Aktif olmayan kurallar asla çalışmaz.', 'stored_new_rule' => '":title" başlığıyla saklanmış yeni kural', 'deleted_rule' => '":title" başlığıyla saklanmış kuralı sil', @@ -346,6 +349,8 @@ işlemlerin kontrol edildiğini lütfen unutmayın.', 'rule_trigger_budget_is' => 'Bütçe ":trigger_value"', 'rule_trigger_tag_is_choice' => '(A) etiketi..', 'rule_trigger_tag_is' => 'Bir etiket ":trigger_value"', + 'rule_trigger_currency_is_choice' => 'Transaction currency is..', + 'rule_trigger_currency_is' => 'Transaction currency is ":trigger_value"', 'rule_trigger_has_attachments_choice' => 'En son bir çok eklentileri var', 'rule_trigger_has_attachments' => 'En azından :trigger_value eklentisine(eklentilerine) sahip olsun', 'rule_trigger_store_journal' => 'Bir işlem oluşturulduğunda', @@ -405,10 +410,20 @@ işlemlerin kontrol edildiğini lütfen unutmayın.', 'rule_action_clear_notes_choice' => 'Herhangi bir notu kaldır', 'rule_action_clear_notes' => 'Herhangi bir notu kaldır', 'rule_action_set_notes_choice' => 'Notları şuna ayarla..', + 'rule_action_link_to_bill_choice' => 'Link to a bill..', + 'rule_action_link_to_bill' => 'Link to bill ":action_value"', 'rule_action_set_notes' => 'Notları ":action_value" olarak ayarla', 'rules_have_read_warning' => 'Uyarıyı okudun mu?', 'apply_rule_warning' => 'Uyarı: çok sayıda işleme bir kuralı(grubu) uygulamak çok zaman alabilir ve zaman aşımına uğrayabilir. Eğer öyle olursa kural(grup) işlemlerin belli olmayan bir kısmına uygulanacaktır. Bu mali yönetiminizi lime lime edebilir. Lütfen dikkatli olun.', + 'rulegroup_for_bills_title' => 'Rule group for bills', + 'rulegroup_for_bills_description' => 'A special rule group for all the rules that involve bills.', + 'rule_for_bill_title' => 'Auto-generated rule for bill ":name"', + 'rule_for_bill_description' => 'This rule is auto-generated to try to match bill ":name".', + 'create_rule_for_bill' => 'Create a new rule for bill ":name"', + 'create_rule_for_bill_txt' => 'You have just created a new bill called ":name", congratulations! Firefly III can automagically match new withdrawals to this bill. For example, whenever you pay your rent, the bill "rent" will be linked to the expense. This way, Firefly III can accurately show you which bills are due and which ones aren\'t. In order to do so, a new rule must be created. Firefly III has filled in some sensible defaults for you. Please make sure these are correct. If these values are correct, Firefly III will automatically link the correct withdrawal to the correct bill. Please check out the triggers to see if they are correct, and add some if they\'re wrong.', + 'new_rule_for_bill_title' => 'Rule for bill ":name"', + 'new_rule_for_bill_description' => 'This rule marks transactions for bill ":name".', // tags 'store_new_tag' => 'Yeni etiket kaydet', @@ -625,8 +640,8 @@ işlemlerin kontrol edildiğini lütfen unutmayın.', 'over_budget_warn' => ' Normally you budget about :amount per day. This is :over_amount per day.', // bills: - 'matching_on' => 'Eşleşti', - 'between_amounts' => ':low ve :high arasında.', + 'match_between_amounts' => 'Bill matches transactions between :low and :high.', + 'bill_related_rules' => 'Rules related to this bill', 'repeats' => 'Tekrarlar', 'connected_journals' => 'İlişkili işlemler', 'auto_match_on' => 'Automatically matched by Firefly III', @@ -636,19 +651,20 @@ işlemlerin kontrol edildiğini lütfen unutmayın.', 'deleted_bill' => 'Silinmiş fatura ":name"', 'edit_bill' => 'Fatura düzenle ":name"', 'more' => 'Daha', - 'rescan_old' => 'Eski işlemleri yeniden tara', + 'rescan_old' => 'Run rules again, on all transactions', 'update_bill' => 'Faturayı güncelle', 'updated_bill' => 'Güncellenmiş fatura ":name"', 'store_new_bill' => 'Yeni fatura kaydet', 'stored_new_bill' => 'Yeni fatura ":name" kaydedildi', 'cannot_scan_inactive_bill' => 'Etkin olmayan faturalar taranamaz.', - 'rescanned_bill' => 'Her şeyi yeniden araştırdım.', + 'rescanned_bill' => 'Rescanned everything, and linked :total transaction(s) to the bill.', 'average_bill_amount_year' => 'Ortalama fatura tutarı (:year)', 'average_bill_amount_overall' => 'Ortalama fatura tutarı (genel)', 'bill_is_active' => 'Fatura aktif', 'bill_expected_between' => ':start ve :end arasında beklenen', 'bill_will_automatch' => 'Fatura uygun işlemlere otomatik olarak bağlandı', 'skips_over' => 'atla', + 'bill_store_error' => 'An unexpected error occurred while storing your new bill. Please check the log files', // accounts: 'details_for_asset' => '":name" Varlık hesabı ayrıntıları', @@ -785,6 +801,7 @@ işlemlerin kontrol edildiğini lütfen unutmayın.', 'opt_group_sharedAsset' => 'Paylaşılan varlık hesapları', 'opt_group_ccAsset' => 'Kredi Kartı', 'notes' => 'Notes', + 'unknown_journal_error' => 'Could not store the transaction. Please check the log files.', // new user: 'welcome' => 'Welcome to Firefly III!', @@ -794,6 +811,10 @@ işlemlerin kontrol edildiğini lütfen unutmayın.', 'savings_balance_text' => 'Firefly III sizin için otomatik olarak bir birikim hesabı oluşturacaktır. Varsayılan olarak birikim hesabınızda hiç para olmayacaktır ama Firefly III\'e dengelemesini söylerseniz o şekilde saklayacaktır.', 'finish_up_new_user' => 'İşte bu! Submit tıklayarak devam edebilirsiniz. Firefly III Anasayfasına yönlendirileceksiniz.', 'stored_new_accounts_new_user' => 'Yuppi! Yeni hesabınız kaydedildi.', + 'set_preferred_language' => 'If you prefer to use Firefly III in another language, please indicate so here.', + 'language' => 'Language', + 'new_savings_account' => ':bank_name savings account', + 'cash_wallet' => 'Cash wallet', // home page: 'yourAccounts' => 'Hesaplarınız', @@ -942,6 +963,7 @@ işlemlerin kontrol edildiğini lütfen unutmayın.', 'account_role_sharedAsset' => 'Paylaşılan varlık hesabı', 'account_role_savingAsset' => 'Birikim hesabı', 'account_role_ccAsset' => 'Kredi Kartı', + 'account_role_cashWalletAsset' => 'Cash wallet', 'budget_chart_click' => 'Bir grafik görmek için lütfen yukarıdaki tabloda bir bütçe adına tıklayın.', 'category_chart_click' => 'Bir grafik görmek için lütfen yukarıdaki tabloda bir kategori adına tıklayın.', 'in_out_accounts' => 'Kazanılan ve kombinasyon başına harcanan', @@ -1001,6 +1023,7 @@ işlemlerin kontrol edildiğini lütfen unutmayın.', 'events' => 'Etkinlikler', 'target_amount' => 'Hedef miktar', 'start_date' => 'Başlangıç Tarihi', + 'no_start_date' => 'No start date', 'target_date' => 'Hedeflenen tarih', 'no_target_date' => 'Hedef tarihi yok', 'table' => 'Tablo', @@ -1137,6 +1160,14 @@ işlemlerin kontrol edildiğini lütfen unutmayın.', 'import_index_title' => 'Firefly III\'e veri aktarma', 'import_index_sub_title' => 'İndeks', 'import_general_index_intro' => 'Welcome to Firefly III\'s import routine. There are a few ways of importing data into Firefly III, displayed here as buttons.', + 'upload_error' => 'The file you have uploaded could not be processed. Possibly it is of an invalid file type or encoding. The log files will have more information.', + 'reset_import_settings_title' => 'Reset import configuration', + 'reset_import_settings_text' => 'You can use these links to reset your import settings for specific providers. This is useful when bad settings stop you from importing data.', + 'reset_settings_bunq' => 'Remove bunq API key, local external IP address and bunq related RSA keys.', + 'reset_settings_spectre' => 'Remove Spectre client ID, service secret and app secret. This will also remove your Spectre keypair. Remember to update the new one.', + 'settings_reset_for_bunq' => 'Bunq settings reset.', + 'settings_reset_for_spectre' => 'Spectre settings reset.', + // sandstorm.io errors and messages: 'sandstorm_not_available' => 'Bir Sandstorm.io ortamında Firefly III kullanıyorsanız, bu işlev kullanılamaz.', diff --git a/resources/lang/tr_TR/form.php b/resources/lang/tr_TR/form.php index d5f0d7c58f..b942393dc5 100644 --- a/resources/lang/tr_TR/form.php +++ b/resources/lang/tr_TR/form.php @@ -1,5 +1,6 @@ 'Minimum tutar', 'amount_max' => 'Minimum tutar', 'match' => 'Eşleşti', + 'strict' => 'Strict mode', 'repeat_freq' => 'Tekrarlar', 'journal_currency_id' => 'Para birimi', 'currency_id' => 'Para birimi', + 'transaction_currency_id' => 'Currency', + 'external_ip' => 'Your server\'s external IP', 'attachments' => 'Ekler', 'journal_amount' => 'Tutar', 'journal_source_account_name' => 'Gelir hesabı (kaynak)', diff --git a/resources/lang/tr_TR/import.php b/resources/lang/tr_TR/import.php index d4a9f22d4b..fed9f49675 100644 --- a/resources/lang/tr_TR/import.php +++ b/resources/lang/tr_TR/import.php @@ -164,6 +164,7 @@ return [ // bunq 'bunq_prerequisites_title' => 'Bunq\'dan içeri aktarım için şartlar', 'bunq_prerequisites_text' => 'In order to import from bunq, you need to obtain an API key. You can do this through the app. Please note that the import function for bunq is in BETA. It has only been tested against the sandbox API.', + 'bunq_prerequisites_text_ip' => 'Bunq requires your externally facing IP address. Firefly III has tried to fill this in using the ipify service. Make sure this IP address is correct, or the import will fail.', 'bunq_do_import' => 'Yes, import from this account', 'bunq_accounts_title' => 'Bunq accounts', 'bunq_accounts_text' => 'These are the accounts associated with your bunq account. Please select the accounts from which you want to import, and in which account the transactions must be imported.', diff --git a/resources/lang/tr_TR/intro.php b/resources/lang/tr_TR/intro.php index e014c745c0..ed21bd0c27 100644 --- a/resources/lang/tr_TR/intro.php +++ b/resources/lang/tr_TR/intro.php @@ -1,5 +1,6 @@ 'Herhangi bir ekleme veya çıkarma işlemi de burada listelenmektedir.', // bill index + 'bills_index_rules' => 'Here you see which rules will check if this bill is hit', 'bills_index_paid_in_period' => 'Bu alan faturanın en son ne zaman ödendiğini gösterir.', 'bills_index_expected_in_period' => 'Bu alan, her fatura için, eğer ödenmesi gerekiyorsa bir sonraki faturanın ne zaman ödeneceğini gösterir.', @@ -100,11 +102,12 @@ return [ 'bills_show_billChart' => 'Bu tablo, bu faturaya ilişkilendirilmiş işlemleri gösterir.', // create bill + 'bills_create_intro' => 'Use bills to track the amount of money you\'re due every period. Think about expenses like rent, insurance or mortgage payments.', 'bills_create_name' => '"Kira" veya "Sağlık sigortası" gibi açıklayıcı bir isim kullanın.', - 'bills_create_match' => 'İşlemleri eşleştirmek için, bu işlemlerden veya ilgili gider hesabından gelen terimleri kullanın. Tüm kelimeler eşleşmelidir.', + //'bills_create_match' => 'To match transactions, use terms from those transactions or the expense account involved. All words must match.', 'bills_create_amount_min_holder' => 'Bu fatura için minimum ve maksimum bir tutar seçin.', 'bills_create_repeat_freq_holder' => 'Birçok fatura aylık yinelenir, fakat burada başka bir sıklık ayarlayabilirsiniz.', - 'bills_create_skip_holder' => 'Örneğin bir fatura her 2 haftada yineleniyorsa, "atla" alanı iki haftada bir atlaması için "1" olarak ayarlanmalıdır.', + 'bills_create_skip_holder' => 'If a bill repeats every 2 weeks, the "skip"-field should be set to "1" to skip every other week.', // rules index 'rules_index_intro' => 'Firefly III, oluşturduğunuz veya düzenlediğiniz herhangi bir işleme otomatik olarak uygulanacak olan kuralları yönetmenize olanak verir.', diff --git a/resources/lang/tr_TR/list.php b/resources/lang/tr_TR/list.php index 2fb18e1762..c5f8214411 100644 --- a/resources/lang/tr_TR/list.php +++ b/resources/lang/tr_TR/list.php @@ -33,6 +33,7 @@ return [ 'name' => 'İsim', 'role' => 'Rol', 'currentBalance' => 'Cari bakiye', + 'linked_to_rules' => 'Relevant rules', 'active' => 'Aktif mi?', 'lastActivity' => 'Son Etkinlik', 'balanceDiff' => 'Bakiye farkı', From fb75e2ef02419414eaa7cb6bd01465d0436fcdc4 Mon Sep 17 00:00:00 2001 From: James Cole Date: Sat, 21 Apr 2018 21:09:56 +0200 Subject: [PATCH 066/117] Move to MariaDB. [skip ci] #1366 --- docker-compose.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker-compose.yml b/docker-compose.yml index b11f7a38e1..28210fcf1b 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -34,7 +34,7 @@ services: - MYSQL_USER=firefly_db - MYSQL_PASSWORD=firefly_db_secret - MYSQL_RANDOM_ROOT_PASSWORD=yes - image: "mysql:latest" + image: "mariadb:latest" networks: - firefly_iii_net volumes: From 36329e596eae518eb979e0286200b27c4600e7b8 Mon Sep 17 00:00:00 2001 From: James Cole Date: Sat, 21 Apr 2018 23:48:54 +0200 Subject: [PATCH 067/117] Fix #1334 --- app/Factory/PiggyBankEventFactory.php | 4 +- app/Http/Controllers/PiggyBankController.php | 192 +++++++++++------- app/Http/Requests/PiggyBankFormRequest.php | 1 - .../PiggyBank/PiggyBankRepository.php | 36 +++- .../PiggyBankRepositoryInterface.php | 13 +- app/Transformers/AccountTransformer.php | 16 +- app/Transformers/PiggyBankTransformer.php | 59 ++++-- resources/views/list/piggy-banks.twig | 48 ++--- resources/views/piggy-banks/add-mobile.twig | 4 +- resources/views/piggy-banks/add.twig | 6 +- resources/views/piggy-banks/create.twig | 2 +- resources/views/piggy-banks/edit.twig | 2 +- resources/views/piggy-banks/index.twig | 22 +- .../views/piggy-banks/remove-mobile.twig | 6 +- resources/views/piggy-banks/remove.twig | 6 +- 15 files changed, 263 insertions(+), 154 deletions(-) diff --git a/app/Factory/PiggyBankEventFactory.php b/app/Factory/PiggyBankEventFactory.php index 441bc9a130..d55ba7dc8f 100644 --- a/app/Factory/PiggyBankEventFactory.php +++ b/app/Factory/PiggyBankEventFactory.php @@ -62,8 +62,8 @@ class PiggyBankEventFactory $piggyRepos->setUser($journal->user); // repetition exists? - $repetition = $piggyRepos->getRepetition($piggyBank, $journal->date); - if (null === $repetition->id) { + $repetition = $piggyRepos->getRepetition($piggyBank); + if (null === $repetition) { Log::error(sprintf('No piggy bank repetition on %s!', $journal->date->format('Y-m-d'))); return null; diff --git a/app/Http/Controllers/PiggyBankController.php b/app/Http/Controllers/PiggyBankController.php index e4b79dc5ea..8b73c8fb14 100644 --- a/app/Http/Controllers/PiggyBankController.php +++ b/app/Http/Controllers/PiggyBankController.php @@ -25,13 +25,18 @@ namespace FireflyIII\Http\Controllers; use Carbon\Carbon; use FireflyIII\Http\Requests\PiggyBankFormRequest; use FireflyIII\Models\PiggyBank; +use FireflyIII\Repositories\Account\AccountRepositoryInterface; +use FireflyIII\Repositories\Currency\CurrencyRepositoryInterface; use FireflyIII\Repositories\PiggyBank\PiggyBankRepositoryInterface; +use FireflyIII\Transformers\AccountTransformer; +use FireflyIII\Transformers\PiggyBankTransformer; use Illuminate\Http\Request; use Illuminate\Pagination\LengthAwarePaginator; +use Illuminate\Support\Collection; use Log; use Preferences; use Session; -use Steam; +use Symfony\Component\HttpFoundation\ParameterBag; use View; /** @@ -39,6 +44,14 @@ use View; */ class PiggyBankController extends Controller { + + /** @var AccountRepositoryInterface */ + private $accountRepos; + /** @var CurrencyRepositoryInterface */ + private $currencyRepos; + /** @var PiggyBankRepositoryInterface */ + private $piggyRepos; + /** * */ @@ -51,6 +64,10 @@ class PiggyBankController extends Controller app('view')->share('title', trans('firefly.piggyBanks')); app('view')->share('mainTitleIcon', 'fa-sort-amount-asc'); + $this->piggyRepos = app(PiggyBankRepositoryInterface::class); + $this->currencyRepos = app(CurrencyRepositoryInterface::class); + $this->accountRepos = app(AccountRepositoryInterface::class); + return $next($request); } ); @@ -59,43 +76,53 @@ class PiggyBankController extends Controller /** * Add money to piggy bank. * - * @param PiggyBank $piggyBank - * - * @param PiggyBankRepositoryInterface $repository + * @param PiggyBank $piggyBank * * @return View */ - public function add(PiggyBank $piggyBank, PiggyBankRepositoryInterface $repository) + public function add(PiggyBank $piggyBank) { /** @var Carbon $date */ $date = session('end', Carbon::now()->endOfMonth()); - $leftOnAccount = $piggyBank->leftOnAccount($date); - $savedSoFar = $repository->getCurrentAmount($piggyBank); + $leftOnAccount = $this->piggyRepos->leftOnAccount($piggyBank, $date); + $savedSoFar = $this->piggyRepos->getCurrentAmount($piggyBank); $leftToSave = bcsub($piggyBank->targetamount, $savedSoFar); $maxAmount = min($leftOnAccount, $leftToSave); - return view('piggy-banks.add', compact('piggyBank', 'maxAmount')); + // get currency: + $currency = app('amount')->getDefaultCurrency(); + $currencyId = (int)$this->accountRepos->getMetaValue($piggyBank->account, 'currency_id'); + if ($currencyId > 0) { + $currency = $this->currencyRepos->findNull($currencyId); + } + + return view('piggy-banks.add', compact('piggyBank', 'maxAmount', 'currency')); } /** * Add money to piggy bank (for mobile devices). * - * @param PiggyBank $piggyBank - * - * @param PiggyBankRepositoryInterface $repository + * @param PiggyBank $piggyBank * * @return View */ - public function addMobile(PiggyBank $piggyBank, PiggyBankRepositoryInterface $repository) + public function addMobile(PiggyBank $piggyBank) { /** @var Carbon $date */ $date = session('end', Carbon::now()->endOfMonth()); - $leftOnAccount = $piggyBank->leftOnAccount($date); - $savedSoFar = $repository->getCurrentAmount($piggyBank); + $leftOnAccount = $this->piggyRepos->leftOnAccount($piggyBank, $date); + $savedSoFar = $this->piggyRepos->getCurrentAmount($piggyBank); $leftToSave = bcsub($piggyBank->targetamount, $savedSoFar); $maxAmount = min($leftOnAccount, $leftToSave); - return view('piggy-banks.add-mobile', compact('piggyBank', 'maxAmount')); + // get currency: + $currency = app('amount')->getDefaultCurrency(); + $currencyId = (int)$this->accountRepos->getMetaValue($piggyBank->account, 'currency_id'); + if ($currencyId > 0) { + $currency = $this->currencyRepos->findNull($currencyId); + } + + return view('piggy-banks.add-mobile', compact('piggyBank', 'maxAmount', 'currency')); } /** @@ -131,16 +158,15 @@ class PiggyBankController extends Controller } /** - * @param PiggyBankRepositoryInterface $repository * @param PiggyBank $piggyBank * * @return \Illuminate\Http\RedirectResponse */ - public function destroy(PiggyBankRepositoryInterface $repository, PiggyBank $piggyBank) + public function destroy(PiggyBank $piggyBank) { Session::flash('success', (string)trans('firefly.deleted_piggy_bank', ['name' => $piggyBank->name])); Preferences::mark(); - $repository->destroy($piggyBank); + $this->piggyRepos->destroy($piggyBank); return redirect($this->getPreviousUri('piggy-banks.delete.uri')); } @@ -185,53 +211,52 @@ class PiggyBankController extends Controller /** * @param Request $request - * @param PiggyBankRepositoryInterface $piggyRepository * * @return View */ - public function index(Request $request, PiggyBankRepositoryInterface $piggyRepository) + public function index(Request $request) { - $collection = $piggyRepository->getPiggyBanks(); + $collection = $this->piggyRepos->getPiggyBanks(); $total = $collection->count(); $page = 0 === (int)$request->get('page') ? 1 : (int)$request->get('page'); $pageSize = (int)Preferences::get('listPageSize', 50)->data; + $accounts = []; /** @var Carbon $end */ $end = session('end', Carbon::now()->endOfMonth()); - $accounts = []; - Log::debug('Looping piggues'); - /** @var PiggyBank $piggyBank */ - foreach ($collection as $piggyBank) { + // transform piggies using the transformer: + $parameters = new ParameterBag; + $parameters->set('end', $end); + $transformed = new Collection; + $transformer = new PiggyBankTransformer(new ParameterBag); + $accountTransformer = new AccountTransformer($parameters); + /** @var PiggyBank $piggy */ + foreach ($collection as $piggy) { + $array = $transformer->transform($piggy); + $account = $accountTransformer->transform($piggy->account); + $accountId = $account['id']; + if (!isset($accounts[$accountId])) { + // create new: + $accounts[$accountId] = $account; - $piggyBank->savedSoFar = $piggyRepository->getCurrentAmount($piggyBank); - $piggyBank->percentage = (int)(0 !== bccomp('0', $piggyBank->savedSoFar) ? $piggyBank->savedSoFar / $piggyBank->targetamount * 100 : 0); - $piggyBank->leftToSave = bcsub($piggyBank->targetamount, (string)$piggyBank->savedSoFar); - $piggyBank->percentage = $piggyBank->percentage > 100 ? 100 : $piggyBank->percentage; + // add some interesting details: + $accounts[$accountId]['left'] = $accounts[$accountId]['current_balance']; + $accounts[$accountId]['saved'] = 0; + $accounts[$accountId]['target'] = 0; + $accounts[$accountId]['to_save'] = 0; + } - // Fill account information: - $account = $piggyBank->account; - $new = false; - if (!isset($accounts[$account->id])) { - $new = true; - $accounts[$account->id] = [ - 'name' => $account->name, - 'balance' => Steam::balanceIgnoreVirtual($account, $end), - 'leftForPiggyBanks' => $piggyBank->leftOnAccount($end), - 'sumOfSaved' => (string)$piggyBank->savedSoFar, - 'sumOfTargets' => $piggyBank->targetamount, - 'leftToSave' => $piggyBank->leftToSave, - ]; - } - if (isset($accounts[$account->id]) && false === $new) { - $accounts[$account->id]['sumOfSaved'] = bcadd($accounts[$account->id]['sumOfSaved'], (string)$piggyBank->savedSoFar); - $accounts[$account->id]['sumOfTargets'] = bcadd($accounts[$account->id]['sumOfTargets'], $piggyBank->targetamount); - $accounts[$account->id]['leftToSave'] = bcadd($accounts[$account->id]['leftToSave'], $piggyBank->leftToSave); - } + // calculate new interesting fields: + $accounts[$accountId]['left'] -= $array['current_amount']; + $accounts[$accountId]['saved'] += $array['current_amount']; + $accounts[$accountId]['target'] += $array['target_amount']; + $accounts[$accountId]['to_save'] += ($array['target_amount'] - $array['current_amount']); + $array['account_name'] = $account['name']; + $transformed->push($array); } - // paginate piggy banks - $collection = $collection->slice(($page - 1) * $pageSize, $pageSize); - $piggyBanks = new LengthAwarePaginator($collection, $total, $pageSize, $page); + $transformed = $transformed->slice(($page - 1) * $pageSize, $pageSize); + $piggyBanks = new LengthAwarePaginator($transformed, $total, $pageSize, $page); $piggyBanks->setPath(route('piggy-banks.index')); return view('piggy-banks.index', compact('piggyBanks', 'accounts')); @@ -239,20 +264,19 @@ class PiggyBankController extends Controller /** * @param Request $request - * @param PiggyBankRepositoryInterface $repository * * @return \Illuminate\Http\JsonResponse */ - public function order(Request $request, PiggyBankRepositoryInterface $repository) + public function order(Request $request) { $data = $request->get('order'); // set all users piggy banks to zero: - $repository->reset(); + $this->piggyRepos->reset(); if (is_array($data)) { foreach ($data as $order => $id) { - $repository->setOrder((int)$id, $order + 1); + $this->piggyRepos->setOrder((int)$id, $order + 1); } } @@ -261,17 +285,20 @@ class PiggyBankController extends Controller /** * @param Request $request - * @param PiggyBankRepositoryInterface $repository * @param PiggyBank $piggyBank * * @return \Illuminate\Http\RedirectResponse */ - public function postAdd(Request $request, PiggyBankRepositoryInterface $repository, PiggyBank $piggyBank) + public function postAdd(Request $request, PiggyBank $piggyBank) { $amount = $request->get('amount') ?? '0'; $currency = app('amount')->getDefaultCurrency(); - if ($repository->canAddAmount($piggyBank, $amount)) { - $repository->addAmount($piggyBank, $amount); + $currencyId = (int)$this->accountRepos->getMetaValue($piggyBank->account, 'currency_id'); + if ($currencyId > 0) { + $currency = $this->currencyRepos->findNull($currencyId); + } + if ($this->piggyRepos->canAddAmount($piggyBank, $amount)) { + $this->piggyRepos->addAmount($piggyBank, $amount); Session::flash( 'success', (string)trans( @@ -298,17 +325,20 @@ class PiggyBankController extends Controller /** * @param Request $request - * @param PiggyBankRepositoryInterface $repository * @param PiggyBank $piggyBank * * @return \Illuminate\Http\RedirectResponse */ - public function postRemove(Request $request, PiggyBankRepositoryInterface $repository, PiggyBank $piggyBank) + public function postRemove(Request $request, PiggyBank $piggyBank) { $amount = $request->get('amount') ?? '0'; $currency = app('amount')->getDefaultCurrency(); - if ($repository->canRemoveAmount($piggyBank, $amount)) { - $repository->removeAmount($piggyBank, $amount); + $currencyId = (int)$this->accountRepos->getMetaValue($piggyBank->account, 'currency_id'); + if ($currencyId > 0) { + $currency = $this->currencyRepos->findNull($currencyId); + } + if ($this->piggyRepos->canRemoveAmount($piggyBank, $amount)) { + $this->piggyRepos->removeAmount($piggyBank, $amount); Session::flash( 'success', (string)trans( @@ -341,7 +371,15 @@ class PiggyBankController extends Controller */ public function remove(PiggyBank $piggyBank) { - return view('piggy-banks.remove', compact('piggyBank')); + $repetition = $this->piggyRepos->getRepetition($piggyBank); + // get currency: + $currency = app('amount')->getDefaultCurrency(); + $currencyId = (int)$this->accountRepos->getMetaValue($piggyBank->account, 'currency_id'); + if ($currencyId > 0) { + $currency = $this->currencyRepos->findNull($currencyId); + } + + return view('piggy-banks.remove', compact('piggyBank', 'repetition', 'currency')); } /** @@ -353,19 +391,27 @@ class PiggyBankController extends Controller */ public function removeMobile(PiggyBank $piggyBank) { - return view('piggy-banks.remove-mobile', compact('piggyBank')); + $repetition = $this->piggyRepos->getRepetition($piggyBank); + // get currency: + $currency = app('amount')->getDefaultCurrency(); + $currencyId = (int)$this->accountRepos->getMetaValue($piggyBank->account, 'currency_id'); + if ($currencyId > 0) { + $currency = $this->currencyRepos->findNull($currencyId); + } + + + return view('piggy-banks.remove-mobile', compact('piggyBank', 'repetition', 'currency')); } /** - * @param PiggyBankRepositoryInterface $repository * @param PiggyBank $piggyBank * * @return View */ - public function show(PiggyBankRepositoryInterface $repository, PiggyBank $piggyBank) + public function show(PiggyBank $piggyBank) { $note = $piggyBank->notes()->first(); - $events = $repository->getEvents($piggyBank); + $events = $this->piggyRepos->getEvents($piggyBank); $subTitle = $piggyBank->name; return view('piggy-banks.show', compact('piggyBank', 'events', 'subTitle', 'note')); @@ -373,17 +419,16 @@ class PiggyBankController extends Controller /** * @param PiggyBankFormRequest $request - * @param PiggyBankRepositoryInterface $repository * * @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector */ - public function store(PiggyBankFormRequest $request, PiggyBankRepositoryInterface $repository) + public function store(PiggyBankFormRequest $request) { $data = $request->getPiggyBankData(); if (null === $data['startdate']) { $data['startdate'] = new Carbon; } - $piggyBank = $repository->store($data); + $piggyBank = $this->piggyRepos->store($data); Session::flash('success', (string)trans('firefly.stored_piggy_bank', ['name' => $piggyBank->name])); Preferences::mark(); @@ -400,16 +445,15 @@ class PiggyBankController extends Controller } /** - * @param PiggyBankRepositoryInterface $repository * @param PiggyBankFormRequest $request * @param PiggyBank $piggyBank * * @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector */ - public function update(PiggyBankRepositoryInterface $repository, PiggyBankFormRequest $request, PiggyBank $piggyBank) + public function update(PiggyBankFormRequest $request, PiggyBank $piggyBank) { $data = $request->getPiggyBankData(); - $piggyBank = $repository->update($piggyBank, $data); + $piggyBank = $this->piggyRepos->update($piggyBank, $data); Session::flash('success', (string)trans('firefly.updated_piggy_bank', ['name' => $piggyBank->name])); Preferences::mark(); diff --git a/app/Http/Requests/PiggyBankFormRequest.php b/app/Http/Requests/PiggyBankFormRequest.php index 76cd62e376..fae23428f7 100644 --- a/app/Http/Requests/PiggyBankFormRequest.php +++ b/app/Http/Requests/PiggyBankFormRequest.php @@ -65,7 +65,6 @@ class PiggyBankFormRequest extends Request 'name' => $nameRule, 'account_id' => 'required|belongsToUser:accounts', 'targetamount' => 'required|numeric|more:0', - 'amount_currency_id_targetamount' => 'required|exists:transaction_currencies,id', 'startdate' => 'date', 'targetdate' => 'date|nullable', 'order' => 'integer|min:1', diff --git a/app/Repositories/PiggyBank/PiggyBankRepository.php b/app/Repositories/PiggyBank/PiggyBankRepository.php index aaca349ba8..005dcd7023 100644 --- a/app/Repositories/PiggyBank/PiggyBankRepository.php +++ b/app/Repositories/PiggyBank/PiggyBankRepository.php @@ -197,8 +197,7 @@ class PiggyBankRepository implements PiggyBankRepositoryInterface */ public function getCurrentAmount(PiggyBank $piggyBank): string { - /** @var PiggyBankRepetition $rep */ - $rep = $piggyBank->piggyBankRepetitions()->first(['piggy_bank_repetitions.*']); + $rep = $this->getRepetition($piggyBank); if (null === $rep) { return '0'; } @@ -301,19 +300,40 @@ class PiggyBankRepository implements PiggyBankRepositoryInterface } /** + * @param PiggyBank $piggyBank + * + * @return PiggyBankRepetition|null + */ + public function getRepetition(PiggyBank $piggyBank): ?PiggyBankRepetition + { + return $piggyBank->piggyBankRepetitions()->first(); + } + + /** + * Get for piggy account what is left to put in piggies. + * * @param PiggyBank $piggyBank * @param Carbon $date * - * @return PiggyBankRepetition + * @return string */ - public function getRepetition(PiggyBank $piggyBank, Carbon $date): PiggyBankRepetition + public function leftOnAccount(PiggyBank $piggyBank, Carbon $date): string { - $repetition = $piggyBank->piggyBankRepetitions()->relevantOnDate($date)->first(); - if (null === $repetition) { - return new PiggyBankRepetition; + + $balance = app('steam')->balanceIgnoreVirtual($piggyBank->account, $date); + + /** @var Collection $piggies */ + $piggies = $piggyBank->account->piggyBanks; + + /** @var PiggyBank $current */ + foreach ($piggies as $current) { + $repetition = $this->getRepetition($current); + if(null !== $repetition) { + $balance = bcsub($balance, $repetition->currentamount); + } } - return $repetition; + return $balance; } /** diff --git a/app/Repositories/PiggyBank/PiggyBankRepositoryInterface.php b/app/Repositories/PiggyBank/PiggyBankRepositoryInterface.php index 57fe6ce14b..59e217d2f3 100644 --- a/app/Repositories/PiggyBank/PiggyBankRepositoryInterface.php +++ b/app/Repositories/PiggyBank/PiggyBankRepositoryInterface.php @@ -162,12 +162,21 @@ interface PiggyBankRepositoryInterface public function getPiggyBanksWithAmount(): Collection; /** + * @param PiggyBank $piggyBank + * + * @return PiggyBankRepetition|null + */ + public function getRepetition(PiggyBank $piggyBank): ?PiggyBankRepetition; + + /** + * Get for piggy account what is left to put in piggies. + * * @param PiggyBank $piggyBank * @param Carbon $date * - * @return PiggyBankRepetition + * @return string */ - public function getRepetition(PiggyBank $piggyBank, Carbon $date): PiggyBankRepetition; + public function leftOnAccount(PiggyBank $piggyBank, Carbon $date): string; /** * @param PiggyBank $piggyBank diff --git a/app/Transformers/AccountTransformer.php b/app/Transformers/AccountTransformer.php index 3ff4d66239..c238a28dd8 100644 --- a/app/Transformers/AccountTransformer.php +++ b/app/Transformers/AccountTransformer.php @@ -151,13 +151,15 @@ class AccountTransformer extends TransformerAbstract if ($type !== AccountType::ASSET || (string)$role === '') { $role = null; } - $currencyId = (int)$this->repository->getMetaValue($account, 'currency_id'); - $currencyCode = null; - $decimalPlaces = 2; + $currencyId = (int)$this->repository->getMetaValue($account, 'currency_id'); + $currencyCode = null; + $currencySymbol = null; + $decimalPlaces = 2; if ($currencyId > 0) { - $currency = TransactionCurrency::find($currencyId); - $currencyCode = $currency->code; - $decimalPlaces = $currency->decimal_places; + $currency = TransactionCurrency::find($currencyId); + $currencyCode = $currency->code; + $decimalPlaces = $currency->decimal_places; + $currencySymbol = $currency->symbol; } $date = new Carbon; @@ -196,6 +198,8 @@ class AccountTransformer extends TransformerAbstract 'type' => $type, 'currency_id' => $currencyId, 'currency_code' => $currencyCode, + 'currency_symbol' => $currencySymbol, + 'currency_dp' => $decimalPlaces, 'current_balance' => round(app('steam')->balance($account, $date), $decimalPlaces), 'current_balance_date' => $date->format('Y-m-d'), 'notes' => $this->repository->getNoteText($account), diff --git a/app/Transformers/PiggyBankTransformer.php b/app/Transformers/PiggyBankTransformer.php index 02a4831c8d..4c7172476a 100644 --- a/app/Transformers/PiggyBankTransformer.php +++ b/app/Transformers/PiggyBankTransformer.php @@ -24,8 +24,10 @@ declare(strict_types=1); namespace FireflyIII\Transformers; +use FireflyIII\Models\Account; use FireflyIII\Models\Note; use FireflyIII\Models\PiggyBank; +use FireflyIII\Repositories\Account\AccountRepositoryInterface; use FireflyIII\Repositories\Currency\CurrencyRepositoryInterface; use FireflyIII\Repositories\PiggyBank\PiggyBankRepositoryInterface; use League\Fractal\Resource\Collection as FractalCollection; @@ -116,39 +118,60 @@ class PiggyBankTransformer extends TransformerAbstract */ public function transform(PiggyBank $piggyBank): array { - $account = $piggyBank->account; - $currencyId = (int)$account->getMeta('currency_id'); - $decimalPlaces = 2; + /** @var Account $account */ + $account = $piggyBank->account; + /** @var AccountRepositoryInterface $accountRepos */ + $accountRepos = app(AccountRepositoryInterface::class); + $accountRepos->setUser($account->user); + $currencyId = (int)$accountRepos->getMetaValue($account, 'currency_id'); + + if ($currencyId === 0) { + $currency = app('amount')->getDefaultCurrencyByUser($account->user); + } + if ($currencyId > 0) { /** @var CurrencyRepositoryInterface $repository */ $repository = app(CurrencyRepositoryInterface::class); $repository->setUser($account->user); - $currency = $repository->findNull($currencyId); - $decimalPlaces = $currency->decimal_places; + $currency = $repository->findNull($currencyId); } + $decimalPlaces = $currency->decimal_places; + // get currently saved amount: /** @var PiggyBankRepositoryInterface $piggyRepos */ $piggyRepos = app(PiggyBankRepositoryInterface::class); $piggyRepos->setUser($account->user); - $currentAmount = round($piggyRepos->getCurrentAmount($piggyBank), $decimalPlaces); + // current amount in piggy bank: + $currentAmountStr = $piggyRepos->getCurrentAmount($piggyBank); + $currentAmount = round($currentAmountStr, $decimalPlaces); + + // left to save to target: + $leftToSave = bcsub($piggyBank->targetamount, $currentAmountStr); $startDate = null === $piggyBank->startdate ? null : $piggyBank->startdate->format('Y-m-d'); $targetDate = null === $piggyBank->targetdate ? null : $piggyBank->targetdate->format('Y-m-d'); $targetAmount = round($piggyBank->targetamount, $decimalPlaces); + $percentage = (int)(0 !== bccomp('0', $currentAmountStr) ? $currentAmount / $targetAmount * 100 : 0); $data = [ - 'id' => (int)$piggyBank->id, - 'updated_at' => $piggyBank->updated_at->toAtomString(), - 'created_at' => $piggyBank->created_at->toAtomString(), - 'name' => $piggyBank->name, - 'target_amount' => $targetAmount, - 'current_amount' => $currentAmount, - 'startdate' => $startDate, - 'targetdate' => $targetDate, - 'order' => (int)$piggyBank->order, - 'active' => (int)$piggyBank->active === 1, - 'notes' => null, - 'links' => [ + 'id' => (int)$piggyBank->id, + 'updated_at' => $piggyBank->updated_at->toAtomString(), + 'created_at' => $piggyBank->created_at->toAtomString(), + 'name' => $piggyBank->name, + 'currency_id' => $currency->id, + 'currency_code' => $currency->code, + 'currency_symbol' => $currency->symbol, + 'currency_dp' => $currency->decimal_places, + 'target_amount' => $targetAmount, + 'percentage' => $percentage, + 'current_amount' => $currentAmount, + 'left_to_save' => round($leftToSave, $decimalPlaces), + 'startdate' => $startDate, + 'targetdate' => $targetDate, + 'order' => (int)$piggyBank->order, + 'active' => (int)$piggyBank->active === 1, + 'notes' => null, + 'links' => [ [ 'rel' => 'self', 'uri' => '/piggy_banks/' . $piggyBank->id, diff --git a/resources/views/list/piggy-banks.twig b/resources/views/list/piggy-banks.twig index 241a532f1f..24387cf7b8 100644 --- a/resources/views/list/piggy-banks.twig +++ b/resources/views/list/piggy-banks.twig @@ -13,15 +13,15 @@
    - {{ piggyBank.name }} + {{ piggy.name }} - {{ piggyBank.savedSoFar|formatAmount }} + {{ formatAmountBySymbol(piggy.current_amount,piggy.currency_symbol,piggy.currency_dp) }}
    {{ info.name }}{{ info.leftForPiggyBanks|formatAmount }} + {{ formatAmountBySymbol(info.left,info.currency_symbol,info.currency_dp) }} +
    {{ 'budget'|_ }} {{ 'budgeted'|_ }}{{ 'left'|_ }}{{ 'left'|_ }} ({{ 'per_day'|_|lower }})
    {{ (repAmount + budgetInformation[budget.id]['spent'])|formatAmount }} + {% if repAmount + budgetInformation[budget.id]['spent'] > 0 %} + ({{ ((repAmount + budgetInformation[budget.id]['spent']) / days)|formatAmount }}) + {% endif %}
    {{ 'bill_will_automatch'|_ }} - {% if object.data.automatch %} - {{ 'yes'|_ }} - {% else %} - {{ 'no'|_ }} - {% endif %} -
    {{ 'next_expected_match'|_ }} From 9975e0b3f3ab81cca5554f4fb3aaa0831c0df0cf Mon Sep 17 00:00:00 2001 From: James Cole Date: Sun, 22 Apr 2018 12:01:34 +0200 Subject: [PATCH 078/117] And now without var_dump. --- app/Http/Controllers/Transaction/SingleController.php | 3 --- 1 file changed, 3 deletions(-) diff --git a/app/Http/Controllers/Transaction/SingleController.php b/app/Http/Controllers/Transaction/SingleController.php index e9d9d95ad6..9159793179 100644 --- a/app/Http/Controllers/Transaction/SingleController.php +++ b/app/Http/Controllers/Transaction/SingleController.php @@ -402,9 +402,6 @@ class SingleController extends Controller // keep current bill: $data['bill_id'] = $journal->bill_id; - var_dump($data); - - exit; $journal = $repository->update($journal, $data); /** @var array $files */ From f7d3d4a0105ce5e5870bac5042a4f26363510bdc Mon Sep 17 00:00:00 2001 From: James Cole Date: Sun, 22 Apr 2018 13:14:36 +0200 Subject: [PATCH 079/117] Updated language strings [skip ci] --- resources/lang/de_DE/firefly.php | 8 +++---- resources/lang/de_DE/form.php | 2 ++ resources/lang/es_ES/form.php | 2 ++ resources/lang/fr_FR/form.php | 2 ++ resources/lang/id_ID/form.php | 2 ++ resources/lang/it_IT/firefly.php | 14 ++++++------- resources/lang/it_IT/form.php | 2 ++ resources/lang/nl_NL/firefly.php | 2 +- resources/lang/nl_NL/form.php | 2 ++ resources/lang/pl_PL/firefly.php | 14 ++++++------- resources/lang/pl_PL/form.php | 2 ++ resources/lang/pt_BR/form.php | 2 ++ resources/lang/ru_RU/firefly.php | 36 ++++++++++++++++---------------- resources/lang/ru_RU/form.php | 4 +++- resources/lang/tr_TR/form.php | 2 ++ 15 files changed, 58 insertions(+), 38 deletions(-) diff --git a/resources/lang/de_DE/firefly.php b/resources/lang/de_DE/firefly.php index c161110767..1e6eb6b8d8 100644 --- a/resources/lang/de_DE/firefly.php +++ b/resources/lang/de_DE/firefly.php @@ -1023,7 +1023,7 @@ Sollen zusätzlich Ihre Girokonten angezeigt werden?', 'events' => 'Ereignisse', 'target_amount' => 'Zielbetrag', 'start_date' => 'Startdatum', - 'no_start_date' => 'No start date', + 'no_start_date' => 'Kein Startzeitpunkt', 'target_date' => 'Zieldatum', 'no_target_date' => 'Kein Zieldatum', 'table' => 'Tabelle', @@ -1161,9 +1161,9 @@ Sollen zusätzlich Ihre Girokonten angezeigt werden?', 'import_index_sub_title' => 'Index', 'import_general_index_intro' => 'Willkommen beim Importassistenten von Firefly III. Es gibt einige Möglichkeiten, Daten in Firefly III zu importieren, die hier als Schaltflächen angezeigt werden.', 'upload_error' => 'Die hochgeladene Datei konnte nicht verarbeitet werden. Möglicherweise handelt es sich um einen ungültigen Dateityp oder eine ungültige Kodierung. Die Protokolldateien enthalten weitere Informationen.', - 'reset_import_settings_title' => 'Reset import configuration', - 'reset_import_settings_text' => 'You can use these links to reset your import settings for specific providers. This is useful when bad settings stop you from importing data.', - 'reset_settings_bunq' => 'Remove bunq API key, local external IP address and bunq related RSA keys.', + 'reset_import_settings_title' => 'Importeinstellungen zurücksetzen', + 'reset_import_settings_text' => 'Über diese Links können Sie Ihre Importeinstellungen für bestimmte Anbieter zurücksetzen. Dies ist nützlich, wenn fehlerhafte Einstellungen den Import von Daten verhindern.', + 'reset_settings_bunq' => 'Bunq-API-Schlüssel entfernen (lokale externe IP-Adresse und Bunq-bezogene RSA-Schlüssel).', 'reset_settings_spectre' => 'Remove Spectre client ID, service secret and app secret. This will also remove your Spectre keypair. Remember to update the new one.', 'settings_reset_for_bunq' => 'Bunq settings reset.', 'settings_reset_for_spectre' => 'Spectre settings reset.', diff --git a/resources/lang/de_DE/form.php b/resources/lang/de_DE/form.php index f64c383047..e25e9cdb64 100644 --- a/resources/lang/de_DE/form.php +++ b/resources/lang/de_DE/form.php @@ -94,6 +94,8 @@ return [ 'convert_Transfer' => 'In Umbuchung umwandeln', 'amount' => 'Betrag', + 'foreign_amount' => 'Foreign amount', + 'existing_attachments' => 'Existing attachments', 'date' => 'Datum', 'interest_date' => 'Zinstermin', 'book_date' => 'Buchungsdatum', diff --git a/resources/lang/es_ES/form.php b/resources/lang/es_ES/form.php index b19b567da5..ef07509ddb 100644 --- a/resources/lang/es_ES/form.php +++ b/resources/lang/es_ES/form.php @@ -94,6 +94,8 @@ return [ 'convert_Transfer' => 'Convertir transferencia', 'amount' => 'Importe', + 'foreign_amount' => 'Foreign amount', + 'existing_attachments' => 'Existing attachments', 'date' => 'Fecha', 'interest_date' => 'Fecha de interés', 'book_date' => 'Fecha de registro', diff --git a/resources/lang/fr_FR/form.php b/resources/lang/fr_FR/form.php index 22f929ce5f..1fbd1513ee 100644 --- a/resources/lang/fr_FR/form.php +++ b/resources/lang/fr_FR/form.php @@ -94,6 +94,8 @@ return [ 'convert_Transfer' => 'Convertir le transfert', 'amount' => 'Montant', + 'foreign_amount' => 'Foreign amount', + 'existing_attachments' => 'Existing attachments', 'date' => 'Date', 'interest_date' => 'Date de l’intérêt', 'book_date' => 'Date de réservation', diff --git a/resources/lang/id_ID/form.php b/resources/lang/id_ID/form.php index 17650c0aa0..a56c62c650 100644 --- a/resources/lang/id_ID/form.php +++ b/resources/lang/id_ID/form.php @@ -94,6 +94,8 @@ return [ 'convert_Transfer' => 'Mengkonversi transfer', 'amount' => 'Jumlah', + 'foreign_amount' => 'Foreign amount', + 'existing_attachments' => 'Existing attachments', 'date' => 'Tanggal', 'interest_date' => 'Tanggal bunga', 'book_date' => 'Tanggal buku', diff --git a/resources/lang/it_IT/firefly.php b/resources/lang/it_IT/firefly.php index 7e6b6ef5b5..4610169611 100644 --- a/resources/lang/it_IT/firefly.php +++ b/resources/lang/it_IT/firefly.php @@ -1022,7 +1022,7 @@ return [ 'events' => 'Eventi', 'target_amount' => 'Importo obiettivo', 'start_date' => 'Data inizio', - 'no_start_date' => 'No start date', + 'no_start_date' => 'Nessuna data di inizio', 'target_date' => 'Data fine', 'no_target_date' => 'Nessuna data fine', 'table' => 'Tabella', @@ -1160,12 +1160,12 @@ return [ 'import_index_sub_title' => 'Indice', 'import_general_index_intro' => 'Benvenuti nella routine di importazione di Firefly III. Esistono alcuni modi per importare dati in Firefly III, visualizzati qui come pulsanti.', 'upload_error' => 'Il file che hai caricato non può essere elaborato. Probabilmente è un tipo di file o una codifica non valida. I file di log avranno maggiori informazioni.', - 'reset_import_settings_title' => 'Reset import configuration', - 'reset_import_settings_text' => 'You can use these links to reset your import settings for specific providers. This is useful when bad settings stop you from importing data.', - 'reset_settings_bunq' => 'Remove bunq API key, local external IP address and bunq related RSA keys.', - 'reset_settings_spectre' => 'Remove Spectre client ID, service secret and app secret. This will also remove your Spectre keypair. Remember to update the new one.', - 'settings_reset_for_bunq' => 'Bunq settings reset.', - 'settings_reset_for_spectre' => 'Spectre settings reset.', + 'reset_import_settings_title' => 'Reimposta la configurazione di importazione', + 'reset_import_settings_text' => 'Puoi utilizzare questi collegamenti per ripristinare le impostazioni di importazione per specifici fornitori. Ciò è utile quando delle impostazioni errate impediscono l\'importazione dei dati.', + 'reset_settings_bunq' => 'Rimuovi la chiave API di bunq, l\'indirizzo IP locale esterno e le chiavi RSA correlate a bunq.', + 'reset_settings_spectre' => 'Rimuovi l\'ID cliente di Spectre, il segreto del servizio e il segreto dell\'app. Questo rimuoverà anche la tua coppia di chiavi Spectre. Ricordati di aggiornare quella nuova.', + 'settings_reset_for_bunq' => 'Ripristina impostazioni bunq.', + 'settings_reset_for_spectre' => 'Ripristina impostazioni Spectre.', // sandstorm.io errors and messages: diff --git a/resources/lang/it_IT/form.php b/resources/lang/it_IT/form.php index c6e2274a58..e45b1bb53d 100644 --- a/resources/lang/it_IT/form.php +++ b/resources/lang/it_IT/form.php @@ -94,6 +94,8 @@ return [ 'convert_Transfer' => 'Converti giroconto', 'amount' => 'Importo', + 'foreign_amount' => 'Foreign amount', + 'existing_attachments' => 'Existing attachments', 'date' => 'Data', 'interest_date' => 'Data interesse', 'book_date' => 'Agenda', diff --git a/resources/lang/nl_NL/firefly.php b/resources/lang/nl_NL/firefly.php index f54bc0f679..0df9c63260 100644 --- a/resources/lang/nl_NL/firefly.php +++ b/resources/lang/nl_NL/firefly.php @@ -154,7 +154,7 @@ return [ 'journals_in_period_for_category' => 'Alle transacties in categorie :name tussen :start en :end', 'journals_in_period_for_tag' => 'Alle transacties voor tag :tag tussen :start en :end', 'not_available_demo_user' => 'De functie die je probeert te gebruiken is niet beschikbaar voor gebruikers van de demo.', - 'exchange_rate_instructions' => 'Betaalrekening "@naam" accepteert alleen boekingen in @native_currency. Als je @foreign_currency wilt gebruiken moet je ook het bedrag in @native_currency opgeven:', + 'exchange_rate_instructions' => 'Betaalrekening "@name" accepteert alleen boekingen in @native_currency. Als je @foreign_currency wilt gebruiken moet je ook het bedrag in @native_currency opgeven:', 'transfer_exchange_rate_instructions' => 'Bronbetaalrekening "@source_name" accepteert alleen overschrijvingen in @source_currency. Doelbetaalrekening "@dest_name" accepteert alleen overschrijvingen in @dest_currency. Je moet het juiste bedrag in beide valuta opgeven.', 'transaction_data' => 'Transactiegegevens', 'invalid_server_configuration' => 'Ongeldige serverconfiguratie', diff --git a/resources/lang/nl_NL/form.php b/resources/lang/nl_NL/form.php index e6d202f030..20c8ecbcbd 100644 --- a/resources/lang/nl_NL/form.php +++ b/resources/lang/nl_NL/form.php @@ -94,6 +94,8 @@ return [ 'convert_Transfer' => 'Verander overschrijving', 'amount' => 'Bedrag', + 'foreign_amount' => 'Bedrag in vreemde valuta', + 'existing_attachments' => 'Bestaande bijlagen', 'date' => 'Datum', 'interest_date' => 'Rentedatum', 'book_date' => 'Boekdatum', diff --git a/resources/lang/pl_PL/firefly.php b/resources/lang/pl_PL/firefly.php index 680bfe22b1..fcee9cd56d 100644 --- a/resources/lang/pl_PL/firefly.php +++ b/resources/lang/pl_PL/firefly.php @@ -1022,7 +1022,7 @@ return [ 'events' => 'Zdarzenia', 'target_amount' => 'Kwota docelowa', 'start_date' => 'Data rozpoczęcia', - 'no_start_date' => 'No start date', + 'no_start_date' => 'Brak daty rozpoczęcia', 'target_date' => 'Data docelowa', 'no_target_date' => 'Brak daty docelowej', 'table' => 'Tabela', @@ -1160,12 +1160,12 @@ return [ 'import_index_sub_title' => 'Indeks', 'import_general_index_intro' => 'Witamy w procedurze importu Firefly III. Istnieje kilka sposobów importowania danych do Firefly III.', 'upload_error' => 'Przesłany plik nie może zostać przetworzony. Prawdopodobnie typ pliku lub kodowanie jest błędne. Pliki dziennika zawierają więcej informacji.', - 'reset_import_settings_title' => 'Reset import configuration', - 'reset_import_settings_text' => 'You can use these links to reset your import settings for specific providers. This is useful when bad settings stop you from importing data.', - 'reset_settings_bunq' => 'Remove bunq API key, local external IP address and bunq related RSA keys.', - 'reset_settings_spectre' => 'Remove Spectre client ID, service secret and app secret. This will also remove your Spectre keypair. Remember to update the new one.', - 'settings_reset_for_bunq' => 'Bunq settings reset.', - 'settings_reset_for_spectre' => 'Spectre settings reset.', + 'reset_import_settings_title' => 'Zresetuj konfigurację importu', + 'reset_import_settings_text' => 'Możesz użyć tych linków, aby zresetować ustawienia importu dla konkretnych dostawców. Jest to przydatne, gdy złe ustawienia uniemożliwiają importowanie danych.', + 'reset_settings_bunq' => 'Usuń klucz API, lokalny zewnętrzny adres IP oraz klucze RSA związane z Bunq.', + 'reset_settings_spectre' => 'Usuń identyfikator klienta Spectre, sekret usługi oraz klucz aplikacji. Spowoduje to również usunięcie Twojego klucza Spectre. Pamiętaj, aby zaktualizować nowy.', + 'settings_reset_for_bunq' => 'Resetowanie ustawień Bunq.', + 'settings_reset_for_spectre' => 'Resetowanie ustawień Spectre.', // sandstorm.io errors and messages: diff --git a/resources/lang/pl_PL/form.php b/resources/lang/pl_PL/form.php index d23b4529de..10e23b6c5a 100644 --- a/resources/lang/pl_PL/form.php +++ b/resources/lang/pl_PL/form.php @@ -94,6 +94,8 @@ return [ 'convert_Transfer' => 'Konwertuj transfer', 'amount' => 'Kwota', + 'foreign_amount' => 'Foreign amount', + 'existing_attachments' => 'Existing attachments', 'date' => 'Data', 'interest_date' => 'Data odsetek', 'book_date' => 'Data księgowania', diff --git a/resources/lang/pt_BR/form.php b/resources/lang/pt_BR/form.php index 803c7dd402..1f11628d38 100644 --- a/resources/lang/pt_BR/form.php +++ b/resources/lang/pt_BR/form.php @@ -94,6 +94,8 @@ return [ 'convert_Transfer' => 'Converter a transferência', 'amount' => 'Valor', + 'foreign_amount' => 'Foreign amount', + 'existing_attachments' => 'Existing attachments', 'date' => 'Data', 'interest_date' => 'Data de interesse', 'book_date' => 'Data reserva', diff --git a/resources/lang/ru_RU/firefly.php b/resources/lang/ru_RU/firefly.php index accdaceae7..810fa7b7e1 100644 --- a/resources/lang/ru_RU/firefly.php +++ b/resources/lang/ru_RU/firefly.php @@ -267,10 +267,10 @@ return [ 'move_rule_group_down' => 'Переместить группу правил вниз', 'save_rules_by_moving' => 'Сохраните эти правила, переместив их в другую группу правил:', 'make_new_rule' => 'Создать новое правило в группе правил ":title"', - 'rule_is_strict' => 'strict rule', - 'rule_is_not_strict' => 'non-strict rule', + 'rule_is_strict' => 'строгое правило', + 'rule_is_not_strict' => 'нестрогое правило', 'rule_help_stop_processing' => 'Когда вы установите этот флажок, более поздние правила в этой группе не будут выполняться.', - 'rule_help_strict' => 'In strict rules ALL triggers must fire for the action(s) to be executed. In non-strict rules, ANY trigger is enough for the action(s) to be executed.', + 'rule_help_strict' => 'В строгих правилах действие будет запущено, если ВСЕ триггеры выполнены. Для нестрогих правил достаточно срабатывания одного ЛЮБОГО триггера.', 'rule_help_active' => 'Неактивные правила никогда не срабатывают.', 'stored_new_rule' => 'Сохранено новое правило с названием ":title"', 'deleted_rule' => 'Удалено правило с названием ":title"', @@ -640,7 +640,7 @@ return [ // bills: 'match_between_amounts' => 'Сравнение транзакций по счетам к оплате между :low и :high.', - 'bill_related_rules' => 'Rules related to this bill', + 'bill_related_rules' => 'Правила, связанные с этим счётом на оплату', 'repeats' => 'Повторы', 'connected_journals' => 'Связанные транзакции', 'auto_match_on' => 'Автоматически сверено Firefly III', @@ -650,13 +650,13 @@ return [ 'deleted_bill' => 'Удаленный счёт к оплате ":name"', 'edit_bill' => 'Отредактировать счёт к оплате ":name"', 'more' => 'Больше', - 'rescan_old' => 'Run rules again, on all transactions', + 'rescan_old' => 'Выполнить правила снова, по всем транзакциям', 'update_bill' => 'Обновить счёт на оплату', 'updated_bill' => 'Счёт на оплату ":name" обновлён', 'store_new_bill' => 'Сохранить новый счёт к оплате', 'stored_new_bill' => 'Новый счёт к оплате ":name" сохранён', 'cannot_scan_inactive_bill' => 'Неактивные счета не могут быть перепроверены.', - 'rescanned_bill' => 'Rescanned everything, and linked :total transaction(s) to the bill.', + 'rescanned_bill' => 'Всё было пересчитано и :total транзакций были привязаны к данному счёту на оплату.', 'average_bill_amount_year' => 'Средняя сумма счёта на оплату (:year)', 'average_bill_amount_overall' => 'Средняя сумма счёта на оплату (за всё время)', 'bill_is_active' => 'Счёт на оплату активен', @@ -810,10 +810,10 @@ return [ 'savings_balance_text' => 'Firefly III автоматически создаст сберегательный счёт для вас. По умолчанию на вашем сберегательном счёте не будет денег, но если вы укажете начальный баланс, он будет сохранен.', 'finish_up_new_user' => 'Это всё! Вы можете продолжить, нажав Подтвердить. Вы попадете на главную страницу Firefly III.', 'stored_new_accounts_new_user' => 'Ура! Ваши новые учётные записи сохранены.', - 'set_preferred_language' => 'If you prefer to use Firefly III in another language, please indicate so here.', - 'language' => 'Language', - 'new_savings_account' => ':bank_name savings account', - 'cash_wallet' => 'Cash wallet', + 'set_preferred_language' => 'Если вы предпочитаете использовать Firefly III на другом языке, укажите здесь здесь.', + 'language' => 'Язык', + 'new_savings_account' => 'сберегательный счёт в :bank_name', + 'cash_wallet' => 'Кошелёк с наличными', // home page: 'yourAccounts' => 'Ваши счета', @@ -962,7 +962,7 @@ return [ 'account_role_sharedAsset' => 'Общий основной счёт', 'account_role_savingAsset' => 'Сберегательный счет', 'account_role_ccAsset' => 'Кредитная карта', - 'account_role_cashWalletAsset' => 'Cash wallet', + 'account_role_cashWalletAsset' => 'Кошелёк с наличными', 'budget_chart_click' => 'Щёлкните по названию бюджета в таблице выше, чтобы увидеть диаграмму.', 'category_chart_click' => 'Щёлкните по названию категории в таблице выше, чтобы увидеть диаграмму.', 'in_out_accounts' => 'Заработано и потрачено в сумме', @@ -1022,7 +1022,7 @@ return [ 'events' => 'События', 'target_amount' => 'Целевая сумма', 'start_date' => 'Дата начала', - 'no_start_date' => 'No start date', + 'no_start_date' => 'Нет начальной даты', 'target_date' => 'Конечная дата', 'no_target_date' => 'Нет конечной даты', 'table' => 'Таблица', @@ -1160,12 +1160,12 @@ return [ 'import_index_sub_title' => 'Главная страница', 'import_general_index_intro' => 'Добро пожаловать в инструмент импорта Firefly III. Существует несколько способов импорта данных в Firefly III, отображаемых здесь в виде кнопок.', 'upload_error' => 'Невозможно обработать загруженный вами файл. Возможно, это неправильный тип файла или кодировка. Дополнительная информация содержится в log-файлах.', - 'reset_import_settings_title' => 'Reset import configuration', - 'reset_import_settings_text' => 'You can use these links to reset your import settings for specific providers. This is useful when bad settings stop you from importing data.', - 'reset_settings_bunq' => 'Remove bunq API key, local external IP address and bunq related RSA keys.', - 'reset_settings_spectre' => 'Remove Spectre client ID, service secret and app secret. This will also remove your Spectre keypair. Remember to update the new one.', - 'settings_reset_for_bunq' => 'Bunq settings reset.', - 'settings_reset_for_spectre' => 'Spectre settings reset.', + 'reset_import_settings_title' => 'Сбросить настройки импорта', + 'reset_import_settings_text' => 'Вы можете использовать эти ссылки для сброса настроек импорта для определенных поставщиков. Это полезно, когда плохие настройки не позволяют вам импортировать данные.', + 'reset_settings_bunq' => 'Удалите ключ API bunq, локальный внешний IP-адрес и ключи RSA, связанные с bunq.', + 'reset_settings_spectre' => 'Удалить ID клиента Spectre и секретные ключи. Также будет удалён ваш Spectre keypair. Не забудьте обновить его.', + 'settings_reset_for_bunq' => 'Сброс настроек Bunq.', + 'settings_reset_for_spectre' => 'Сброс настроек Spectre.', // sandstorm.io errors and messages: diff --git a/resources/lang/ru_RU/form.php b/resources/lang/ru_RU/form.php index 9215e5410d..86ce6ae304 100644 --- a/resources/lang/ru_RU/form.php +++ b/resources/lang/ru_RU/form.php @@ -34,7 +34,7 @@ return [ 'amount_min' => 'Минимальная сумма', 'amount_max' => 'Максимальная сумма', 'match' => 'Ключи для связи', - 'strict' => 'Strict mode', + 'strict' => 'Строгий режим', 'repeat_freq' => 'Повторы', 'journal_currency_id' => 'Валюта', 'currency_id' => 'Валюта', @@ -94,6 +94,8 @@ return [ 'convert_Transfer' => 'Конвертировать перевод', 'amount' => 'Сумма', + 'foreign_amount' => 'Foreign amount', + 'existing_attachments' => 'Existing attachments', 'date' => 'Дата', 'interest_date' => 'Дата выплаты', 'book_date' => 'Дата бронирования', diff --git a/resources/lang/tr_TR/form.php b/resources/lang/tr_TR/form.php index b942393dc5..fc4b64e56a 100644 --- a/resources/lang/tr_TR/form.php +++ b/resources/lang/tr_TR/form.php @@ -94,6 +94,8 @@ return [ 'convert_Transfer' => 'Aktarımı dönüştür', 'amount' => 'Tutar', + 'foreign_amount' => 'Foreign amount', + 'existing_attachments' => 'Existing attachments', 'date' => 'Tarih', 'interest_date' => 'Faiz tarihi', 'book_date' => 'Kitap Tarihi', From 8032684ad02a5c3679d46f7ebbf30ae1190b848c Mon Sep 17 00:00:00 2001 From: James Cole Date: Sun, 22 Apr 2018 17:10:11 +0200 Subject: [PATCH 080/117] Some code cleanup for #1272 --- .../Account/ReconcileController.php | 8 +- .../Admin/ConfigurationController.php | 2 +- app/Http/Controllers/Admin/HomeController.php | 2 +- .../Controllers/Admin/UpdateController.php | 2 +- app/Http/Controllers/Admin/UserController.php | 4 +- .../Controllers/Auth/RegisterController.php | 2 +- app/Http/Controllers/Controller.php | 2 +- app/Http/Controllers/NewUserController.php | 2 +- app/Http/Controllers/PiggyBankController.php | 16 +- .../Controllers/PreferencesController.php | 2 +- app/Http/Controllers/ProfileController.php | 26 +- app/Http/Controllers/ReportController.php | 8 +- app/Http/Controllers/RuleController.php | 262 +++++++++--------- app/Http/Controllers/RuleGroupController.php | 8 +- app/Http/Controllers/TagController.php | 6 +- .../Transaction/BulkController.php | 88 ++---- .../Transaction/ConvertController.php | 10 +- .../Transaction/LinkController.php | 10 +- .../Transaction/MassController.php | 8 +- .../Transaction/SingleController.php | 20 +- .../Transaction/SplitController.php | 4 +- app/Support/Binder/SimpleJournalList.php | 111 ++++++++ config/firefly.php | 3 +- routes/web.php | 2 +- 24 files changed, 339 insertions(+), 269 deletions(-) create mode 100644 app/Support/Binder/SimpleJournalList.php diff --git a/app/Http/Controllers/Account/ReconcileController.php b/app/Http/Controllers/Account/ReconcileController.php index 33f80dd1f6..d4b5a0dc60 100644 --- a/app/Http/Controllers/Account/ReconcileController.php +++ b/app/Http/Controllers/Account/ReconcileController.php @@ -100,7 +100,7 @@ class ReconcileController extends Controller 'amount' => $pTransaction->amount, ]; - Session::flash('preFilled', $preFilled); + session()->flash('preFilled', $preFilled); // put previous url in session if not redirect from store (not "return_to_edit"). if (true !== session('reconcile.edit.fromUpdate')) { @@ -184,7 +184,7 @@ class ReconcileController extends Controller return $this->redirectToOriginalAccount($account); } if (AccountType::ASSET !== $account->accountType->type) { - Session::flash('error', trans('firefly.must_be_asset_account')); + session()->flash('error', trans('firefly.must_be_asset_account')); return redirect(route('accounts.index', [config('firefly.shortNamesByFullName.' . $account->accountType->type)])); } @@ -326,7 +326,7 @@ class ReconcileController extends Controller Preferences::mark(); - Session::flash('success', trans('firefly.reconciliation_stored')); + session()->flash('success', trans('firefly.reconciliation_stored')); return redirect(route('accounts.show', [$account->id])); } @@ -387,7 +387,7 @@ class ReconcileController extends Controller return redirect(route('transactions.show', [$journal->id])); } if (0 === bccomp('0', $request->get('amount'))) { - Session::flash('error', trans('firefly.amount_cannot_be_zero')); + session()->flash('error', trans('firefly.amount_cannot_be_zero')); return redirect(route('accounts.reconcile.edit', [$journal->id]))->withInput(); } diff --git a/app/Http/Controllers/Admin/ConfigurationController.php b/app/Http/Controllers/Admin/ConfigurationController.php index 64c47a5be5..f444af9ee5 100644 --- a/app/Http/Controllers/Admin/ConfigurationController.php +++ b/app/Http/Controllers/Admin/ConfigurationController.php @@ -91,7 +91,7 @@ class ConfigurationController extends Controller FireflyConfig::set('is_demo_site', $data['is_demo_site']); // flash message - Session::flash('success', (string)trans('firefly.configuration_updated')); + session()->flash('success', (string)trans('firefly.configuration_updated')); Preferences::mark(); return Redirect::route('admin.configuration.index'); diff --git a/app/Http/Controllers/Admin/HomeController.php b/app/Http/Controllers/Admin/HomeController.php index a13c54280b..ecd403b1f3 100644 --- a/app/Http/Controllers/Admin/HomeController.php +++ b/app/Http/Controllers/Admin/HomeController.php @@ -66,7 +66,7 @@ class HomeController extends Controller $ipAddress = $request->ip(); Log::debug(sprintf('Now in testMessage() controller. IP is %s', $ipAddress)); event(new AdminRequestedTestMessage(auth()->user(), $ipAddress)); - Session::flash('info', (string)trans('firefly.send_test_triggered')); + session()->flash('info', (string)trans('firefly.send_test_triggered')); return redirect(route('admin.index')); } diff --git a/app/Http/Controllers/Admin/UpdateController.php b/app/Http/Controllers/Admin/UpdateController.php index 44834b3597..28ae82489f 100644 --- a/app/Http/Controllers/Admin/UpdateController.php +++ b/app/Http/Controllers/Admin/UpdateController.php @@ -90,7 +90,7 @@ class UpdateController extends Controller $checkForUpdates = (int)$request->get('check_for_updates'); FireflyConfig::set('permission_update_check', $checkForUpdates); FireflyConfig::set('last_update_check', time()); - Session::flash('success', (string)trans('firefly.configuration_updated')); + session()->flash('success', (string)trans('firefly.configuration_updated')); return redirect(route('admin.update-check')); } diff --git a/app/Http/Controllers/Admin/UserController.php b/app/Http/Controllers/Admin/UserController.php index a7f2e4e102..52668c09ad 100644 --- a/app/Http/Controllers/Admin/UserController.php +++ b/app/Http/Controllers/Admin/UserController.php @@ -78,7 +78,7 @@ class UserController extends Controller public function destroy(User $user, UserRepositoryInterface $repository) { $repository->destroy($user); - Session::flash('success', (string)trans('firefly.user_deleted')); + session()->flash('success', (string)trans('firefly.user_deleted')); return redirect(route('admin.users')); } @@ -182,7 +182,7 @@ class UserController extends Controller $repository->changeStatus($user, $data['blocked'], $data['blocked_code']); $repository->updateEmail($user, $data['email']); - Session::flash('success', (string)trans('firefly.updated_user', ['email' => $user->email])); + session()->flash('success', (string)trans('firefly.updated_user', ['email' => $user->email])); Preferences::mark(); if (1 === (int)$request->get('return_to_edit')) { diff --git a/app/Http/Controllers/Auth/RegisterController.php b/app/Http/Controllers/Auth/RegisterController.php index 7e78ef8f2d..b67861652d 100644 --- a/app/Http/Controllers/Auth/RegisterController.php +++ b/app/Http/Controllers/Auth/RegisterController.php @@ -83,7 +83,7 @@ class RegisterController extends Controller $this->guard()->login($user); - Session::flash('success', (string)trans('firefly.registered')); + session()->flash('success', (string)trans('firefly.registered')); return $this->registered($request, $user) ?: redirect($this->redirectPath()); diff --git a/app/Http/Controllers/Controller.php b/app/Http/Controllers/Controller.php index e9135c4698..8cb0036c5d 100644 --- a/app/Http/Controllers/Controller.php +++ b/app/Http/Controllers/Controller.php @@ -163,7 +163,7 @@ class Controller extends BaseController } } // @codeCoverageIgnoreStart - Session::flash('error', (string)trans('firefly.cannot_redirect_to_account')); + session()->flash('error', (string)trans('firefly.cannot_redirect_to_account')); return redirect(route('index')); // @codeCoverageIgnoreEnd diff --git a/app/Http/Controllers/NewUserController.php b/app/Http/Controllers/NewUserController.php index 0e0e74445d..d8e7a85fe2 100644 --- a/app/Http/Controllers/NewUserController.php +++ b/app/Http/Controllers/NewUserController.php @@ -126,7 +126,7 @@ class NewUserController extends Controller ]; Preferences::set('transaction_journal_optional_fields', $visibleFields); - Session::flash('success', (string)trans('firefly.stored_new_accounts_new_user')); + session()->flash('success', (string)trans('firefly.stored_new_accounts_new_user')); Preferences::mark(); return redirect(route('index')); diff --git a/app/Http/Controllers/PiggyBankController.php b/app/Http/Controllers/PiggyBankController.php index 8b73c8fb14..2ada211d3a 100644 --- a/app/Http/Controllers/PiggyBankController.php +++ b/app/Http/Controllers/PiggyBankController.php @@ -164,7 +164,7 @@ class PiggyBankController extends Controller */ public function destroy(PiggyBank $piggyBank) { - Session::flash('success', (string)trans('firefly.deleted_piggy_bank', ['name' => $piggyBank->name])); + session()->flash('success', (string)trans('firefly.deleted_piggy_bank', ['name' => $piggyBank->name])); Preferences::mark(); $this->piggyRepos->destroy($piggyBank); @@ -198,7 +198,7 @@ class PiggyBankController extends Controller 'startdate' => $startDate, 'note' => null === $note ? '' : $note->text, ]; - Session::flash('preFilled', $preFilled); + session()->flash('preFilled', $preFilled); // put previous url in session if not redirect from store (not "return_to_edit"). if (true !== session('piggy-banks.edit.fromUpdate')) { @@ -299,7 +299,7 @@ class PiggyBankController extends Controller } if ($this->piggyRepos->canAddAmount($piggyBank, $amount)) { $this->piggyRepos->addAmount($piggyBank, $amount); - Session::flash( + session()->flash( 'success', (string)trans( 'firefly.added_amount_to_piggy', @@ -312,7 +312,7 @@ class PiggyBankController extends Controller } Log::error('Cannot add ' . $amount . ' because canAddAmount returned false.'); - Session::flash( + session()->flash( 'error', (string)trans( 'firefly.cannot_add_amount_piggy', @@ -339,7 +339,7 @@ class PiggyBankController extends Controller } if ($this->piggyRepos->canRemoveAmount($piggyBank, $amount)) { $this->piggyRepos->removeAmount($piggyBank, $amount); - Session::flash( + session()->flash( 'success', (string)trans( 'firefly.removed_amount_from_piggy', @@ -353,7 +353,7 @@ class PiggyBankController extends Controller $amount = (string)round($request->get('amount'), 12); - Session::flash( + session()->flash( 'error', (string)trans( 'firefly.cannot_remove_from_piggy', @@ -430,7 +430,7 @@ class PiggyBankController extends Controller } $piggyBank = $this->piggyRepos->store($data); - Session::flash('success', (string)trans('firefly.stored_piggy_bank', ['name' => $piggyBank->name])); + session()->flash('success', (string)trans('firefly.stored_piggy_bank', ['name' => $piggyBank->name])); Preferences::mark(); if (1 === (int)$request->get('create_another')) { @@ -455,7 +455,7 @@ class PiggyBankController extends Controller $data = $request->getPiggyBankData(); $piggyBank = $this->piggyRepos->update($piggyBank, $data); - Session::flash('success', (string)trans('firefly.updated_piggy_bank', ['name' => $piggyBank->name])); + session()->flash('success', (string)trans('firefly.updated_piggy_bank', ['name' => $piggyBank->name])); Preferences::mark(); if (1 === (int)$request->get('return_to_edit')) { diff --git a/app/Http/Controllers/PreferencesController.php b/app/Http/Controllers/PreferencesController.php index 6b3082ba38..6e66ed4ab9 100644 --- a/app/Http/Controllers/PreferencesController.php +++ b/app/Http/Controllers/PreferencesController.php @@ -143,7 +143,7 @@ class PreferencesController extends Controller ]; Preferences::set('transaction_journal_optional_fields', $optionalTj); - Session::flash('success', (string)trans('firefly.saved_preferences')); + session()->flash('success', (string)trans('firefly.saved_preferences')); Preferences::mark(); return redirect(route('preferences.index')); diff --git a/app/Http/Controllers/ProfileController.php b/app/Http/Controllers/ProfileController.php index 1270707146..51d0a377e1 100644 --- a/app/Http/Controllers/ProfileController.php +++ b/app/Http/Controllers/ProfileController.php @@ -107,7 +107,7 @@ class ProfileController extends Controller { $domain = $this->getDomain(); $secret = Google2FA::generateSecretKey(); - Session::flash('two-factor-secret', $secret); + session()->flash('two-factor-secret', $secret); $image = Google2FA::getQRCodeInline($domain, auth()->user()->email, $secret, 200); return view('profile.code', compact('image')); @@ -143,7 +143,7 @@ class ProfileController extends Controller $repository->unblockUser($user); // return to login. - Session::flash('success', (string)trans('firefly.login_with_new_email')); + session()->flash('success', (string)trans('firefly.login_with_new_email')); return redirect(route('login')); } @@ -167,8 +167,8 @@ class ProfileController extends Controller { Preferences::delete('twoFactorAuthEnabled'); Preferences::delete('twoFactorAuthSecret'); - Session::flash('success', (string)trans('firefly.pref_two_factor_auth_disabled')); - Session::flash('info', (string)trans('firefly.pref_two_factor_auth_remove_it')); + session()->flash('success', (string)trans('firefly.pref_two_factor_auth_disabled')); + session()->flash('info', (string)trans('firefly.pref_two_factor_auth_remove_it')); return redirect(route('profile.index')); } @@ -242,7 +242,7 @@ class ProfileController extends Controller $newEmail = $request->string('email'); $oldEmail = $user->email; if ($newEmail === $user->email) { - Session::flash('error', (string)trans('firefly.email_not_changed')); + session()->flash('error', (string)trans('firefly.email_not_changed')); return redirect(route('profile.change-email'))->withInput(); } @@ -252,7 +252,7 @@ class ProfileController extends Controller Auth::guard()->logout(); $request->session()->invalidate(); - Session::flash('success', (string)trans('firefly.email_changed')); + session()->flash('success', (string)trans('firefly.email_changed')); return redirect(route('index')); } @@ -267,7 +267,7 @@ class ProfileController extends Controller // force user logout. Auth::guard()->logout(); $request->session()->invalidate(); - Session::flash('success', (string)trans('firefly.email_changed')); + session()->flash('success', (string)trans('firefly.email_changed')); return redirect(route('index')); } @@ -287,13 +287,13 @@ class ProfileController extends Controller try { $this->validatePassword(auth()->user(), $current, $new); } catch (ValidationException $e) { - Session::flash('error', $e->getMessage()); + session()->flash('error', $e->getMessage()); return redirect(route('profile.change-password')); } $repository->changePassword(auth()->user(), $request->get('new_password')); - Session::flash('success', (string)trans('firefly.password_changed')); + session()->flash('success', (string)trans('firefly.password_changed')); return redirect(route('profile.index')); } @@ -309,7 +309,7 @@ class ProfileController extends Controller Preferences::set('twoFactorAuthEnabled', 1); Preferences::set('twoFactorAuthSecret', Session::get('two-factor-secret')); - Session::flash('success', (string)trans('firefly.saved_preferences')); + session()->flash('success', (string)trans('firefly.saved_preferences')); Preferences::mark(); return redirect(route('profile.index')); @@ -324,7 +324,7 @@ class ProfileController extends Controller public function postDeleteAccount(UserRepositoryInterface $repository, DeleteAccountFormRequest $request) { if (!Hash::check($request->get('password'), auth()->user()->password)) { - Session::flash('error', (string)trans('firefly.invalid_password')); + session()->flash('error', (string)trans('firefly.invalid_password')); return redirect(route('profile.delete-account')); } @@ -345,7 +345,7 @@ class ProfileController extends Controller { $token = auth()->user()->generateAccessToken(); Preferences::set('access_token', $token); - Session::flash('success', (string)trans('firefly.token_regenerated')); + session()->flash('success', (string)trans('firefly.token_regenerated')); return redirect(route('profile.index')); } @@ -395,7 +395,7 @@ class ProfileController extends Controller $repository->unblockUser($user); // return to login. - Session::flash('success', (string)trans('firefly.login_with_old_email')); + session()->flash('success', (string)trans('firefly.login_with_old_email')); return redirect(route('login')); } diff --git a/app/Http/Controllers/ReportController.php b/app/Http/Controllers/ReportController.php index 9681f9440f..7d4b3ea82f 100644 --- a/app/Http/Controllers/ReportController.php +++ b/app/Http/Controllers/ReportController.php @@ -325,25 +325,25 @@ class ReportController extends Controller if (0 === $request->getAccountList()->count()) { Log::debug('Account count is zero'); - Session::flash('error', trans('firefly.select_more_than_one_account')); + session()->flash('error', trans('firefly.select_more_than_one_account')); return redirect(route('reports.index')); } if (0 === $request->getCategoryList()->count() && 'category' === $reportType) { - Session::flash('error', trans('firefly.select_more_than_one_category')); + session()->flash('error', trans('firefly.select_more_than_one_category')); return redirect(route('reports.index')); } if (0 === $request->getBudgetList()->count() && 'budget' === $reportType) { - Session::flash('error', trans('firefly.select_more_than_one_budget')); + session()->flash('error', trans('firefly.select_more_than_one_budget')); return redirect(route('reports.index')); } if (0 === $request->getTagList()->count() && 'tag' === $reportType) { - Session::flash('error', trans('firefly.select_more_than_one_tag')); + session()->flash('error', trans('firefly.select_more_than_one_tag')); return redirect(route('reports.index')); } diff --git a/app/Http/Controllers/RuleController.php b/app/Http/Controllers/RuleController.php index b6d08b6886..dce7622951 100644 --- a/app/Http/Controllers/RuleController.php +++ b/app/Http/Controllers/RuleController.php @@ -24,6 +24,7 @@ namespace FireflyIII\Http\Controllers; use Carbon\Carbon; use ExpandedForm; +use FireflyIII\Exceptions\FireflyException; use FireflyIII\Http\Requests\RuleFormRequest; use FireflyIII\Http\Requests\SelectTransactionsRequest; use FireflyIII\Http\Requests\TestRuleFormRequest; @@ -39,7 +40,9 @@ use FireflyIII\Repositories\Bill\BillRepositoryInterface; use FireflyIII\Repositories\Rule\RuleRepositoryInterface; use FireflyIII\Repositories\RuleGroup\RuleGroupRepositoryInterface; use FireflyIII\TransactionRules\TransactionMatcher; +use Illuminate\Http\JsonResponse; use Illuminate\Http\Request; +use Illuminate\Support\Collection; use Log; use Preferences; use Session; @@ -51,6 +54,15 @@ use View; */ class RuleController extends Controller { + /** @var AccountRepositoryInterface */ + private $accountRepos; + /** @var BillRepositoryInterface */ + private $billRepos; + /** @var RuleGroupRepositoryInterface */ + private $ruleGroupRepos; + /** @var RuleRepositoryInterface */ + private $ruleRepos; + /** * RuleController constructor. */ @@ -63,6 +75,11 @@ class RuleController extends Controller app('view')->share('title', trans('firefly.rules')); app('view')->share('mainTitleIcon', 'fa-random'); + $this->accountRepos = app(AccountRepositoryInterface::class); + $this->billRepos = app(BillRepositoryInterface::class); + $this->ruleGroupRepos = app(RuleGroupRepositoryInterface::class); + $this->ruleRepos = app(RuleRepositoryInterface::class); + return $next($request); } ); @@ -77,7 +94,7 @@ class RuleController extends Controller * @return View * */ - public function create(Request $request, RuleGroupRepositoryInterface $ruleGroupRepository, BillRepositoryInterface $billRepository, RuleGroup $ruleGroup) + public function create(Request $request, RuleGroup $ruleGroup) { $this->createDefaultRuleGroup(); $this->createDefaultRule(); @@ -86,7 +103,7 @@ class RuleController extends Controller $preFilled = [ 'strict' => true, ]; - $groups = ExpandedForm::makeSelectList($ruleGroupRepository->get()); + $groups = ExpandedForm::makeSelectList($this->ruleGroupRepos->get()); $oldTriggers = []; $oldActions = []; $returnToBill = false; @@ -97,7 +114,7 @@ class RuleController extends Controller // has bill? if ($billId > 0) { - $bill = $billRepository->find($billId); + $bill = $this->billRepos->find($billId); } // has old input? @@ -160,74 +177,65 @@ class RuleController extends Controller /** * Actually destroy the given rule. * - * @param Rule $rule - * @param RuleRepositoryInterface $repository + * @param Rule $rule * * @return \Illuminate\Http\RedirectResponse */ - public function destroy(RuleRepositoryInterface $repository, Rule $rule) + public function destroy(Rule $rule) { $title = $rule->title; - $repository->destroy($rule); + $this->ruleRepos->destroy($rule); - Session::flash('success', trans('firefly.deleted_rule', ['title' => $title])); + session()->flash('success', trans('firefly.deleted_rule', ['title' => $title])); Preferences::mark(); return redirect($this->getPreviousUri('rules.delete.uri')); } /** - * @param RuleRepositoryInterface $repository - * @param Rule $rule + * @param Rule $rule * * @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector */ - public function down(RuleRepositoryInterface $repository, Rule $rule) + public function down(Rule $rule) { - $repository->moveDown($rule); + $this->ruleRepos->moveDown($rule); return redirect(route('rules.index')); } /** - * @param Request $request - * @param RuleRepositoryInterface $repository - * @param Rule $rule + * @param Request $request + * @param Rule $rule * * @return View * - - - - */ - public function edit(Request $request, RuleRepositoryInterface $repository, Rule $rule) + public function edit(Request $request, Rule $rule) { - /** @var RuleGroupRepositoryInterface $ruleGroupRepository */ - $ruleGroupRepository = app(RuleGroupRepositoryInterface::class); - $ruleGroups = ExpandedForm::makeSelectList($ruleGroupRepository->get()); - $triggerCount = 0; - $actionCount = 0; - $oldActions = []; - $oldTriggers = []; + $ruleGroups = ExpandedForm::makeSelectList($this->ruleGroupRepos->get()); + $triggerCount = 0; + $actionCount = 0; + $oldActions = []; + $oldTriggers = []; // has old input? - if (count($request->old()) > 0) { + if (\count($request->old()) > 0) { $oldTriggers = $this->getPreviousTriggers($request); - $triggerCount = count($oldTriggers); + $triggerCount = \count($oldTriggers); $oldActions = $this->getPreviousActions($request); - $actionCount = count($oldActions); + $actionCount = \count($oldActions); } // overrule old input when it as no rule data: if (0 === $triggerCount && 0 === $actionCount) { $oldTriggers = $this->getCurrentTriggers($rule); - $triggerCount = count($oldTriggers); + $triggerCount = \count($oldTriggers); $oldActions = $this->getCurrentActions($rule); - $actionCount = count($oldActions); + $actionCount = \count($oldActions); } // get rule trigger for update / store-journal: - $primaryTrigger = $repository->getPrimaryTrigger($rule); + $primaryTrigger = $this->ruleRepos->getPrimaryTrigger($rule); $subTitle = trans('firefly.edit_rule', ['title' => $rule->title]); // put previous url in session if not redirect from store (not "return_to_edit"). @@ -236,36 +244,23 @@ class RuleController extends Controller } Session::forget('rules.edit.fromUpdate'); - return view( - 'rules.rule.edit', - compact( - 'rule', - 'subTitle', - 'primaryTrigger', - 'oldTriggers', - 'oldActions', - 'triggerCount', - 'actionCount', - 'ruleGroups' - ) - ); + return view('rules.rule.edit', compact('rule', 'subTitle', 'primaryTrigger', 'oldTriggers', 'oldActions', 'triggerCount', 'actionCount', 'ruleGroups')); } /** * Execute the given rule on a set of existing transactions. * - * @param SelectTransactionsRequest $request - * @param AccountRepositoryInterface $repository - * @param Rule $rule + * @param SelectTransactionsRequest $request + * @param Rule $rule * * @return \Illuminate\Http\RedirectResponse * * @internal param RuleGroup $ruleGroup */ - public function execute(SelectTransactionsRequest $request, AccountRepositoryInterface $repository, Rule $rule) + public function execute(SelectTransactionsRequest $request, Rule $rule) { // Get parameters specified by the user - $accounts = $repository->getAccountsById($request->get('accounts')); + $accounts = $this->accountRepos->getAccountsById($request->get('accounts')); $startDate = new Carbon($request->get('start_date')); $endDate = new Carbon($request->get('end_date')); @@ -282,37 +277,34 @@ class RuleController extends Controller $this->dispatch($job); // Tell the user that the job is queued - Session::flash('success', (string)trans('firefly.applied_rule_selection', ['title' => $rule->title])); + session()->flash('success', (string)trans('firefly.applied_rule_selection', ['title' => $rule->title])); return redirect()->route('rules.index'); } /** - * @param RuleGroupRepositoryInterface $repository - * * @return View */ - public function index(RuleGroupRepositoryInterface $repository) + public function index() { $this->createDefaultRuleGroup(); $this->createDefaultRule(); - $ruleGroups = $repository->getRuleGroupsWithRules(auth()->user()); + $ruleGroups = $this->ruleGroupRepos->getRuleGroupsWithRules(auth()->user()); return view('rules.index', compact('ruleGroups')); } /** - * @param Request $request - * @param RuleRepositoryInterface $repository - * @param Rule $rule + * @param Request $request + * @param Rule $rule * - * @return \Illuminate\Http\JsonResponse + * @return JsonResponse */ - public function reorderRuleActions(Request $request, RuleRepositoryInterface $repository, Rule $rule) + public function reorderRuleActions(Request $request, Rule $rule): JsonResponse { $ids = $request->get('actions'); - if (is_array($ids)) { - $repository->reorderRuleActions($rule, $ids); + if (\is_array($ids)) { + $this->ruleGroupRepos->reorderRuleActions($rule, $ids); } return response()->json('true'); @@ -323,28 +315,27 @@ class RuleController extends Controller * @param RuleRepositoryInterface $repository * @param Rule $rule * - * @return \Illuminate\Http\JsonResponse + * @return JsonResponse */ - public function reorderRuleTriggers(Request $request, RuleRepositoryInterface $repository, Rule $rule) + public function reorderRuleTriggers(Request $request, Rule $rule): JsonResponse { $ids = $request->get('triggers'); - if (is_array($ids)) { - $repository->reorderRuleTriggers($rule, $ids); + if (\is_array($ids)) { + $this->ruleGroupRepos->reorderRuleTriggers($rule, $ids); } return response()->json('true'); } /** - * @param AccountRepositoryInterface $repository - * @param Rule $rule + * @param Rule $rule * * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View */ - public function selectTransactions(AccountRepositoryInterface $repository, Rule $rule) + public function selectTransactions(Rule $rule) { // does the user have shared accounts? - $accounts = $repository->getAccountsByType([AccountType::ASSET]); + $accounts = $this->accountRepos->getAccountsByType([AccountType::ASSET]); $accountList = ExpandedForm::makeSelectList($accounts); $checkedAccounts = array_keys($accountList); $first = session('first')->format('Y-m-d'); @@ -355,15 +346,14 @@ class RuleController extends Controller } /** - * @param RuleFormRequest $request - * @param RuleRepositoryInterface $repository + * @param RuleFormRequest $request * * @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector */ - public function store(RuleFormRequest $request, RuleRepositoryInterface $repository) + public function store(RuleFormRequest $request) { $data = $request->getRuleData(); - $rule = $repository->store($data); + $rule = $this->ruleRepos->store($data); session()->flash('success', trans('firefly.stored_new_rule', ['title' => $rule->title])); Preferences::mark(); @@ -399,39 +389,50 @@ class RuleController extends Controller * * @param TestRuleFormRequest $request * - * @return \Illuminate\Http\JsonResponse - * + * @return JsonResponse */ - public function testTriggers(TestRuleFormRequest $request) + public function testTriggers(TestRuleFormRequest $request): JsonResponse { // build trigger array from response $triggers = $this->getValidTriggerList($request); - if (0 === count($triggers)) { + if (0 === \count($triggers)) { return response()->json(['html' => '', 'warning' => trans('firefly.warning_no_valid_triggers')]); // @codeCoverageIgnore } - $limit = (int)config('firefly.test-triggers.limit'); - $range = (int)config('firefly.test-triggers.range'); - + $limit = (int)config('firefly.test-triggers.limit'); + $range = (int)config('firefly.test-triggers.range'); + $matchingTransactions = new Collection; /** @var TransactionMatcher $matcher */ $matcher = app(TransactionMatcher::class); $matcher->setLimit($limit); $matcher->setRange($range); $matcher->setTriggers($triggers); - $matchingTransactions = $matcher->findTransactionsByTriggers(); + try { + $matchingTransactions = $matcher->findTransactionsByTriggers(); + } catch (FireflyException $exception) { + Log::error(sprintf('Could not grab transactions in testTriggers(): %s', $exception->getMessage())); + Log::error($exception->getTraceAsString()); + } + // Warn the user if only a subset of transactions is returned $warning = ''; - if (count($matchingTransactions) === $limit) { + if ($matchingTransactions->count() === $limit) { $warning = trans('firefly.warning_transaction_subset', ['max_num_transactions' => $limit]); // @codeCoverageIgnore } - if (0 === count($matchingTransactions)) { + if (0 === $matchingTransactions->count()) { $warning = trans('firefly.warning_no_matching_transactions', ['num_transactions' => $range]); // @codeCoverageIgnore } // Return json response - $view = view('list.journals-tiny', ['transactions' => $matchingTransactions])->render(); + $view = 'ERROR, see logs.'; + try { + $view = view('list.journals-tiny', ['transactions' => $matchingTransactions])->render(); + } catch (Throwable $exception) { + Log::error(sprintf('Could not render view in testTriggers(): %s', $exception->getMessage())); + Log::error($exception->getTraceAsString()); + } return response()->json(['html' => $view, 'warning' => $warning]); } @@ -444,14 +445,11 @@ class RuleController extends Controller * to find transaction journals matching the users input. A maximum range of transactions to try (range) and * a maximum number of transactions to return (limit) are set as well. * - * * @param Rule $rule * - * @return \Illuminate\Http\JsonResponse - * @throws Throwable - * @throws \FireflyIII\Exceptions\FireflyException + * @return JsonResponse */ - public function testTriggersByRule(Rule $rule) + public function testTriggersByRule(Rule $rule): JsonResponse { $triggers = $rule->ruleTriggers; @@ -459,57 +457,67 @@ class RuleController extends Controller return response()->json(['html' => '', 'warning' => trans('firefly.warning_no_valid_triggers')]); // @codeCoverageIgnore } - $limit = (int)config('firefly.test-triggers.limit'); - $range = (int)config('firefly.test-triggers.range'); + $limit = (int)config('firefly.test-triggers.limit'); + $range = (int)config('firefly.test-triggers.range'); + $matchingTransactions = new Collection; /** @var TransactionMatcher $matcher */ $matcher = app(TransactionMatcher::class); $matcher->setLimit($limit); $matcher->setRange($range); $matcher->setRule($rule); - $matchingTransactions = $matcher->findTransactionsByRule(); + try { + $matchingTransactions = $matcher->findTransactionsByRule(); + } catch (FireflyException $exception) { + Log::error(sprintf('Could not grab transactions in testTriggersByRule(): %s', $exception->getMessage())); + Log::error($exception->getTraceAsString()); + } // Warn the user if only a subset of transactions is returned $warning = ''; - if (\count($matchingTransactions) === $limit) { + if ($matchingTransactions->count() === $limit) { $warning = trans('firefly.warning_transaction_subset', ['max_num_transactions' => $limit]); // @codeCoverageIgnore } - if (0 === \count($matchingTransactions)) { + if (0 === $matchingTransactions->count()) { $warning = trans('firefly.warning_no_matching_transactions', ['num_transactions' => $range]); // @codeCoverageIgnore } // Return json response - $view = view('list.journals-tiny', ['transactions' => $matchingTransactions])->render(); + $view = 'ERROR, see logs.'; + try { + $view = view('list.journals-tiny', ['transactions' => $matchingTransactions])->render(); + } catch (Throwable $exception) { + Log::error(sprintf('Could not render view in testTriggersByRule(): %s', $exception->getMessage())); + Log::error($exception->getTraceAsString()); + } return response()->json(['html' => $view, 'warning' => $warning]); } /** - * @param RuleRepositoryInterface $repository - * @param Rule $rule + * @param Rule $rule * * @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector */ - public function up(RuleRepositoryInterface $repository, Rule $rule) + public function up(Rule $rule) { - $repository->moveUp($rule); + $this->ruleRepos->moveUp($rule); return redirect(route('rules.index')); } /** - * @param RuleRepositoryInterface $repository - * @param RuleFormRequest $request - * @param Rule $rule + * @param RuleFormRequest $request + * @param Rule $rule * * @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector */ - public function update(RuleRepositoryInterface $repository, RuleFormRequest $request, Rule $rule) + public function update(RuleFormRequest $request, Rule $rule) { $data = $request->getRuleData(); - $repository->update($rule, $data); + $this->ruleRepos->update($rule, $data); - Session::flash('success', trans('firefly.updated_rule', ['title' => $rule->title])); + session()->flash('success', trans('firefly.updated_rule', ['title' => $rule->title])); Preferences::mark(); if (1 === (int)$request->get('return_to_edit')) { @@ -523,14 +531,14 @@ class RuleController extends Controller return redirect($this->getPreviousUri('rules.edit.uri')); } - private function createDefaultRule() + /** + * + */ + private function createDefaultRule(): void { - /** @var RuleRepositoryInterface $repository */ - $repository = app(RuleRepositoryInterface::class); - - if (0 === $repository->count()) { + if (0 === $this->ruleRepos->count()) { $data = [ - 'rule_group_id' => $repository->getFirstRuleGroup()->id, + 'rule_group_id' => $this->ruleRepos->getFirstRuleGroup()->id, 'stop_processing' => 0, 'title' => trans('firefly.default_rule_name'), 'description' => trans('firefly.default_rule_description'), @@ -548,25 +556,22 @@ class RuleController extends Controller 'rule-actions' => ['prepend_description', 'set_category'], ]; - $repository->store($data); + $this->ruleRepos->store($data); } } /** * */ - private function createDefaultRuleGroup() + private function createDefaultRuleGroup(): void { - /** @var RuleGroupRepositoryInterface $repository */ - $repository = app(RuleGroupRepositoryInterface::class); - - if (0 === $repository->count()) { + if (0 === $this->ruleGroupRepos->count()) { $data = [ 'title' => trans('firefly.default_rule_group_name'), 'description' => trans('firefly.default_rule_group_description'), ]; - $repository->store($data); + $this->ruleGroupRepos->store($data); } } @@ -589,7 +594,8 @@ class RuleController extends Controller ] )->render(); } catch (Throwable $e) { - Log::debug(sprintf('Throwable was thrown in getActionsForBill(): %s', $e->getMessage())); + Log::error(sprintf('Throwable was thrown in getActionsForBill(): %s', $e->getMessage())); + Log::error($e->getTraceAsString()); } return $actions; @@ -602,7 +608,7 @@ class RuleController extends Controller * */ - private function getCurrentActions(Rule $rule) + private function getCurrentActions(Rule $rule): array { $index = 0; $actions = []; @@ -622,6 +628,7 @@ class RuleController extends Controller )->render(); } catch (Throwable $e) { Log::debug(sprintf('Throwable was thrown in getCurrentActions(): %s', $e->getMessage())); + Log::error($e->getTraceAsString()); } ++$index; } @@ -634,9 +641,8 @@ class RuleController extends Controller * * @return array * - */ - private function getCurrentTriggers(Rule $rule) + private function getCurrentTriggers(Rule $rule): array { $index = 0; $triggers = []; @@ -657,6 +663,7 @@ class RuleController extends Controller )->render(); } catch (Throwable $e) { Log::debug(sprintf('Throwable was thrown in getCurrentTriggers(): %s', $e->getMessage())); + Log::error($e->getTraceAsString()); } ++$index; } @@ -670,9 +677,8 @@ class RuleController extends Controller * * @return array * - */ - private function getPreviousActions(Request $request) + private function getPreviousActions(Request $request): array { $newIndex = 0; $actions = []; @@ -693,6 +699,7 @@ class RuleController extends Controller )->render(); } catch (Throwable $e) { Log::debug(sprintf('Throwable was thrown in getPreviousActions(): %s', $e->getMessage())); + Log::error($e->getTraceAsString()); } ++$newIndex; } @@ -707,7 +714,7 @@ class RuleController extends Controller * */ - private function getPreviousTriggers(Request $request) + private function getPreviousTriggers(Request $request): array { $newIndex = 0; $triggers = []; @@ -728,6 +735,7 @@ class RuleController extends Controller )->render(); } catch (Throwable $e) { Log::debug(sprintf('Throwable was thrown in getPreviousTriggers(): %s', $e->getMessage())); + Log::error($e->getTraceAsString()); } ++$newIndex; } diff --git a/app/Http/Controllers/RuleGroupController.php b/app/Http/Controllers/RuleGroupController.php index adf37c3746..2d139e9361 100644 --- a/app/Http/Controllers/RuleGroupController.php +++ b/app/Http/Controllers/RuleGroupController.php @@ -108,7 +108,7 @@ class RuleGroupController extends Controller $repository->destroy($ruleGroup, $moveTo); - Session::flash('success', (string)trans('firefly.deleted_rule_group', ['title' => $title])); + session()->flash('success', (string)trans('firefly.deleted_rule_group', ['title' => $title])); Preferences::mark(); return redirect($this->getPreviousUri('rule-groups.delete.uri')); @@ -174,7 +174,7 @@ class RuleGroupController extends Controller $this->dispatch($job); // Tell the user that the job is queued - Session::flash('success', (string)trans('firefly.applied_rule_group_selection', ['title' => $ruleGroup->title])); + session()->flash('success', (string)trans('firefly.applied_rule_group_selection', ['title' => $ruleGroup->title])); return redirect()->route('rules.index'); } @@ -209,7 +209,7 @@ class RuleGroupController extends Controller $data = $request->getRuleGroupData(); $ruleGroup = $repository->store($data); - Session::flash('success', (string)trans('firefly.created_new_rule_group', ['title' => $ruleGroup->title])); + session()->flash('success', (string)trans('firefly.created_new_rule_group', ['title' => $ruleGroup->title])); Preferences::mark(); if (1 === (int)$request->get('create_another')) { @@ -253,7 +253,7 @@ class RuleGroupController extends Controller $repository->update($ruleGroup, $data); - Session::flash('success', (string)trans('firefly.updated_rule_group', ['title' => $ruleGroup->title])); + session()->flash('success', (string)trans('firefly.updated_rule_group', ['title' => $ruleGroup->title])); Preferences::mark(); if (1 === (int)$request->get('return_to_edit')) { diff --git a/app/Http/Controllers/TagController.php b/app/Http/Controllers/TagController.php index 53652a00cc..ffc0e7a838 100644 --- a/app/Http/Controllers/TagController.php +++ b/app/Http/Controllers/TagController.php @@ -118,7 +118,7 @@ class TagController extends Controller $tagName = $tag->tag; $this->repository->destroy($tag); - Session::flash('success', (string)trans('firefly.deleted_tag', ['tag' => $tagName])); + session()->flash('success', (string)trans('firefly.deleted_tag', ['tag' => $tagName])); Preferences::mark(); return redirect($this->getPreviousUri('tags.delete.uri')); @@ -261,7 +261,7 @@ class TagController extends Controller $data = $request->collectTagData(); $this->repository->store($data); - Session::flash('success', (string)trans('firefly.created_tag', ['tag' => $data['tag']])); + session()->flash('success', (string)trans('firefly.created_tag', ['tag' => $data['tag']])); Preferences::mark(); if (1 === (int)$request->get('create_another')) { @@ -286,7 +286,7 @@ class TagController extends Controller $data = $request->collectTagData(); $this->repository->update($tag, $data); - Session::flash('success', (string)trans('firefly.updated_tag', ['tag' => $data['tag']])); + session()->flash('success', (string)trans('firefly.updated_tag', ['tag' => $data['tag']])); Preferences::mark(); if (1 === (int)$request->get('return_to_edit')) { diff --git a/app/Http/Controllers/Transaction/BulkController.php b/app/Http/Controllers/Transaction/BulkController.php index d4ed300ea6..ab1dd5f0f7 100644 --- a/app/Http/Controllers/Transaction/BulkController.php +++ b/app/Http/Controllers/Transaction/BulkController.php @@ -28,7 +28,6 @@ use ExpandedForm; use FireflyIII\Http\Controllers\Controller; use FireflyIII\Http\Requests\BulkEditJournalRequest; use FireflyIII\Models\TransactionJournal; -use FireflyIII\Models\TransactionType; use FireflyIII\Repositories\Budget\BudgetRepositoryInterface; use FireflyIII\Repositories\Journal\JournalRepositoryInterface; use FireflyIII\Services\Internal\Update\JournalUpdateService; @@ -66,70 +65,25 @@ class BulkController extends Controller } /** - * @param Request $request * @param Collection $journals * * @return View */ - public function edit(Request $request, Collection $journals) + public function edit(Collection $journals) { - $subTitle = trans('firefly.mass_bulk_journals'); - // skip transactions that have multiple destinations, multiple sources or are an opening balance. - $filtered = new Collection; - $messages = []; - /** @var TransactionJournal $journal */ - foreach ($journals as $journal) { - $sources = $this->repository->getJournalSourceAccounts($journal); - $destinations = $this->repository->getJournalDestinationAccounts($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; - } - if (TransactionType::OPENING_BALANCE === $this->repository->getTransactionType($journal)) { - $messages[] = trans('firefly.cannot_edit_opening_balance'); - continue; - } - - // cannot edit reconciled transactions / journals: - if ($this->repository->isJournalReconciled($journal)) { - $messages[] = trans('firefly.cannot_edit_reconciled', ['description' => $journal->description, 'id' => $journal->id]); - continue; - } - - $filtered->push($journal); - } - - if (count($messages) > 0) { - $request->session()->flash('info', $messages); - } - - // put previous url in session - $this->rememberPreviousUri('transactions.bulk-edit.uri'); - // get list of budgets: /** @var BudgetRepositoryInterface $repository */ $repository = app(BudgetRepositoryInterface::class); $budgetList = ExpandedForm::makeSelectListWithEmpty($repository->getActiveBudgets()); // collect some useful meta data for the mass edit: - $filtered->each( + $journals->each( function (TransactionJournal $journal) { $journal->transaction_count = $journal->transactions()->count(); } ); - if (0 === $filtered->count()) { - $request->session()->flash('error', trans('firefly.no_edit_multiple_left')); - } - - $journals = $filtered; - return view('transactions.bulk.edit', compact('journals', 'subTitle', 'budgetList')); } @@ -142,36 +96,32 @@ class BulkController extends Controller */ public function update(BulkEditJournalRequest $request, JournalRepositoryInterface $repository) { - /** @var JournalUpdateService $service */ - $service = app(JournalUpdateService::class); $journalIds = $request->get('journals'); $ignoreCategory = (int)$request->get('ignore_category') === 1; $ignoreBudget = (int)$request->get('ignore_budget') === 1; $ignoreTags = (int)$request->get('ignore_tags') === 1; $count = 0; - if (is_array($journalIds)) { + if (\is_array($journalIds)) { foreach ($journalIds as $journalId) { $journal = $repository->find((int)$journalId); - if (null !== $journal) { - $count++; - Log::debug(sprintf('Found journal #%d', $journal->id)); - // update category if not told to ignore - if ($ignoreCategory === false) { - Log::debug(sprintf('Set category to %s', $request->string('category'))); + $count++; + Log::debug(sprintf('Found journal #%d', $journal->id)); - $repository->updateCategory($journal, $request->string('category')); - } - // update budget if not told to ignore (and is withdrawal) - if ($ignoreBudget === false) { - Log::debug(sprintf('Set budget to %d', $request->integer('budget_id'))); - $repository->updateBudget($journal, $request->integer('budget_id')); - } - if ($ignoreTags === false) { - Log::debug(sprintf('Set tags to %s', $request->string('budget_id'))); - $repository->updateTags($journal, ['tags' => explode(',', $request->string('tags'))]); - } - // update tags if not told to ignore (and is withdrawal) + // update category if not told to ignore + if ($ignoreCategory === false) { + Log::debug(sprintf('Set category to %s', $request->string('category'))); + + $repository->updateCategory($journal, $request->string('category')); + } + // update budget if not told to ignore (and is withdrawal) + if ($ignoreBudget === false) { + Log::debug(sprintf('Set budget to %d', $request->integer('budget_id'))); + $repository->updateBudget($journal, $request->integer('budget_id')); + } + if ($ignoreTags === false) { + Log::debug(sprintf('Set tags to %s', $request->string('budget_id'))); + $repository->updateTags($journal, ['tags' => explode(',', $request->string('tags'))]); } } } diff --git a/app/Http/Controllers/Transaction/ConvertController.php b/app/Http/Controllers/Transaction/ConvertController.php index 2d4cb53068..64962a9e67 100644 --- a/app/Http/Controllers/Transaction/ConvertController.php +++ b/app/Http/Controllers/Transaction/ConvertController.php @@ -81,14 +81,14 @@ class ConvertController extends Controller // cannot convert to its own type. if ($sourceType->type === $destinationType->type) { - Session::flash('info', trans('firefly.convert_is_already_type_' . $destinationType->type)); + session()->flash('info', trans('firefly.convert_is_already_type_' . $destinationType->type)); return redirect(route('transactions.show', [$journal->id])); } // cannot convert split. if ($journal->transactions()->count() > 2) { - Session::flash('error', trans('firefly.cannot_convert_split_journal')); + session()->flash('error', trans('firefly.cannot_convert_split_journal')); return redirect(route('transactions.show', [$journal->id])); } @@ -138,13 +138,13 @@ class ConvertController extends Controller $data = $request->all(); if ($journal->transactionType->type === $destinationType->type) { - Session::flash('error', trans('firefly.convert_is_already_type_' . $destinationType->type)); + session()->flash('error', trans('firefly.convert_is_already_type_' . $destinationType->type)); return redirect(route('transactions.show', [$journal->id])); } if ($journal->transactions()->count() > 2) { - Session::flash('error', trans('firefly.cannot_convert_split_journal')); + session()->flash('error', trans('firefly.cannot_convert_split_journal')); return redirect(route('transactions.show', [$journal->id])); } @@ -160,7 +160,7 @@ class ConvertController extends Controller return redirect(route('transactions.convert.index', [strtolower($destinationType->type), $journal->id]))->withErrors($errors)->withInput(); } - Session::flash('success', trans('firefly.converted_to_' . $destinationType->type)); + session()->flash('success', trans('firefly.converted_to_' . $destinationType->type)); return redirect(route('transactions.show', [$journal->id])); } diff --git a/app/Http/Controllers/Transaction/LinkController.php b/app/Http/Controllers/Transaction/LinkController.php index 0c7f0b02b2..e12f51afd5 100644 --- a/app/Http/Controllers/Transaction/LinkController.php +++ b/app/Http/Controllers/Transaction/LinkController.php @@ -86,7 +86,7 @@ class LinkController extends Controller { $this->repository->destroyLink($link); - Session::flash('success', (string)trans('firefly.deleted_link')); + session()->flash('success', (string)trans('firefly.deleted_link')); Preferences::mark(); return redirect((string)session('journal_links.delete.uri')); @@ -104,7 +104,7 @@ class LinkController extends Controller Log::debug('We are here (store)'); $linkInfo = $request->getLinkInfo(); if (0 === $linkInfo['transaction_journal_id']) { - Session::flash('error', trans('firefly.invalid_link_selection')); + session()->flash('error', trans('firefly.invalid_link_selection')); return redirect(route('transactions.show', [$journal->id])); } @@ -112,19 +112,19 @@ class LinkController extends Controller $alreadyLinked = $this->repository->findLink($journal, $other); if ($other->id === $journal->id) { - Session::flash('error', trans('firefly.journals_link_to_self')); + session()->flash('error', trans('firefly.journals_link_to_self')); return redirect(route('transactions.show', [$journal->id])); } if ($alreadyLinked) { - Session::flash('error', trans('firefly.journals_error_linked')); + session()->flash('error', trans('firefly.journals_error_linked')); return redirect(route('transactions.show', [$journal->id])); } Log::debug(sprintf('Journal is %d, opposing is %d', $journal->id, $other->id)); $this->repository->storeLink($linkInfo, $other, $journal); - Session::flash('success', trans('firefly.journals_linked')); + session()->flash('success', trans('firefly.journals_linked')); return redirect(route('transactions.show', [$journal->id])); } diff --git a/app/Http/Controllers/Transaction/MassController.php b/app/Http/Controllers/Transaction/MassController.php index bfd29a23e2..d9aca02868 100644 --- a/app/Http/Controllers/Transaction/MassController.php +++ b/app/Http/Controllers/Transaction/MassController.php @@ -108,7 +108,7 @@ class MassController extends Controller } Preferences::mark(); - Session::flash('success', trans('firefly.mass_deleted_transactions_success', ['amount' => $count])); + session()->flash('success', trans('firefly.mass_deleted_transactions_success', ['amount' => $count])); // redirect to previous URL: return redirect($this->getPreviousUri('transactions.mass-delete.uri')); @@ -163,7 +163,7 @@ class MassController extends Controller } if (count($messages) > 0) { - Session::flash('info', $messages); + session()->flash('info', $messages); } // put previous url in session @@ -196,7 +196,7 @@ class MassController extends Controller ); if (0 === $filtered->count()) { - Session::flash('error', trans('firefly.no_edit_multiple_left')); + session()->flash('error', trans('firefly.no_edit_multiple_left')); } $journals = $filtered; @@ -281,7 +281,7 @@ class MassController extends Controller } } Preferences::mark(); - Session::flash('success', trans('firefly.mass_edited_transactions_success', ['amount' => $count])); + session()->flash('success', trans('firefly.mass_edited_transactions_success', ['amount' => $count])); // redirect to previous URL: return redirect($this->getPreviousUri('transactions.mass-edit.uri')); diff --git a/app/Http/Controllers/Transaction/SingleController.php b/app/Http/Controllers/Transaction/SingleController.php index 9159793179..e722a33bd3 100644 --- a/app/Http/Controllers/Transaction/SingleController.php +++ b/app/Http/Controllers/Transaction/SingleController.php @@ -140,7 +140,7 @@ class SingleController extends Controller $preFilled['notes'] = $note->text; } - Session::flash('preFilled', $preFilled); + session()->flash('preFilled', $preFilled); return redirect(route('transactions.create', [strtolower($journal->transactionType->type)])); } @@ -227,7 +227,7 @@ class SingleController extends Controller } // @codeCoverageIgnoreEnd $type = $transactionJournal->transactionTypeStr(); - Session::flash('success', (string)trans('firefly.deleted_' . strtolower($type), ['description' => $transactionJournal->description])); + session()->flash('success', (string)trans('firefly.deleted_' . strtolower($type), ['description' => $transactionJournal->description])); $this->repository->destroy($transactionJournal); @@ -312,7 +312,7 @@ class SingleController extends Controller $preFilled['currency'] = $pTransaction->foreignCurrency; } - Session::flash('preFilled', $preFilled); + session()->flash('preFilled', $preFilled); // put previous url in session if not redirect from store (not "return_to_edit"). if (true !== session('transactions.edit.fromUpdate')) { @@ -343,7 +343,7 @@ class SingleController extends Controller if (null === $journal->id) { // error! Log::error('Could not store transaction journal.'); - Session::flash('error', (string)trans('firefly.unknown_journal_error')); + session()->flash('error', (string)trans('firefly.unknown_journal_error')); return redirect(route('transactions.create', [$request->input('what')]))->withInput(); } @@ -355,16 +355,16 @@ class SingleController extends Controller // store the journal only, flash the rest. Log::debug(sprintf('Count of error messages is %d', $this->attachments->getErrors()->count())); if (\count($this->attachments->getErrors()->get('attachments')) > 0) { - Session::flash('error', $this->attachments->getErrors()->get('attachments')); + session()->flash('error', $this->attachments->getErrors()->get('attachments')); } // flash messages if (\count($this->attachments->getMessages()->get('attachments')) > 0) { - Session::flash('info', $this->attachments->getMessages()->get('attachments')); + session()->flash('info', $this->attachments->getMessages()->get('attachments')); } event(new StoredTransactionJournal($journal, $data['piggy_bank_id'])); - Session::flash('success', (string)trans('firefly.stored_journal', ['description' => $journal->description])); + session()->flash('success', (string)trans('firefly.stored_journal', ['description' => $journal->description])); Preferences::mark(); // @codeCoverageIgnoreStart @@ -410,10 +410,10 @@ class SingleController extends Controller // @codeCoverageIgnoreStart if (count($this->attachments->getErrors()->get('attachments')) > 0) { - Session::flash('error', $this->attachments->getErrors()->get('attachments')); + session()->flash('error', $this->attachments->getErrors()->get('attachments')); } if (count($this->attachments->getMessages()->get('attachments')) > 0) { - Session::flash('info', $this->attachments->getMessages()->get('attachments')); + session()->flash('info', $this->attachments->getMessages()->get('attachments')); } // @codeCoverageIgnoreEnd @@ -421,7 +421,7 @@ class SingleController extends Controller // update, get events by date and sort DESC $type = strtolower($this->repository->getTransactionType($journal)); - Session::flash('success', (string)trans('firefly.updated_' . $type, ['description' => $data['description']])); + session()->flash('success', (string)trans('firefly.updated_' . $type, ['description' => $data['description']])); Preferences::mark(); // @codeCoverageIgnoreStart diff --git a/app/Http/Controllers/Transaction/SplitController.php b/app/Http/Controllers/Transaction/SplitController.php index 94443d2433..b574015d42 100644 --- a/app/Http/Controllers/Transaction/SplitController.php +++ b/app/Http/Controllers/Transaction/SplitController.php @@ -159,12 +159,12 @@ class SplitController extends Controller // flash messages // @codeCoverageIgnoreStart if (count($this->attachments->getMessages()->get('attachments')) > 0) { - Session::flash('info', $this->attachments->getMessages()->get('attachments')); + session()->flash('info', $this->attachments->getMessages()->get('attachments')); } // @codeCoverageIgnoreEnd $type = strtolower($this->repository->getTransactionType($journal)); - Session::flash('success', (string)trans('firefly.updated_' . $type, ['description' => $journal->description])); + session()->flash('success', (string)trans('firefly.updated_' . $type, ['description' => $journal->description])); Preferences::mark(); // @codeCoverageIgnoreStart diff --git a/app/Support/Binder/SimpleJournalList.php b/app/Support/Binder/SimpleJournalList.php new file mode 100644 index 0000000000..0b3dadf344 --- /dev/null +++ b/app/Support/Binder/SimpleJournalList.php @@ -0,0 +1,111 @@ +. + */ + +declare(strict_types=1); + +namespace FireflyIII\Support\Binder; + +use FireflyIII\Models\TransactionJournal; +use FireflyIII\Models\TransactionType; +use FireflyIII\Repositories\Journal\JournalRepositoryInterface; +use Illuminate\Routing\Route; +use Illuminate\Support\Collection; +use Session; +use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; + +/** + * Class SimpleJournalList + */ +class SimpleJournalList implements BinderInterface +{ + /** + * @param string $value + * @param Route $route + * + * @return mixed + * @throws \Symfony\Component\HttpKernel\Exception\NotFoundHttpException + */ + public static function routeBinder(string $value, Route $route): Collection + { + if (auth()->check()) { + $list = []; + $incoming = explode(',', $value); + foreach ($incoming as $entry) { + $list[] = (int)$entry; + } + $list = array_unique($list); + if (\count($list) === 0) { + throw new NotFoundHttpException; // @codeCoverageIgnore + } + + // prep some vars + $messages = []; + $final = new Collection; + /** @var JournalRepositoryInterface $repository */ + $repository = app(JournalRepositoryInterface::class); + + // get all journals: + /** @var \Illuminate\Support\Collection $collection */ + $collection = auth()->user()->transactionJournals() + ->whereIn('transaction_journals.id', $list) + ->where('transaction_journals.completed', 1) + ->get(['transaction_journals.*']); + + // filter the list! Yay! + /** @var TransactionJournal $journal */ + foreach ($collection as $journal) { + $sources = $repository->getJournalSourceAccounts($journal); + $destinations = $repository->getJournalDestinationAccounts($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; + } + if (TransactionType::OPENING_BALANCE === $repository->getTransactionType($journal)) { + $messages[] = trans('firefly.cannot_edit_opening_balance'); + continue; + } + + // cannot edit reconciled transactions / journals: + if ($repository->isJournalReconciled($journal)) { + $messages[] = trans('firefly.cannot_edit_reconciled', ['description' => $journal->description, 'id' => $journal->id]); + continue; + } + + $final->push($journal); + } + + if ($final->count() > 0) { + + if (\count($messages) > 0) { + session()->flash('info', $messages); + } + + return $final; + } + } + throw new NotFoundHttpException; + } +} \ No newline at end of file diff --git a/config/firefly.php b/config/firefly.php index f5b8183ed7..7ff8d17995 100644 --- a/config/firefly.php +++ b/config/firefly.php @@ -165,7 +165,7 @@ return [ 'default_export_format' => 'csv', 'default_import_format' => 'csv', 'bill_periods' => ['weekly', 'monthly', 'quarterly', 'half-year', 'yearly'], - 'accountRoles' => ['defaultAsset', 'sharedAsset', 'savingAsset', 'ccAsset','cashWalletAsset'], + 'accountRoles' => ['defaultAsset', 'sharedAsset', 'savingAsset', 'ccAsset', 'cashWalletAsset'], 'ccTypes' => [ 'monthlyFull' => 'Full payment every month', ], @@ -296,6 +296,7 @@ return [ 'journalList' => \FireflyIII\Support\Binder\JournalList::class, 'categoryList' => \FireflyIII\Support\Binder\CategoryList::class, 'tagList' => \FireflyIII\Support\Binder\TagList::class, + 'simpleJournalList' => \FireflyIII\Support\Binder\SimpleJournalList::class, // others 'fromCurrencyCode' => \FireflyIII\Support\Binder\CurrencyCode::class, diff --git a/routes/web.php b/routes/web.php index 696cc57bf9..d9ce86919a 100755 --- a/routes/web.php +++ b/routes/web.php @@ -835,7 +835,7 @@ Route::group( Route::group( ['middleware' => 'user-full-auth', 'namespace' => 'FireflyIII\Http\Controllers\Transaction', 'prefix' => 'transactions/bulk', 'as' => 'transactions.bulk.'], function () { - Route::get('edit/{journalList}', ['uses' => 'BulkController@edit', 'as' => 'edit']); + Route::get('edit/{simpleJournalList}', ['uses' => 'BulkController@edit', 'as' => 'edit']); Route::post('update', ['uses' => 'BulkController@update', 'as' => 'update']); } ); From 36a5f17af21380121d6b7f885737d48b835ec5d4 Mon Sep 17 00:00:00 2001 From: James Cole Date: Sun, 22 Apr 2018 17:12:22 +0200 Subject: [PATCH 081/117] Code cleanup as described in #1272 --- app/Http/Controllers/Account/ReconcileController.php | 4 ++-- app/Http/Controllers/Admin/UserController.php | 4 ++-- app/Http/Controllers/Controller.php | 2 +- app/Http/Controllers/PiggyBankController.php | 8 ++++---- app/Http/Controllers/PreferencesController.php | 6 +++--- app/Http/Controllers/ProfileController.php | 4 ++-- app/Http/Controllers/RuleController.php | 8 ++++---- app/Http/Controllers/RuleGroupController.php | 8 ++++---- app/Http/Controllers/TagController.php | 8 ++++---- app/Http/Controllers/Transaction/BulkController.php | 2 -- .../Controllers/Transaction/SingleController.php | 12 ++++++------ app/Http/Controllers/Transaction/SplitController.php | 4 ++-- 12 files changed, 34 insertions(+), 36 deletions(-) diff --git a/app/Http/Controllers/Account/ReconcileController.php b/app/Http/Controllers/Account/ReconcileController.php index d4b5a0dc60..d8fd0cd6c3 100644 --- a/app/Http/Controllers/Account/ReconcileController.php +++ b/app/Http/Controllers/Account/ReconcileController.php @@ -106,7 +106,7 @@ class ReconcileController extends Controller if (true !== session('reconcile.edit.fromUpdate')) { $this->rememberPreviousUri('reconcile.edit.uri'); } - Session::forget('reconcile.edit.fromUpdate'); + session()->forget('reconcile.edit.fromUpdate'); return view( 'accounts.reconcile.edit', @@ -444,7 +444,7 @@ class ReconcileController extends Controller // @codeCoverageIgnoreStart if (1 === (int)$request->get('return_to_edit')) { - Session::put('reconcile.edit.fromUpdate', true); + session()->put('reconcile.edit.fromUpdate', true); return redirect(route('accounts.reconcile.edit', [$journal->id]))->withInput(['return_to_edit' => 1]); } diff --git a/app/Http/Controllers/Admin/UserController.php b/app/Http/Controllers/Admin/UserController.php index 52668c09ad..0f514dc232 100644 --- a/app/Http/Controllers/Admin/UserController.php +++ b/app/Http/Controllers/Admin/UserController.php @@ -94,7 +94,7 @@ class UserController extends Controller if (true !== session('users.edit.fromUpdate')) { $this->rememberPreviousUri('users.edit.uri'); } - Session::forget('users.edit.fromUpdate'); + session()->forget('users.edit.fromUpdate'); $subTitle = (string)trans('firefly.edit_user', ['email' => $user->email]); $subTitleIcon = 'fa-user-o'; @@ -187,7 +187,7 @@ class UserController extends Controller if (1 === (int)$request->get('return_to_edit')) { // @codeCoverageIgnoreStart - Session::put('users.edit.fromUpdate', true); + session()->put('users.edit.fromUpdate', true); return redirect(route('admin.users.edit', [$user->id]))->withInput(['return_to_edit' => 1]); // @codeCoverageIgnoreEnd diff --git a/app/Http/Controllers/Controller.php b/app/Http/Controllers/Controller.php index 8cb0036c5d..ec49442c69 100644 --- a/app/Http/Controllers/Controller.php +++ b/app/Http/Controllers/Controller.php @@ -174,6 +174,6 @@ class Controller extends BaseController */ protected function rememberPreviousUri(string $identifier) { - Session::put($identifier, URL::previous()); + session()->put($identifier, URL::previous()); } } diff --git a/app/Http/Controllers/PiggyBankController.php b/app/Http/Controllers/PiggyBankController.php index 2ada211d3a..1e34577ae1 100644 --- a/app/Http/Controllers/PiggyBankController.php +++ b/app/Http/Controllers/PiggyBankController.php @@ -137,7 +137,7 @@ class PiggyBankController extends Controller if (true !== session('piggy-banks.create.fromStore')) { $this->rememberPreviousUri('piggy-banks.create.uri'); } - Session::forget('piggy-banks.create.fromStore'); + session()->forget('piggy-banks.create.fromStore'); return view('piggy-banks.create', compact('subTitle', 'subTitleIcon')); } @@ -204,7 +204,7 @@ class PiggyBankController extends Controller if (true !== session('piggy-banks.edit.fromUpdate')) { $this->rememberPreviousUri('piggy-banks.edit.uri'); } - Session::forget('piggy-banks.edit.fromUpdate'); + session()->forget('piggy-banks.edit.fromUpdate'); return view('piggy-banks.edit', compact('subTitle', 'subTitleIcon', 'piggyBank', 'preFilled')); } @@ -435,7 +435,7 @@ class PiggyBankController extends Controller if (1 === (int)$request->get('create_another')) { // @codeCoverageIgnoreStart - Session::put('piggy-banks.create.fromStore', true); + session()->put('piggy-banks.create.fromStore', true); return redirect(route('piggy-banks.create'))->withInput(); // @codeCoverageIgnoreEnd @@ -460,7 +460,7 @@ class PiggyBankController extends Controller if (1 === (int)$request->get('return_to_edit')) { // @codeCoverageIgnoreStart - Session::put('piggy-banks.edit.fromUpdate', true); + session()->put('piggy-banks.edit.fromUpdate', true); return redirect(route('piggy-banks.edit', [$piggyBank->id])); // @codeCoverageIgnoreEnd diff --git a/app/Http/Controllers/PreferencesController.php b/app/Http/Controllers/PreferencesController.php index 6e66ed4ab9..2a2dedfe55 100644 --- a/app/Http/Controllers/PreferencesController.php +++ b/app/Http/Controllers/PreferencesController.php @@ -105,9 +105,9 @@ class PreferencesController extends Controller // view range: Preferences::set('viewRange', $request->get('viewRange')); // forget session values: - Session::forget('start'); - Session::forget('end'); - Session::forget('range'); + session()->forget('start'); + session()->forget('end'); + session()->forget('range'); // custom fiscal year $customFiscalYear = 1 === (int)$request->get('customFiscalYear'); diff --git a/app/Http/Controllers/ProfileController.php b/app/Http/Controllers/ProfileController.php index 51d0a377e1..dc2f2cdd3a 100644 --- a/app/Http/Controllers/ProfileController.php +++ b/app/Http/Controllers/ProfileController.php @@ -307,7 +307,7 @@ class ProfileController extends Controller public function postCode(TokenFormRequest $request) { Preferences::set('twoFactorAuthEnabled', 1); - Preferences::set('twoFactorAuthSecret', Session::get('two-factor-secret')); + Preferences::set('twoFactorAuthSecret', session()->get('two-factor-secret')); session()->flash('success', (string)trans('firefly.saved_preferences')); Preferences::mark(); @@ -332,7 +332,7 @@ class ProfileController extends Controller Log::info(sprintf('User #%d has opted to delete their account', auth()->user()->id)); // make repository delete user: auth()->logout(); - Session::flush(); + session()->flush(); $repository->destroy($user); return redirect(route('index')); diff --git a/app/Http/Controllers/RuleController.php b/app/Http/Controllers/RuleController.php index dce7622951..55eed182cb 100644 --- a/app/Http/Controllers/RuleController.php +++ b/app/Http/Controllers/RuleController.php @@ -146,7 +146,7 @@ class RuleController extends Controller if (true !== session('rules.create.fromStore')) { $this->rememberPreviousUri('rules.create.uri'); } - Session::forget('rules.create.fromStore'); + session()->forget('rules.create.fromStore'); return view( 'rules.rule.create', @@ -242,7 +242,7 @@ class RuleController extends Controller if (true !== session('rules.edit.fromUpdate')) { $this->rememberPreviousUri('rules.edit.uri'); } - Session::forget('rules.edit.fromUpdate'); + session()->forget('rules.edit.fromUpdate'); return view('rules.rule.edit', compact('rule', 'subTitle', 'primaryTrigger', 'oldTriggers', 'oldActions', 'triggerCount', 'actionCount', 'ruleGroups')); } @@ -370,7 +370,7 @@ class RuleController extends Controller if (1 === (int)$request->get('create_another')) { // @codeCoverageIgnoreStart - Session::put('rules.create.fromStore', true); + session()->put('rules.create.fromStore', true); return redirect(route('rules.create', [$data['rule_group_id']]))->withInput(); // @codeCoverageIgnoreEnd @@ -522,7 +522,7 @@ class RuleController extends Controller if (1 === (int)$request->get('return_to_edit')) { // @codeCoverageIgnoreStart - Session::put('rules.edit.fromUpdate', true); + session()->put('rules.edit.fromUpdate', true); return redirect(route('rules.edit', [$rule->id]))->withInput(['return_to_edit' => 1]); // @codeCoverageIgnoreEnd diff --git a/app/Http/Controllers/RuleGroupController.php b/app/Http/Controllers/RuleGroupController.php index 2d139e9361..0f91704347 100644 --- a/app/Http/Controllers/RuleGroupController.php +++ b/app/Http/Controllers/RuleGroupController.php @@ -70,7 +70,7 @@ class RuleGroupController extends Controller if (true !== session('rule-groups.create.fromStore')) { $this->rememberPreviousUri('rule-groups.create.uri'); } - Session::forget('rule-groups.create.fromStore'); + session()->forget('rule-groups.create.fromStore'); return view('rules.rule-group.create', compact('subTitleIcon', 'subTitle')); } @@ -140,7 +140,7 @@ class RuleGroupController extends Controller if (true !== session('rule-groups.edit.fromUpdate')) { $this->rememberPreviousUri('rule-groups.edit.uri'); } - Session::forget('rule-groups.edit.fromUpdate'); + session()->forget('rule-groups.edit.fromUpdate'); return view('rules.rule-group.edit', compact('ruleGroup', 'subTitle')); } @@ -214,7 +214,7 @@ class RuleGroupController extends Controller if (1 === (int)$request->get('create_another')) { // @codeCoverageIgnoreStart - Session::put('rule-groups.create.fromStore', true); + session()->put('rule-groups.create.fromStore', true); return redirect(route('rule-groups.create'))->withInput(); // @codeCoverageIgnoreEnd @@ -258,7 +258,7 @@ class RuleGroupController extends Controller if (1 === (int)$request->get('return_to_edit')) { // @codeCoverageIgnoreStart - Session::put('rule-groups.edit.fromUpdate', true); + session()->put('rule-groups.edit.fromUpdate', true); return redirect(route('rule-groups.edit', [$ruleGroup->id]))->withInput(['return_to_edit' => 1]); // @codeCoverageIgnoreEnd diff --git a/app/Http/Controllers/TagController.php b/app/Http/Controllers/TagController.php index ffc0e7a838..0a67591875 100644 --- a/app/Http/Controllers/TagController.php +++ b/app/Http/Controllers/TagController.php @@ -86,7 +86,7 @@ class TagController extends Controller if (true !== session('tags.create.fromStore')) { $this->rememberPreviousUri('tags.create.uri'); } - Session::forget('tags.create.fromStore'); + session()->forget('tags.create.fromStore'); return view('tags.create', compact('subTitle', 'subTitleIcon', 'apiKey')); } @@ -141,7 +141,7 @@ class TagController extends Controller if (true !== session('tags.edit.fromUpdate')) { $this->rememberPreviousUri('tags.edit.uri'); } - Session::forget('tags.edit.fromUpdate'); + session()->forget('tags.edit.fromUpdate'); return view('tags.edit', compact('tag', 'subTitle', 'subTitleIcon', 'apiKey')); } @@ -266,7 +266,7 @@ class TagController extends Controller if (1 === (int)$request->get('create_another')) { // @codeCoverageIgnoreStart - Session::put('tags.create.fromStore', true); + session()->put('tags.create.fromStore', true); return redirect(route('tags.create'))->withInput(); // @codeCoverageIgnoreEnd @@ -291,7 +291,7 @@ class TagController extends Controller if (1 === (int)$request->get('return_to_edit')) { // @codeCoverageIgnoreStart - Session::put('tags.edit.fromUpdate', true); + session()->put('tags.edit.fromUpdate', true); return redirect(route('tags.edit', [$tag->id]))->withInput(['return_to_edit' => 1]); // @codeCoverageIgnoreEnd diff --git a/app/Http/Controllers/Transaction/BulkController.php b/app/Http/Controllers/Transaction/BulkController.php index ab1dd5f0f7..72e807051c 100644 --- a/app/Http/Controllers/Transaction/BulkController.php +++ b/app/Http/Controllers/Transaction/BulkController.php @@ -30,8 +30,6 @@ use FireflyIII\Http\Requests\BulkEditJournalRequest; use FireflyIII\Models\TransactionJournal; use FireflyIII\Repositories\Budget\BudgetRepositoryInterface; use FireflyIII\Repositories\Journal\JournalRepositoryInterface; -use FireflyIII\Services\Internal\Update\JournalUpdateService; -use Illuminate\Http\Request; use Illuminate\Support\Collection; use Log; use Preferences; diff --git a/app/Http/Controllers/Transaction/SingleController.php b/app/Http/Controllers/Transaction/SingleController.php index e722a33bd3..3ef98a6fd4 100644 --- a/app/Http/Controllers/Transaction/SingleController.php +++ b/app/Http/Controllers/Transaction/SingleController.php @@ -158,7 +158,7 @@ class SingleController extends Controller $budgets = ExpandedForm::makeSelectListWithEmpty($this->budgets->getActiveBudgets()); $piggyBanks = $this->piggyBanks->getPiggyBanksWithAmount(); $piggies = ExpandedForm::makeSelectListWithEmpty($piggyBanks); - $preFilled = Session::has('preFilled') ? session('preFilled') : []; + $preFilled = session()->has('preFilled') ? session('preFilled') : []; $subTitle = trans('form.add_new_' . $what); $subTitleIcon = 'fa-plus'; $optionalFields = Preferences::get('transaction_journal_optional_fields', [])->data; @@ -171,13 +171,13 @@ class SingleController extends Controller $preFilled['destination_account_id'] = $source; } - Session::put('preFilled', $preFilled); + session()->put('preFilled', $preFilled); // put previous url in session if not redirect from store (not "create another"). if (true !== session('transactions.create.fromStore')) { $this->rememberPreviousUri('transactions.create.uri'); } - Session::forget('transactions.create.fromStore'); + session()->forget('transactions.create.fromStore'); asort($piggies); @@ -318,7 +318,7 @@ class SingleController extends Controller if (true !== session('transactions.edit.fromUpdate')) { $this->rememberPreviousUri('transactions.edit.uri'); } - Session::forget('transactions.edit.fromUpdate'); + session()->forget('transactions.edit.fromUpdate'); return view( 'transactions.single.edit', @@ -369,7 +369,7 @@ class SingleController extends Controller // @codeCoverageIgnoreStart if (true === $createAnother) { - Session::put('transactions.create.fromStore', true); + session()->put('transactions.create.fromStore', true); return redirect(route('transactions.create', [$request->input('what')]))->withInput(); } @@ -426,7 +426,7 @@ class SingleController extends Controller // @codeCoverageIgnoreStart if (1 === (int)$request->get('return_to_edit')) { - Session::put('transactions.edit.fromUpdate', true); + session()->put('transactions.edit.fromUpdate', true); return redirect(route('transactions.edit', [$journal->id]))->withInput(['return_to_edit' => 1]); } diff --git a/app/Http/Controllers/Transaction/SplitController.php b/app/Http/Controllers/Transaction/SplitController.php index b574015d42..936b5cf15b 100644 --- a/app/Http/Controllers/Transaction/SplitController.php +++ b/app/Http/Controllers/Transaction/SplitController.php @@ -122,7 +122,7 @@ class SplitController extends Controller if (true !== session('transactions.edit-split.fromUpdate')) { $this->rememberPreviousUri('transactions.edit-split.uri'); } - Session::forget('transactions.edit-split.fromUpdate'); + session()->forget('transactions.edit-split.fromUpdate'); return view( 'transactions.split.edit', compact( @@ -170,7 +170,7 @@ class SplitController extends Controller // @codeCoverageIgnoreStart if (1 === (int)$request->get('return_to_edit')) { // set value so edit routine will not overwrite URL: - Session::put('transactions.edit-split.fromUpdate', true); + session()->put('transactions.edit-split.fromUpdate', true); return redirect(route('transactions.split.edit', [$journal->id]))->withInput(['return_to_edit' => 1]); } From 4fcdfd41fa7ecf92edd8ba77a34af17acfce9f16 Mon Sep 17 00:00:00 2001 From: James Cole Date: Sun, 22 Apr 2018 19:17:43 +0200 Subject: [PATCH 082/117] Update readme [skip ci] --- readme.md | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/readme.md b/readme.md index 2b7eedb67b..227444a421 100644 --- a/readme.md +++ b/readme.md @@ -37,8 +37,7 @@ [![Overview of all budgets](https://firefly-iii.org/static/screenshots/4.7.0/tiny/budget.png)](https://firefly-iii.org/static/screenshots/4.7.0/budget.png) [![Overview of a category](https://firefly-iii.org/static/screenshots/4.7.0/tiny/category.png)](https://firefly-iii.org/static/screenshots/4.7.0/category.png) ### Purpose -Personal financial management is pretty difficult, and everybody has their own approach to it. Some people make budgets, other people limit their cashflow by throwing away their credit cards, -others try to increase their current cashflow. There are tons of ways to save and earn money. Firefly III works on the principle that if you know where you're money is going, you can stop it from going there. +Personal financial management is pretty difficult, and everybody has their own approach to it. Some people make budgets, other people limit their cashflow by throwing away their credit cards, others try to increase their current cashflow. There are tons of ways to save and earn money. Firefly III works on the principle that if you know where you're money is going, you can stop it from going there. By keeping track of your expenses and your income you can budget accordingly and save money. Stop living from paycheck to paycheck but give yourself the financial wiggle room you need. @@ -109,6 +108,8 @@ Of course there are some [contributing guidelines](https://github.com/firefly-ii I can always use your help [squashing bugs](http://firefly-iii.readthedocs.io/en/latest/support/contribute.html#bugs), thinking about [new features](http://firefly-iii.readthedocs.io/en/latest/support/contribute.html#feature-requests) or [translating Firefly III](http://firefly-iii.readthedocs.io/en/latest/support/contribute.html#translations) into other languages. +For all other contributions, see below. + ## The goal Firefly III should give you **insight** into and **control** over your finances. Money should be useful, not scary. You should be able to *see* where it is going, to *feel* your expenses and to... wow, I'm going overboard with this aren't I? @@ -127,7 +128,9 @@ We use [SemVer](http://semver.org/) for versioning. For the versions available, This work [is licensed](https://github.com/firefly-iii/firefly-iii/blob/master/LICENSE) under the [GPL v3](https://www.gnu.org/licenses/gpl.html). ### Donate -If you like Firefly III and if it helps you save lots of money, why not send me [a dime for every dollar saved](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=44UKUT455HUFA) (this is a joke, although the Paypal form works just fine, try it!) +If you like Firefly III and if it helps you save lots of money, why not send me a dime for every dollar you saved using Firefly III! + +OK that was a joke. Thank you for considering donating to Firefly III! Please checkout [my Patreon page](https://www.patreon.com/jc5) or visit [PayPal](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=44UKUT455HUFA). ### Alternatives If you are looking for alternatives, check out [Kickball's Awesome-Selfhosted list](https://github.com/Kickball/awesome-selfhosted) which features not only Firefly III but also noteworthy alternatives such as [Silverstrike](https://github.com/agstrike/silverstrike). From 1eea81e9dd8b82ac072b16e4e5885ae16e5063f1 Mon Sep 17 00:00:00 2001 From: James Cole Date: Sun, 22 Apr 2018 19:18:57 +0200 Subject: [PATCH 083/117] Update readme [skip ci] --- readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.md b/readme.md index 227444a421..05e6bd0d8f 100644 --- a/readme.md +++ b/readme.md @@ -128,7 +128,7 @@ We use [SemVer](http://semver.org/) for versioning. For the versions available, This work [is licensed](https://github.com/firefly-iii/firefly-iii/blob/master/LICENSE) under the [GPL v3](https://www.gnu.org/licenses/gpl.html). ### Donate -If you like Firefly III and if it helps you save lots of money, why not send me a dime for every dollar you saved using Firefly III! +If you like Firefly III and if it helps you save lots of money, why not send me a dime for every dollar saved! OK that was a joke. Thank you for considering donating to Firefly III! Please checkout [my Patreon page](https://www.patreon.com/jc5) or visit [PayPal](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=44UKUT455HUFA). From 798d9ee876be9abe8e4231b25622a0786eb9723b Mon Sep 17 00:00:00 2001 From: James Cole Date: Tue, 24 Apr 2018 19:23:32 +0200 Subject: [PATCH 084/117] Mail to logbooks. --- .env.example | 2 +- .env.heroku | 2 +- .env.sandstorm | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.env.example b/.env.example index d8a506824c..2f2f38771a 100644 --- a/.env.example +++ b/.env.example @@ -54,7 +54,7 @@ COOKIE_DOMAIN= COOKIE_SECURE=false # If you want Firefly III to mail you, update these settings -MAIL_DRIVER=smtp +MAIL_DRIVER=log MAIL_HOST=smtp.mailtrap.io MAIL_PORT=2525 MAIL_FROM=changeme@example.com diff --git a/.env.heroku b/.env.heroku index c798fc0a29..e25675664d 100644 --- a/.env.heroku +++ b/.env.heroku @@ -54,7 +54,7 @@ COOKIE_DOMAIN= COOKIE_SECURE=false # If you want Firefly III to mail you, update these settings -MAIL_DRIVER=smtp +MAIL_DRIVER=log MAIL_HOST=smtp.mailtrap.io MAIL_PORT=2525 MAIL_FROM=changeme@example.com diff --git a/.env.sandstorm b/.env.sandstorm index 9b3a8f8e86..8aa9358af8 100755 --- a/.env.sandstorm +++ b/.env.sandstorm @@ -54,7 +54,7 @@ COOKIE_DOMAIN= COOKIE_SECURE=false # If you want Firefly III to mail you, update these settings -MAIL_DRIVER=smtp +MAIL_DRIVER=log MAIL_HOST=smtp.mailtrap.io MAIL_PORT=2525 MAIL_FROM=changeme@example.com From f78b8f92679c68929efb21b5e287a3f29750d4b7 Mon Sep 17 00:00:00 2001 From: James Cole Date: Tue, 24 Apr 2018 19:26:16 +0200 Subject: [PATCH 085/117] Some code for #1272 --- .../Account/ReconcileController.php | 7 +- .../Admin/ConfigurationController.php | 1 - app/Http/Controllers/Admin/HomeController.php | 1 - .../Controllers/Admin/UpdateController.php | 1 - app/Http/Controllers/Admin/UserController.php | 1 - .../Controllers/Auth/RegisterController.php | 1 - app/Http/Controllers/BudgetController.php | 4 +- app/Http/Controllers/Controller.php | 3 +- app/Http/Controllers/JsonController.php | 4 - app/Http/Controllers/NewUserController.php | 1 - app/Http/Controllers/PiggyBankController.php | 31 ++- .../Controllers/PreferencesController.php | 1 - app/Http/Controllers/ProfileController.php | 1 - app/Http/Controllers/ReportController.php | 1 - app/Http/Controllers/RuleController.php | 1 - app/Http/Controllers/RuleGroupController.php | 1 - app/Http/Controllers/TagController.php | 1 - .../Transaction/ConvertController.php | 1 - .../Transaction/LinkController.php | 1 - .../Transaction/MassController.php | 95 +++------ .../Transaction/SingleController.php | 1 - .../Transaction/SplitController.php | 5 +- .../Journal/JournalRepository.php | 14 ++ .../Journal/JournalRepositoryInterface.php | 11 ++ app/Transformers/TransactionTransformer.php | 14 +- resources/views/transactions/mass/edit.twig | 180 +++++++++--------- routes/breadcrumbs.php | 7 +- routes/web.php | 2 +- 28 files changed, 172 insertions(+), 220 deletions(-) diff --git a/app/Http/Controllers/Account/ReconcileController.php b/app/Http/Controllers/Account/ReconcileController.php index d8fd0cd6c3..047de6bc14 100644 --- a/app/Http/Controllers/Account/ReconcileController.php +++ b/app/Http/Controllers/Account/ReconcileController.php @@ -41,7 +41,6 @@ use Illuminate\Http\Request; use Illuminate\Support\Collection; use Log; use Preferences; -use Session; /** * Class ReconcileController. @@ -217,6 +216,7 @@ class ReconcileController extends Controller $transactionsUri = route('accounts.reconcile.transactions', [$account->id, '%start%', '%end%']); $overviewUri = route('accounts.reconcile.overview', [$account->id, '%start%', '%end%']); $indexUri = route('accounts.reconcile', [$account->id, '%start%', '%end%']); + return view( 'accounts.reconcile.index', compact( 'account', 'currency', 'subTitleIcon', 'start', 'end', 'subTitle', 'startBalance', 'endBalance', 'transactionsUri', @@ -370,7 +370,9 @@ class ReconcileController extends Controller $collector->setAccounts(new Collection([$account])) ->setRange($selectionStart, $selectionEnd)->withBudgetInformation()->withOpposingAccount()->withCategoryInformation(); $transactions = $collector->getJournals(); - $html = view('accounts.reconcile.transactions', compact('account', 'transactions','currency', 'start', 'end', 'selectionStart', 'selectionEnd'))->render(); + $html = view( + 'accounts.reconcile.transactions', compact('account', 'transactions', 'currency', 'start', 'end', 'selectionStart', 'selectionEnd') + )->render(); return response()->json(['html' => $html, 'startBalance' => $startBalance, 'endBalance' => $endBalance]); } @@ -441,7 +443,6 @@ class ReconcileController extends Controller $this->repository->update($journal, $data); - // @codeCoverageIgnoreStart if (1 === (int)$request->get('return_to_edit')) { session()->put('reconcile.edit.fromUpdate', true); diff --git a/app/Http/Controllers/Admin/ConfigurationController.php b/app/Http/Controllers/Admin/ConfigurationController.php index f444af9ee5..f38c2263a8 100644 --- a/app/Http/Controllers/Admin/ConfigurationController.php +++ b/app/Http/Controllers/Admin/ConfigurationController.php @@ -29,7 +29,6 @@ use FireflyIII\Http\Requests\ConfigurationRequest; use FireflyIII\Support\Facades\FireflyConfig; use Preferences; use Redirect; -use Session; use View; /** diff --git a/app/Http/Controllers/Admin/HomeController.php b/app/Http/Controllers/Admin/HomeController.php index ecd403b1f3..92d0760119 100644 --- a/app/Http/Controllers/Admin/HomeController.php +++ b/app/Http/Controllers/Admin/HomeController.php @@ -28,7 +28,6 @@ use FireflyIII\Http\Middleware\IsDemoUser; use FireflyIII\Http\Middleware\IsSandStormUser; use Illuminate\Http\Request; use Log; -use Session; /** * Class HomeController. diff --git a/app/Http/Controllers/Admin/UpdateController.php b/app/Http/Controllers/Admin/UpdateController.php index 28ae82489f..9aadf140dc 100644 --- a/app/Http/Controllers/Admin/UpdateController.php +++ b/app/Http/Controllers/Admin/UpdateController.php @@ -32,7 +32,6 @@ use FireflyIII\Services\Github\Object\Release; use FireflyIII\Services\Github\Request\UpdateRequest; use Illuminate\Http\Request; use Log; -use Session; /** * Class HomeController. diff --git a/app/Http/Controllers/Admin/UserController.php b/app/Http/Controllers/Admin/UserController.php index 0f514dc232..a1df8408c6 100644 --- a/app/Http/Controllers/Admin/UserController.php +++ b/app/Http/Controllers/Admin/UserController.php @@ -30,7 +30,6 @@ use FireflyIII\Repositories\User\UserRepositoryInterface; use FireflyIII\User; use Log; use Preferences; -use Session; use View; /** diff --git a/app/Http/Controllers/Auth/RegisterController.php b/app/Http/Controllers/Auth/RegisterController.php index b67861652d..265cd0924d 100644 --- a/app/Http/Controllers/Auth/RegisterController.php +++ b/app/Http/Controllers/Auth/RegisterController.php @@ -29,7 +29,6 @@ use Illuminate\Auth\Events\Registered; use Illuminate\Foundation\Auth\RegistersUsers; use Illuminate\Http\Request; use Illuminate\Support\Facades\Validator; -use Session; /** * @codeCoverageIgnore diff --git a/app/Http/Controllers/BudgetController.php b/app/Http/Controllers/BudgetController.php index f82fa49e95..f14ed31da5 100644 --- a/app/Http/Controllers/BudgetController.php +++ b/app/Http/Controllers/BudgetController.php @@ -127,8 +127,8 @@ class BudgetController extends Controller $warnText = (string)trans( 'firefly.over_budget_warn', [ - 'amount' => app('amount')->formatAnything($currency, $average, false), - 'over_amount' => app('amount')->formatAnything($currency, $current, false), + 'amount' => app('amount')->formatAnything($currency, $average, false), + 'over_amount' => app('amount')->formatAnything($currency, $current, false), ] ); } diff --git a/app/Http/Controllers/Controller.php b/app/Http/Controllers/Controller.php index ec49442c69..2e206063ff 100644 --- a/app/Http/Controllers/Controller.php +++ b/app/Http/Controllers/Controller.php @@ -34,7 +34,6 @@ use Illuminate\Foundation\Validation\ValidatesRequests; use Illuminate\Routing\Controller as BaseController; use Log; use Route; -use Session; use URL; use View; @@ -99,7 +98,7 @@ class Controller extends BaseController } // share language - $language = Preferences::get('language', config('firefly.default_language', 'en_US'))->data; + $language = Preferences::get('language', config('firefly.default_language', 'en_US'))->data; View::share('language', $language); View::share('shownDemo', $shownDemo); diff --git a/app/Http/Controllers/JsonController.php b/app/Http/Controllers/JsonController.php index 1ab9a93808..fddd772a25 100644 --- a/app/Http/Controllers/JsonController.php +++ b/app/Http/Controllers/JsonController.php @@ -22,10 +22,6 @@ declare(strict_types=1); namespace FireflyIII\Http\Controllers; -use FireflyIII\Repositories\Budget\BudgetRepositoryInterface; -use FireflyIII\Repositories\Category\CategoryRepositoryInterface; -use FireflyIII\Repositories\Journal\JournalRepositoryInterface; -use FireflyIII\Repositories\Tag\TagRepositoryInterface; use Illuminate\Http\Request; /** diff --git a/app/Http/Controllers/NewUserController.php b/app/Http/Controllers/NewUserController.php index d8e7a85fe2..cf3d0223e0 100644 --- a/app/Http/Controllers/NewUserController.php +++ b/app/Http/Controllers/NewUserController.php @@ -28,7 +28,6 @@ use FireflyIII\Models\TransactionCurrency; use FireflyIII\Repositories\Account\AccountRepositoryInterface; use FireflyIII\Repositories\Currency\CurrencyRepositoryInterface; use Preferences; -use Session; use View; /** diff --git a/app/Http/Controllers/PiggyBankController.php b/app/Http/Controllers/PiggyBankController.php index 1e34577ae1..8fe2936832 100644 --- a/app/Http/Controllers/PiggyBankController.php +++ b/app/Http/Controllers/PiggyBankController.php @@ -35,7 +35,6 @@ use Illuminate\Pagination\LengthAwarePaginator; use Illuminate\Support\Collection; use Log; use Preferences; -use Session; use Symfony\Component\HttpFoundation\ParameterBag; use View; @@ -158,7 +157,7 @@ class PiggyBankController extends Controller } /** - * @param PiggyBank $piggyBank + * @param PiggyBank $piggyBank * * @return \Illuminate\Http\RedirectResponse */ @@ -210,7 +209,7 @@ class PiggyBankController extends Controller } /** - * @param Request $request + * @param Request $request * * @return View */ @@ -263,7 +262,7 @@ class PiggyBankController extends Controller } /** - * @param Request $request + * @param Request $request * * @return \Illuminate\Http\JsonResponse */ @@ -284,15 +283,15 @@ class PiggyBankController extends Controller } /** - * @param Request $request - * @param PiggyBank $piggyBank + * @param Request $request + * @param PiggyBank $piggyBank * * @return \Illuminate\Http\RedirectResponse */ public function postAdd(Request $request, PiggyBank $piggyBank) { - $amount = $request->get('amount') ?? '0'; - $currency = app('amount')->getDefaultCurrency(); + $amount = $request->get('amount') ?? '0'; + $currency = app('amount')->getDefaultCurrency(); $currencyId = (int)$this->accountRepos->getMetaValue($piggyBank->account, 'currency_id'); if ($currencyId > 0) { $currency = $this->currencyRepos->findNull($currencyId); @@ -324,15 +323,15 @@ class PiggyBankController extends Controller } /** - * @param Request $request - * @param PiggyBank $piggyBank + * @param Request $request + * @param PiggyBank $piggyBank * * @return \Illuminate\Http\RedirectResponse */ public function postRemove(Request $request, PiggyBank $piggyBank) { - $amount = $request->get('amount') ?? '0'; - $currency = app('amount')->getDefaultCurrency(); + $amount = $request->get('amount') ?? '0'; + $currency = app('amount')->getDefaultCurrency(); $currencyId = (int)$this->accountRepos->getMetaValue($piggyBank->account, 'currency_id'); if ($currencyId > 0) { $currency = $this->currencyRepos->findNull($currencyId); @@ -404,7 +403,7 @@ class PiggyBankController extends Controller } /** - * @param PiggyBank $piggyBank + * @param PiggyBank $piggyBank * * @return View */ @@ -418,7 +417,7 @@ class PiggyBankController extends Controller } /** - * @param PiggyBankFormRequest $request + * @param PiggyBankFormRequest $request * * @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector */ @@ -445,8 +444,8 @@ class PiggyBankController extends Controller } /** - * @param PiggyBankFormRequest $request - * @param PiggyBank $piggyBank + * @param PiggyBankFormRequest $request + * @param PiggyBank $piggyBank * * @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector */ diff --git a/app/Http/Controllers/PreferencesController.php b/app/Http/Controllers/PreferencesController.php index 2a2dedfe55..17e8adc52b 100644 --- a/app/Http/Controllers/PreferencesController.php +++ b/app/Http/Controllers/PreferencesController.php @@ -27,7 +27,6 @@ use FireflyIII\Repositories\Account\AccountRepositoryInterface; use FireflyIII\Repositories\User\UserRepositoryInterface; use Illuminate\Http\Request; use Preferences; -use Session; use View; /** diff --git a/app/Http/Controllers/ProfileController.php b/app/Http/Controllers/ProfileController.php index dc2f2cdd3a..12c9923f6c 100644 --- a/app/Http/Controllers/ProfileController.php +++ b/app/Http/Controllers/ProfileController.php @@ -44,7 +44,6 @@ use Laravel\Passport\Passport; use Log; use phpseclib\Crypt\RSA; use Preferences; -use Session; use View; /** diff --git a/app/Http/Controllers/ReportController.php b/app/Http/Controllers/ReportController.php index 7d4b3ea82f..bfb00130f7 100644 --- a/app/Http/Controllers/ReportController.php +++ b/app/Http/Controllers/ReportController.php @@ -36,7 +36,6 @@ use Illuminate\Http\RedirectResponse; use Illuminate\Support\Collection; use Log; use Preferences; -use Session; use View; /** diff --git a/app/Http/Controllers/RuleController.php b/app/Http/Controllers/RuleController.php index 55eed182cb..05cafcd305 100644 --- a/app/Http/Controllers/RuleController.php +++ b/app/Http/Controllers/RuleController.php @@ -45,7 +45,6 @@ use Illuminate\Http\Request; use Illuminate\Support\Collection; use Log; use Preferences; -use Session; use Throwable; use View; diff --git a/app/Http/Controllers/RuleGroupController.php b/app/Http/Controllers/RuleGroupController.php index 0f91704347..16c44dea94 100644 --- a/app/Http/Controllers/RuleGroupController.php +++ b/app/Http/Controllers/RuleGroupController.php @@ -33,7 +33,6 @@ use FireflyIII\Repositories\Account\AccountRepositoryInterface; use FireflyIII\Repositories\RuleGroup\RuleGroupRepositoryInterface; use Illuminate\Http\Request; use Preferences; -use Session; use View; /** diff --git a/app/Http/Controllers/TagController.php b/app/Http/Controllers/TagController.php index 0a67591875..43a8b57470 100644 --- a/app/Http/Controllers/TagController.php +++ b/app/Http/Controllers/TagController.php @@ -32,7 +32,6 @@ use FireflyIII\Support\CacheProperties; use Illuminate\Http\Request; use Illuminate\Support\Collection; use Preferences; -use Session; use View; /** diff --git a/app/Http/Controllers/Transaction/ConvertController.php b/app/Http/Controllers/Transaction/ConvertController.php index 64962a9e67..ed0aca2d5e 100644 --- a/app/Http/Controllers/Transaction/ConvertController.php +++ b/app/Http/Controllers/Transaction/ConvertController.php @@ -30,7 +30,6 @@ use FireflyIII\Models\TransactionType; use FireflyIII\Repositories\Account\AccountRepositoryInterface; use FireflyIII\Repositories\Journal\JournalRepositoryInterface; use Illuminate\Http\Request; -use Session; use View; /** diff --git a/app/Http/Controllers/Transaction/LinkController.php b/app/Http/Controllers/Transaction/LinkController.php index e12f51afd5..c238f36f01 100644 --- a/app/Http/Controllers/Transaction/LinkController.php +++ b/app/Http/Controllers/Transaction/LinkController.php @@ -30,7 +30,6 @@ use FireflyIII\Repositories\Journal\JournalRepositoryInterface; use FireflyIII\Repositories\LinkType\LinkTypeRepositoryInterface; use Log; use Preferences; -use Session; use URL; /** diff --git a/app/Http/Controllers/Transaction/MassController.php b/app/Http/Controllers/Transaction/MassController.php index d9aca02868..a99e87edbc 100644 --- a/app/Http/Controllers/Transaction/MassController.php +++ b/app/Http/Controllers/Transaction/MassController.php @@ -23,19 +23,22 @@ declare(strict_types=1); namespace FireflyIII\Http\Controllers\Transaction; use Carbon\Carbon; +use FireflyIII\Helpers\Collector\JournalCollectorInterface; +use FireflyIII\Helpers\Filter\NegativeAmountFilter; use FireflyIII\Http\Controllers\Controller; use FireflyIII\Http\Requests\MassDeleteJournalRequest; use FireflyIII\Http\Requests\MassEditBulkJournalRequest; use FireflyIII\Http\Requests\MassEditJournalRequest; use FireflyIII\Models\AccountType; +use FireflyIII\Models\Transaction; use FireflyIII\Models\TransactionJournal; -use FireflyIII\Models\TransactionType; use FireflyIII\Repositories\Account\AccountRepositoryInterface; use FireflyIII\Repositories\Budget\BudgetRepositoryInterface; use FireflyIII\Repositories\Journal\JournalRepositoryInterface; +use FireflyIII\Transformers\TransactionTransformer; use Illuminate\Support\Collection; use Preferences; -use Session; +use Symfony\Component\HttpFoundation\ParameterBag; use View; /** @@ -69,7 +72,7 @@ class MassController extends Controller * * @return View */ - public function delete(Collection $journals) + public function delete(Collection $journals): View { $subTitle = trans('firefly.mass_delete_journals'); @@ -88,12 +91,12 @@ class MassController extends Controller { $ids = $request->get('confirm_mass_delete'); $set = new Collection; - if (is_array($ids)) { - /** @var int $journalId */ + if (\is_array($ids)) { + /** @var string $journalId */ foreach ($ids as $journalId) { /** @var TransactionJournal $journal */ - $journal = $this->repository->find((int)$journalId); - if (null !== $journal->id && (int)$journalId === $journal->id) { + $journal = $this->repository->findNull((int)$journalId); + if (null !== $journal && (int)$journalId === $journal->id) { $set->push($journal); } } @@ -132,75 +135,31 @@ class MassController extends Controller $budgetRepository = app(BudgetRepositoryInterface::class); $budgets = $budgetRepository->getBudgets(); - // skip transactions that have multiple destinations, multiple sources or are an opening balance. - $filtered = new Collection; - $messages = []; - /** @var TransactionJournal $journal */ - foreach ($journals as $journal) { - $sources = $this->repository->getJournalSourceAccounts($journal); - $destinations = $this->repository->getJournalDestinationAccounts($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; - } - if (TransactionType::OPENING_BALANCE === $this->repository->getTransactionType($journal)) { - $messages[] = trans('firefly.cannot_edit_opening_balance'); - continue; - } - - // cannot edit reconciled transactions / journals: - if ($this->repository->isJournalReconciled($journal)) { - $messages[] = trans('firefly.cannot_edit_reconciled', ['description' => $journal->description, 'id' => $journal->id]); - continue; - } - - $filtered->push($journal); - } - - if (count($messages) > 0) { - session()->flash('info', $messages); - } - // put previous url in session $this->rememberPreviousUri('transactions.mass-edit.uri'); - // collect some useful meta data for the mass edit: - $filtered->each( - function (TransactionJournal $journal) { - $transaction = $this->repository->getFirstPosTransaction($journal); - $currency = $transaction->transactionCurrency; - $journal->amount = (float)$transaction->amount; - $sources = $this->repository->getJournalSourceAccounts($journal); - $destinations = $this->repository->getJournalDestinationAccounts($journal); - $journal->transaction_count = $journal->transactions()->count(); - $journal->currency_symbol = $currency->symbol; - $journal->transaction_type_type = $journal->transactionType->type; + // use the collector to get them. + $transformer = new TransactionTransformer(new ParameterBag); + /** @var JournalCollectorInterface $collector */ + $collector = app(JournalCollectorInterface::class); + $collector->setUser(auth()->user()); + $collector->withOpposingAccount()->withCategoryInformation()->withBudgetInformation(); + $collector->setJournals($journals); + $collector->addFilter(NegativeAmountFilter::class); + $transactions = $collector->getJournals(); - $journal->foreign_amount = (float)$transaction->foreign_amount; - $journal->foreign_currency = $transaction->foreignCurrency; + // add some filters: - if (null !== $sources->first()) { - $journal->source_account_id = $sources->first()->id; - $journal->source_account_name = $sources->first()->editname; - } - if (null !== $destinations->first()) { - $journal->destination_account_id = $destinations->first()->id; - $journal->destination_account_name = $destinations->first()->editname; - } + + // transform to array + $journals = $transactions->map( + function (Transaction $transaction) use ($transformer) { + $result = $transformer->transform($transaction); + + return $result; } ); - if (0 === $filtered->count()) { - session()->flash('error', trans('firefly.no_edit_multiple_left')); - } - - $journals = $filtered; - return view('transactions.mass.edit', compact('journals', 'subTitle', 'accounts', 'budgets')); } diff --git a/app/Http/Controllers/Transaction/SingleController.php b/app/Http/Controllers/Transaction/SingleController.php index 3ef98a6fd4..325570e0b5 100644 --- a/app/Http/Controllers/Transaction/SingleController.php +++ b/app/Http/Controllers/Transaction/SingleController.php @@ -40,7 +40,6 @@ use FireflyIII\Repositories\PiggyBank\PiggyBankRepositoryInterface; use Illuminate\Http\Request; use Log; use Preferences; -use Session; use View; /** diff --git a/app/Http/Controllers/Transaction/SplitController.php b/app/Http/Controllers/Transaction/SplitController.php index 936b5cf15b..e3e1fe1116 100644 --- a/app/Http/Controllers/Transaction/SplitController.php +++ b/app/Http/Controllers/Transaction/SplitController.php @@ -42,7 +42,6 @@ use FireflyIII\Transformers\TransactionTransformer; use Illuminate\Http\Request; use Illuminate\Support\Collection; use Preferences; -use Session; use Steam; use Symfony\Component\HttpFoundation\ParameterBag; use View; @@ -143,7 +142,7 @@ class SplitController extends Controller if ($this->isOpeningBalance($journal)) { return $this->redirectToAccount($journal); // @codeCoverageIgnore } - $data = $request->getAll(); + $data = $request->getAll(); // keep current bill: $data['bill_id'] = $journal->bill_id; @@ -221,7 +220,7 @@ class SplitController extends Controller $array['transactions'] = $this->updateWithPrevious($array['transactions'], $request->old()); // update journal amount and foreign amount: - $array['journal_amount'] = array_sum(array_column($array['transactions'], 'amount')); + $array['journal_amount'] = array_sum(array_column($array['transactions'], 'amount')); $array['journal_foreign_amount'] = array_sum(array_column($array['transactions'], 'foreign_amount')); return $array; diff --git a/app/Repositories/Journal/JournalRepository.php b/app/Repositories/Journal/JournalRepository.php index 4847148cff..69c99fa925 100644 --- a/app/Repositories/Journal/JournalRepository.php +++ b/app/Repositories/Journal/JournalRepository.php @@ -132,6 +132,20 @@ class JournalRepository implements JournalRepositoryInterface return $journal; } + /** + * Find a specific journal. + * + * @param int $journalId + * + * @deprecated + * + * @return TransactionJournal|null + */ + public function findNull(int $journalId): ?TransactionJournal + { + return $this->user->transactionJournals()->where('id', $journalId)->first(); + } + /** * @param Transaction $transaction * diff --git a/app/Repositories/Journal/JournalRepositoryInterface.php b/app/Repositories/Journal/JournalRepositoryInterface.php index a3738e4c69..86190749ed 100644 --- a/app/Repositories/Journal/JournalRepositoryInterface.php +++ b/app/Repositories/Journal/JournalRepositoryInterface.php @@ -68,11 +68,22 @@ interface JournalRepositoryInterface * Find a specific journal. * * @param int $journalId + * @deprecated * * @return TransactionJournal */ public function find(int $journalId): TransactionJournal; + /** + * Find a specific journal. + * + * @param int $journalId + * @deprecated + * + * @return TransactionJournal|null + */ + public function findNull(int $journalId): ?TransactionJournal; + /** * @param Transaction $transaction * diff --git a/app/Transformers/TransactionTransformer.php b/app/Transformers/TransactionTransformer.php index 0a12a23c2a..1956162c06 100644 --- a/app/Transformers/TransactionTransformer.php +++ b/app/Transformers/TransactionTransformer.php @@ -157,16 +157,12 @@ class TransactionTransformer extends TransformerAbstract $categoryName = null; $budgetId = null; $budgetName = null; - $categoryId = null === $transaction->transaction_category_id ? $transaction->transaction_journal_category_id - : $transaction->transaction_category_id; - $categoryName = null === $transaction->transaction_category_name ? $transaction->transaction_journal_category_name - : $transaction->transaction_category_name; + $categoryId = $transaction->transaction_category_id ?? $transaction->transaction_journal_category_id; + $categoryName = $transaction->transaction_category_name ?? $transaction->transaction_journal_category_name; if ($transaction->transaction_type_type === TransactionType::WITHDRAWAL) { - $budgetId = null === $transaction->transaction_budget_id ? $transaction->transaction_journal_budget_id - : $transaction->transaction_budget_id; - $budgetName = null === $transaction->transaction_budget_name ? $transaction->transaction_journal_budget_name - : $transaction->transaction_budget_name; + $budgetId = $transaction->transaction_budget_id ?? $transaction->transaction_journal_budget_id; + $budgetName = $transaction->transaction_budget_name ?? $transaction->transaction_journal_budget_name; } /** @var Note $dbNote */ $dbNote = $transaction->transactionJournal->notes()->first(); @@ -250,7 +246,7 @@ class TransactionTransformer extends TransformerAbstract } // expand description. - if (strlen((string)$transaction->transaction_description) > 0) { + if (\strlen((string)$transaction->transaction_description) > 0) { $data['description'] = $transaction->transaction_description . ' (' . $transaction->description . ')'; } diff --git a/resources/views/transactions/mass/edit.twig b/resources/views/transactions/mass/edit.twig index 285308adbe..1da5e566db 100644 --- a/resources/views/transactions/mass/edit.twig +++ b/resources/views/transactions/mass/edit.twig @@ -30,105 +30,101 @@ {{ trans('list.budget') }}
    - {# LINK TO EDIT FORM #} - - - - {# DESCRIPTION #} - - +
    + {# LINK TO EDIT FORM #} + + + + {# DESCRIPTION #} + + +
    + {{ journal.currency_symbol }} + + +
    + {% if journal.foreign_amount %} + {# insert foreign data #}
    - {{ journal.currency_symbol }} - - + {{ journal.foreign_currency.symbol }} + +
    - {% if journal.foreign_amount %} - {# insert foreign data #} -
    - {{ journal.foreign_currency.symbol }} - - -
    - {% endif %} -
    - {# DATE #} - - - {# SOURCE ACCOUNT ID FOR TRANSFER OR WITHDRAWAL #} - {% if journal.transaction_type_type == 'Transfer' or journal.transaction_type_type == 'Withdrawal' %} - - {% else %} - {# SOURCE ACCOUNT NAME FOR DEPOSIT #} - - {% endif %} - - {% if journal.transaction_type_type == 'Transfer' or journal.transaction_type_type == 'Deposit' %} - {# DESTINATION ACCOUNT NAME FOR TRANSFER AND DEPOSIT #} - - {% else %} - {# DESTINATION ACCOUNT NAME FOR EXPENSE #} - - {% endif %} - - - - {% if journal.transaction_type_type == 'Withdrawal' %} - - {% endif %} -
    + {# DATE #} + + + {# SOURCE ACCOUNT ID FOR TRANSFER OR WITHDRAWAL #} + {% if journal.transaction_type_type == 'Transfer' or journal.transaction_type_type == 'Withdrawal' %} + + {% else %} + {# SOURCE ACCOUNT NAME FOR DEPOSIT #} + + {% endif %} + + {% if journal.transaction_type_type == 'Transfer' or journal.transaction_type_type == 'Deposit' %} + {# DESTINATION ACCOUNT NAME FOR TRANSFER AND DEPOSIT #} + + {% else %} + {# DESTINATION ACCOUNT NAME FOR EXPENSE #} + + {% endif %} + + + + {% if journal.transaction_type_type == 'Withdrawal' %} + + {% endif %} +
    diff --git a/routes/breadcrumbs.php b/routes/breadcrumbs.php index 38440d7474..a8a498b0e2 100644 --- a/routes/breadcrumbs.php +++ b/routes/breadcrumbs.php @@ -973,18 +973,15 @@ Breadcrumbs::register( Breadcrumbs::register( 'transactions.mass.edit', function (BreadCrumbsGenerator $breadcrumbs, Collection $journals): void { - if ($journals->count() > 0) { + if (\count($journals) > 0) { $journalIds = $journals->pluck('id')->toArray(); - $what = strtolower($journals->first()->transactionType->type); + $what = strtolower($journals->first()['type']); $breadcrumbs->parent('transactions.index', $what); $breadcrumbs->push(trans('firefly.mass_edit_journals'), route('transactions.mass.edit', $journalIds)); return; } - $breadcrumbs->parent('index'); - - return; } ); diff --git a/routes/web.php b/routes/web.php index d9ce86919a..d50b243549 100755 --- a/routes/web.php +++ b/routes/web.php @@ -822,7 +822,7 @@ Route::group( Route::group( ['middleware' => 'user-full-auth', 'namespace' => 'FireflyIII\Http\Controllers\Transaction', 'prefix' => 'transactions/mass', 'as' => 'transactions.mass.'], function () { - Route::get('edit/{journalList}', ['uses' => 'MassController@edit', 'as' => 'edit']); + Route::get('edit/{simpleJournalList}', ['uses' => 'MassController@edit', 'as' => 'edit']); Route::get('delete/{journalList}', ['uses' => 'MassController@delete', 'as' => 'delete']); Route::post('update', ['uses' => 'MassController@update', 'as' => 'update']); Route::post('destroy', ['uses' => 'MassController@destroy', 'as' => 'destroy']); From 846df21764edc43e2b9cd1d521acf7266a168363 Mon Sep 17 00:00:00 2001 From: James Cole Date: Tue, 24 Apr 2018 19:26:31 +0200 Subject: [PATCH 086/117] Fix #1372 --- app/Services/Internal/Support/AccountServiceTrait.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/Services/Internal/Support/AccountServiceTrait.php b/app/Services/Internal/Support/AccountServiceTrait.php index 9e320e3034..e555407fde 100644 --- a/app/Services/Internal/Support/AccountServiceTrait.php +++ b/app/Services/Internal/Support/AccountServiceTrait.php @@ -90,7 +90,7 @@ trait AccountServiceTrait $rules = ['iban' => 'required|iban']; $validator = Validator::make($data, $rules); if ($validator->fails()) { - Log::error(sprintf('Detected invalid IBAN ("%s"). Return NULL instead.', $iban)); + Log::info(sprintf('Detected invalid IBAN ("%s"). Return NULL instead.', $iban)); return null; } From 48357d1cc971087feab618fb1143fdae138e0195 Mon Sep 17 00:00:00 2001 From: James Cole Date: Tue, 24 Apr 2018 19:48:42 +0200 Subject: [PATCH 087/117] Fix #1273 and #1272 --- .../Transaction/BulkController.php | 48 ++++++++++--------- .../Transaction/ConvertController.php | 29 ++++------- .../Transaction/MassController.php | 1 - .../Journal/JournalRepository.php | 35 +++++++++----- .../Journal/JournalRepositoryInterface.php | 1 - 5 files changed, 58 insertions(+), 56 deletions(-) diff --git a/app/Http/Controllers/Transaction/BulkController.php b/app/Http/Controllers/Transaction/BulkController.php index 72e807051c..b1dcce8f4e 100644 --- a/app/Http/Controllers/Transaction/BulkController.php +++ b/app/Http/Controllers/Transaction/BulkController.php @@ -88,39 +88,44 @@ class BulkController extends Controller /** * @param BulkEditJournalRequest $request - * @param JournalRepositoryInterface $repository * * @return mixed */ - public function update(BulkEditJournalRequest $request, JournalRepositoryInterface $repository) + public function update(BulkEditJournalRequest $request) { $journalIds = $request->get('journals'); + $journalIds = \is_array($journalIds) ? $journalIds : []; $ignoreCategory = (int)$request->get('ignore_category') === 1; $ignoreBudget = (int)$request->get('ignore_budget') === 1; $ignoreTags = (int)$request->get('ignore_tags') === 1; $count = 0; - if (\is_array($journalIds)) { - foreach ($journalIds as $journalId) { - $journal = $repository->find((int)$journalId); - $count++; - Log::debug(sprintf('Found journal #%d', $journal->id)); + foreach ($journalIds as $journalId) { + $journal = $this->repository->findNull((int)$journalId); + if (null === $journal) { + continue; + } - // update category if not told to ignore - if ($ignoreCategory === false) { - Log::debug(sprintf('Set category to %s', $request->string('category'))); + $count++; + Log::debug(sprintf('Found journal #%d', $journal->id)); - $repository->updateCategory($journal, $request->string('category')); - } - // update budget if not told to ignore (and is withdrawal) - if ($ignoreBudget === false) { - Log::debug(sprintf('Set budget to %d', $request->integer('budget_id'))); - $repository->updateBudget($journal, $request->integer('budget_id')); - } - if ($ignoreTags === false) { - Log::debug(sprintf('Set tags to %s', $request->string('budget_id'))); - $repository->updateTags($journal, ['tags' => explode(',', $request->string('tags'))]); - } + // update category if not told to ignore + if ($ignoreCategory === false) { + Log::debug(sprintf('Set category to %s', $request->string('category'))); + + $this->repository->updateCategory($journal, $request->string('category')); + } + + // update budget if not told to ignore (and is withdrawal) + if ($ignoreBudget === false) { + Log::debug(sprintf('Set budget to %d', $request->integer('budget_id'))); + $this->repository->updateBudget($journal, $request->integer('budget_id')); + } + + // update tags: + if ($ignoreTags === false) { + Log::debug(sprintf('Set tags to %s', $request->string('budget_id'))); + $this->repository->updateTags($journal, ['tags' => explode(',', $request->string('tags'))]); } } @@ -130,5 +135,4 @@ class BulkController extends Controller // redirect to previous URL: return redirect($this->getPreviousUri('transactions.bulk-edit.uri')); } - } diff --git a/app/Http/Controllers/Transaction/ConvertController.php b/app/Http/Controllers/Transaction/ConvertController.php index ed0aca2d5e..1b09ccc760 100644 --- a/app/Http/Controllers/Transaction/ConvertController.php +++ b/app/Http/Controllers/Transaction/ConvertController.php @@ -97,36 +97,23 @@ class ConvertController extends Controller $destinationAccount = $this->repository->getJournalDestinationAccounts($journal)->first(); return view( - 'transactions.convert', - compact( - 'sourceType', - 'destinationType', - 'journal', - 'positiveAmount', - 'sourceAccount', - 'destinationAccount', - 'sourceType', - 'subTitle', - 'subTitleIcon' - ) + 'transactions.convert', compact( + 'sourceType', 'destinationType', 'journal', 'positiveAmount', 'sourceAccount', 'destinationAccount', 'sourceType', 'subTitle', 'subTitleIcon' + ) ); - - // convert withdrawal to deposit requires a new source account () - // or to transfer requires } /** - * @param Request $request - * @param JournalRepositoryInterface $repository - * @param TransactionType $destinationType - * @param TransactionJournal $journal + * @param Request $request + * @param TransactionType $destinationType + * @param TransactionJournal $journal * * @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector * * @throws FireflyException * @throws FireflyException */ - public function postIndex(Request $request, JournalRepositoryInterface $repository, TransactionType $destinationType, TransactionJournal $journal) + public function postIndex(Request $request, TransactionType $destinationType, TransactionJournal $journal) { // @codeCoverageIgnoreStart if ($this->isOpeningBalance($journal)) { @@ -153,7 +140,7 @@ class ConvertController extends Controller $destination = $this->getDestinationAccount($journal, $destinationType, $data); // update the journal: - $errors = $repository->convert($journal, $destinationType, $source, $destination); + $errors = $this->repository->convert($journal, $destinationType, $source, $destination); if ($errors->count() > 0) { return redirect(route('transactions.convert.index', [strtolower($destinationType->type), $journal->id]))->withErrors($errors)->withInput(); diff --git a/app/Http/Controllers/Transaction/MassController.php b/app/Http/Controllers/Transaction/MassController.php index a99e87edbc..7b9e5d6744 100644 --- a/app/Http/Controllers/Transaction/MassController.php +++ b/app/Http/Controllers/Transaction/MassController.php @@ -27,7 +27,6 @@ use FireflyIII\Helpers\Collector\JournalCollectorInterface; use FireflyIII\Helpers\Filter\NegativeAmountFilter; use FireflyIII\Http\Controllers\Controller; use FireflyIII\Http\Requests\MassDeleteJournalRequest; -use FireflyIII\Http\Requests\MassEditBulkJournalRequest; use FireflyIII\Http\Requests\MassEditJournalRequest; use FireflyIII\Models\AccountType; use FireflyIII\Models\Transaction; diff --git a/app/Repositories/Journal/JournalRepository.php b/app/Repositories/Journal/JournalRepository.php index 69c99fa925..002f6ea03e 100644 --- a/app/Repositories/Journal/JournalRepository.php +++ b/app/Repositories/Journal/JournalRepository.php @@ -60,19 +60,30 @@ class JournalRepository implements JournalRepositoryInterface */ public function convert(TransactionJournal $journal, TransactionType $type, Account $source, Account $destination): MessageBag { - // default message bag that shows errors for everything. - $messages = new MessageBag; - $messages->add('source_account_revenue', trans('firefly.invalid_convert_selection')); - $messages->add('destination_account_asset', trans('firefly.invalid_convert_selection')); - $messages->add('destination_account_expense', trans('firefly.invalid_convert_selection')); - $messages->add('source_account_asset', trans('firefly.invalid_convert_selection')); - if ($source->id === $destination->id || null === $source->id || null === $destination->id) { + // default message bag that shows errors for everything. + $messages = new MessageBag; + $messages->add('source_account_revenue', trans('firefly.invalid_convert_selection')); + $messages->add('destination_account_asset', trans('firefly.invalid_convert_selection')); + $messages->add('destination_account_expense', trans('firefly.invalid_convert_selection')); + $messages->add('source_account_asset', trans('firefly.invalid_convert_selection')); + return $messages; } - $sourceTransaction = $journal->transactions()->where('amount', '<', 0)->first(); - $destinationTransaction = $journal->transactions()->where('amount', '>', 0)->first(); + $sourceTransaction = $journal->transactions()->where('amount', '<', 0)->first(); + $destinationTransaction = $journal->transactions()->where('amount', '>', 0)->first(); + if (null === $sourceTransaction || null === $destinationTransaction) { + // default message bag that shows errors for everything. + + $messages = new MessageBag; + $messages->add('source_account_revenue', trans('firefly.source_or_dest_invalid')); + $messages->add('destination_account_asset', trans('firefly.source_or_dest_invalid')); + $messages->add('destination_account_expense', trans('firefly.source_or_dest_invalid')); + $messages->add('source_account_asset', trans('firefly.source_or_dest_invalid')); + + return $messages; + } $sourceTransaction->account_id = $source->id; $sourceTransaction->save(); $destinationTransaction->account_id = $destination->id; @@ -83,6 +94,10 @@ class JournalRepository implements JournalRepositoryInterface // if journal is a transfer now, remove budget: if (TransactionType::TRANSFER === $type->type) { $journal->budgets()->detach(); + // also from transactions: + foreach ($journal->transactions as $transaction) { + $transaction->budgets()->detach(); + } } Preferences::mark(); @@ -137,8 +152,6 @@ class JournalRepository implements JournalRepositoryInterface * * @param int $journalId * - * @deprecated - * * @return TransactionJournal|null */ public function findNull(int $journalId): ?TransactionJournal diff --git a/app/Repositories/Journal/JournalRepositoryInterface.php b/app/Repositories/Journal/JournalRepositoryInterface.php index 86190749ed..70011c6106 100644 --- a/app/Repositories/Journal/JournalRepositoryInterface.php +++ b/app/Repositories/Journal/JournalRepositoryInterface.php @@ -78,7 +78,6 @@ interface JournalRepositoryInterface * Find a specific journal. * * @param int $journalId - * @deprecated * * @return TransactionJournal|null */ From 2e1a777811e68238326a1319b4822774a15a92a6 Mon Sep 17 00:00:00 2001 From: James Cole Date: Tue, 24 Apr 2018 19:49:54 +0200 Subject: [PATCH 088/117] Fix small deprecated function call. [skip ci] --- app/Http/Controllers/Transaction/SingleController.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/Http/Controllers/Transaction/SingleController.php b/app/Http/Controllers/Transaction/SingleController.php index 325570e0b5..4973dfedce 100644 --- a/app/Http/Controllers/Transaction/SingleController.php +++ b/app/Http/Controllers/Transaction/SingleController.php @@ -225,7 +225,7 @@ class SingleController extends Controller return $this->redirectToAccount($transactionJournal); } // @codeCoverageIgnoreEnd - $type = $transactionJournal->transactionTypeStr(); + $type = $this->repository->getTransactionType($transactionJournal); session()->flash('success', (string)trans('firefly.deleted_' . strtolower($type), ['description' => $transactionJournal->description])); $this->repository->destroy($transactionJournal); From 490c817fc11cb316b01c894def100b75a23c4e47 Mon Sep 17 00:00:00 2001 From: James Cole Date: Wed, 25 Apr 2018 16:01:51 +0200 Subject: [PATCH 089/117] Some fixes for #1378 --- app/Import/Routine/BunqRoutine.php | 3 ++- app/Services/Bunq/Request/InstallationTokenRequest.php | 10 +++++++++- resources/lang/en_US/firefly.php | 1 + 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/app/Import/Routine/BunqRoutine.php b/app/Import/Routine/BunqRoutine.php index 18098a214c..b522f4e4bf 100644 --- a/app/Import/Routine/BunqRoutine.php +++ b/app/Import/Routine/BunqRoutine.php @@ -798,6 +798,7 @@ class BunqRoutine implements RoutineInterface $mapping = $config['accounts-mapped']; $token = new SessionToken($config['session_token']); $count = 0; + $all = []; if (0 === $user->getId()) { $user = new UserCompany($config['user_company']); Log::debug(sprintf('Will try to get transactions for company #%d', $user->getId())); @@ -826,7 +827,7 @@ class BunqRoutine implements RoutineInterface 'import_id' => $importId, 'payments' => $payments, ]; - $count += count($payments); + $count += \count($payments); } Log::debug(sprintf('Total number of payments: %d', $count)); $this->addStep(); diff --git a/app/Services/Bunq/Request/InstallationTokenRequest.php b/app/Services/Bunq/Request/InstallationTokenRequest.php index b612a9aed2..d22614654a 100644 --- a/app/Services/Bunq/Request/InstallationTokenRequest.php +++ b/app/Services/Bunq/Request/InstallationTokenRequest.php @@ -22,6 +22,7 @@ declare(strict_types=1); namespace FireflyIII\Services\Bunq\Request; +use FireflyIII\Exceptions\FireflyException; use FireflyIII\Services\Bunq\Id\InstallationId; use FireflyIII\Services\Bunq\Object\ServerPublicKey; use FireflyIII\Services\Bunq\Token\InstallationToken; @@ -96,12 +97,19 @@ class InstallationTokenRequest extends BunqRequest * @param array $response * * @return InstallationId + * @throws FireflyException */ private function extractInstallationId(array $response): InstallationId { $installationId = new InstallationId; $data = $this->getKeyFromResponse('Id', $response); - $installationId->setId((int)$data['id']); + + if (!isset($data['id'])) { + Log::error('No installation token in bunq response.', $response); + throw new FireflyException('There is no installation token in the bunq response. Sorry, I cannot continue.'); + } + + $installationId->setId($data['id']); return $installationId; } diff --git a/resources/lang/en_US/firefly.php b/resources/lang/en_US/firefly.php index 7e83a1ac11..1493ce7863 100644 --- a/resources/lang/en_US/firefly.php +++ b/resources/lang/en_US/firefly.php @@ -583,6 +583,7 @@ return [ 'converted_to_Deposit' => 'The transaction has been converted to a deposit', 'converted_to_Transfer' => 'The transaction has been converted to a transfer', 'invalid_convert_selection' => 'The account you have selected is already used in this transaction or does not exist.', + 'source_or_dest_invalid' => 'Cannot find the correct transaction details. Conversion is not possible.', // create new stuff: 'create_new_withdrawal' => 'Create new withdrawal', From 71f39f55f2fc9b6d486ba1927296fdf65812372d Mon Sep 17 00:00:00 2001 From: James Cole Date: Wed, 25 Apr 2018 17:02:43 +0200 Subject: [PATCH 090/117] Push some more fixes for #1378 --- app/Import/Routine/BunqRoutine.php | 2 +- app/Services/Bunq/Object/LabelMonetaryAccount.php | 7 ++++--- app/Services/Bunq/Object/LabelUser.php | 2 +- app/Services/Bunq/Object/MonetaryAccountBank.php | 4 ++-- 4 files changed, 8 insertions(+), 7 deletions(-) diff --git a/app/Import/Routine/BunqRoutine.php b/app/Import/Routine/BunqRoutine.php index b522f4e4bf..ffc7f09df4 100644 --- a/app/Import/Routine/BunqRoutine.php +++ b/app/Import/Routine/BunqRoutine.php @@ -810,7 +810,7 @@ class BunqRoutine implements RoutineInterface $this->addStep(); $account = new MonetaryAccountBank($accountData); $importId = $account->getId(); - if (1 === $mapping[$importId]) { + if (isset($mapping[$importId])) { Log::debug(sprintf('Will grab payments for account %s', $account->getDescription())); $request = new ListPaymentRequest(); $request->setPrivateKey($this->getPrivateKey()); diff --git a/app/Services/Bunq/Object/LabelMonetaryAccount.php b/app/Services/Bunq/Object/LabelMonetaryAccount.php index 2e6198530c..7bc61a4442 100644 --- a/app/Services/Bunq/Object/LabelMonetaryAccount.php +++ b/app/Services/Bunq/Object/LabelMonetaryAccount.php @@ -24,6 +24,7 @@ declare(strict_types=1); namespace FireflyIII\Services\Bunq\Object; use FireflyIII\Exceptions\FireflyException; + /** * Class LabelMonetaryAccount */ @@ -49,15 +50,15 @@ class LabelMonetaryAccount extends BunqObject { $this->iban = $data['iban']; $this->isLight = $data['is_light']; - $this->avatar = new Avatar($data['avatar']); + $this->avatar = isset($data['avatar']) ? new Avatar($data['avatar']) : null; $this->labelUser = new LabelUser($data['label_user']); $this->country = $data['country']; } /** - * @return string + * @return string|null */ - public function getIban(): string + public function getIban(): ?string { return $this->iban; } diff --git a/app/Services/Bunq/Object/LabelUser.php b/app/Services/Bunq/Object/LabelUser.php index d7820f9eb5..a2b1f8cb39 100644 --- a/app/Services/Bunq/Object/LabelUser.php +++ b/app/Services/Bunq/Object/LabelUser.php @@ -51,7 +51,7 @@ class LabelUser extends BunqObject $this->displayName = $data['display_name']; $this->country = $data['country']; $this->publicNickName = $data['public_nick_name']; - $this->avatar = new Avatar($data['avatar']); + $this->avatar = isset($data['avatar']) ? new Avatar($data['avatar']) : null; } /** diff --git a/app/Services/Bunq/Object/MonetaryAccountBank.php b/app/Services/Bunq/Object/MonetaryAccountBank.php index 18264af185..86a0d738a7 100644 --- a/app/Services/Bunq/Object/MonetaryAccountBank.php +++ b/app/Services/Bunq/Object/MonetaryAccountBank.php @@ -93,7 +93,7 @@ class MonetaryAccountBank extends BunqObject $this->monetaryAccountProfile = new MonetaryAccountProfile($data['monetary_account_profile']); $this->setting = new MonetaryAccountSetting($data['setting']); $this->overdraftLimit = new Amount($data['overdraft_limit']); - $this->avatar = new Avatar($data['avatar']); + $this->avatar = isset($data['avatar']) ? new Avatar($data['avatar']) : null; $this->reason = $data['reason'] ?? ''; $this->reasonDescription = $data['reason_description'] ?? ''; @@ -176,7 +176,7 @@ class MonetaryAccountBank extends BunqObject 'monetary_account_profile' => $this->monetaryAccountProfile->toArray(), 'setting' => $this->setting->toArray(), 'overdraft_limit' => $this->overdraftLimit->toArray(), - 'avatar' => $this->avatar->toArray(), + 'avatar' => null === $this->avatar ? null : $this->avatar->toArray()->toArray(), 'reason' => $this->reason, 'reason_description' => $this->reasonDescription, 'alias' => [], From d2848cf569387dfbd25b1ca14ae3a61b21b56384 Mon Sep 17 00:00:00 2001 From: Paul Sohier Date: Wed, 25 Apr 2018 19:11:32 +0200 Subject: [PATCH 091/117] getIban might return null from the bunq API. Fixes #1378 as it gets imported now :) --- app/Import/Routine/BunqRoutine.php | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/app/Import/Routine/BunqRoutine.php b/app/Import/Routine/BunqRoutine.php index ffc7f09df4..9ae6e42871 100644 --- a/app/Import/Routine/BunqRoutine.php +++ b/app/Import/Routine/BunqRoutine.php @@ -320,23 +320,27 @@ class BunqRoutine implements RoutineInterface private function convertToAccount(LabelMonetaryAccount $party, string $expectedType): Account { Log::debug('in convertToAccount()'); - // find opposing party by IBAN first. - $result = $this->accountRepository->findByIbanNull($party->getIban(), [$expectedType]); - if (null !== $result) { - Log::debug(sprintf('Search for %s resulted in account %s (#%d)', $party->getIban(), $result->name, $result->id)); - return $result; - } - - // try to find asset account just in case: - if ($expectedType !== AccountType::ASSET) { - $result = $this->accountRepository->findByIbanNull($party->getIban(), [AccountType::ASSET]); + if ($party->getIban() !== null) { + // find opposing party by IBAN first. + $result = $this->accountRepository->findByIbanNull($party->getIban(), [$expectedType]); if (null !== $result) { - Log::debug(sprintf('Search for Asset "%s" resulted in account %s (#%d)', $party->getIban(), $result->name, $result->id)); + Log::debug(sprintf('Search for %s resulted in account %s (#%d)', $party->getIban(), $result->name, $result->id)); return $result; } + + // try to find asset account just in case: + if ($expectedType !== AccountType::ASSET) { + $result = $this->accountRepository->findByIbanNull($party->getIban(), [AccountType::ASSET]); + if (null !== $result) { + Log::debug(sprintf('Search for Asset "%s" resulted in account %s (#%d)', $party->getIban(), $result->name, $result->id)); + + return $result; + } + } } + // create new account: $data = [ 'user_id' => $this->job->user_id, From d5f7430723600a7144b6f2fc10e110da19a128a1 Mon Sep 17 00:00:00 2001 From: James Cole Date: Thu, 26 Apr 2018 21:00:29 +0200 Subject: [PATCH 092/117] Move and update security txt [skip ci] --- security.txt => .well-known/security.txt | 3 +++ 1 file changed, 3 insertions(+) rename security.txt => .well-known/security.txt (73%) diff --git a/security.txt b/.well-known/security.txt similarity index 73% rename from security.txt rename to .well-known/security.txt index 78f431c07d..0945cee4a9 100644 --- a/security.txt +++ b/.well-known/security.txt @@ -1,3 +1,6 @@ +# Please report security issues related to Firefly III +# to me ASAP via the email address below. + Contact: mailto:thegrumpydictator@gmail.com Encryption: https://keybase.io/jc5/pgp_keys.asc?fingerprint=90f546f13b81b67a1baa5dddc16961e655e74b5e Acknowledgements: https://github.com/firefly-iii/firefly-iii From 9026c9d6f1659dd7c69763e88fec9454347288fe Mon Sep 17 00:00:00 2001 From: James Cole Date: Thu, 26 Apr 2018 21:16:45 +0200 Subject: [PATCH 093/117] Update docker file. --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index e3730e4787..05884d9350 100644 --- a/Dockerfile +++ b/Dockerfile @@ -28,7 +28,7 @@ RUN apt-get update -y && \ RUN docker-php-ext-install -j$(nproc) curl gd intl json readline tidy zip bcmath xml mbstring pdo_sqlite pdo_mysql bz2 pdo_pgsql # Generate locales supported by Firefly III -RUN echo "de_DE.UTF-8 UTF-8\nen_US.UTF-8 UTF-8\nfr_FR.UTF-8 UTF-8\nid_ID.UTF-8 UTF-8\nnl_NL.UTF-8 UTF-8\npl_PL.UTF-8 UTF-8" > /etc/locale.gen && locale-gen +RUN echo "de_DE.UTF-8 UTF-8\nen_US.UTF-8 UTF-8\nes_ES.UTF-8 UTF-8\nfr_FR.UTF-8 UTF-8\nid_ID.UTF-8 UTF-8\nit_IT.UTF-8 UTF-8\nnl_NL.UTF-8 UTF-8\npl_PL.UTF-8 UTF-8pt_BR.UTF-8 UTF-8ru_RU.UTF-8 UTF-8\ntr_TR.UTF-8 UTF-8\n\n" > /etc/locale.gen && locale-gen # copy Apache config to correct spot. COPY ./.deploy/docker/apache2.conf /etc/apache2/apache2.conf From a9dd8eb9e7b9abc8583d5a7c847fc05df6059694 Mon Sep 17 00:00:00 2001 From: James Cole Date: Fri, 27 Apr 2018 06:26:37 +0200 Subject: [PATCH 094/117] Fix #1382 --- bootstrap/app.php | 15 +++++++++++++++ config/app.php | 12 ++++++------ config/cache.php | 2 +- config/database.php | 20 ++++++++++---------- config/logging.php | 10 +++++----- config/mail.php | 4 ++-- config/queue.php | 4 ++-- 7 files changed, 41 insertions(+), 26 deletions(-) diff --git a/bootstrap/app.php b/bootstrap/app.php index f1d4085827..1eb38a8791 100644 --- a/bootstrap/app.php +++ b/bootstrap/app.php @@ -36,6 +36,21 @@ declare(strict_types=1); bcscale(12); +/** + * @param string $key + * @param null $default + * + * @return mixed|null + */ +function envNonEmpty(string $key, $default = null) +{ + $result = env($key, $default); + if (is_string($result) && $result === '') { + $result = $default; + } + return $result; +} + $app = new Illuminate\Foundation\Application( realpath(__DIR__ . '/../') diff --git a/config/app.php b/config/app.php index 6a4a8ae47a..953ed046ee 100644 --- a/config/app.php +++ b/config/app.php @@ -23,17 +23,17 @@ declare(strict_types=1); return [ - 'name' => env('APP_NAME', 'Firefly III'), - 'env' => env('APP_ENV', 'production'), + 'name' => envNonEmpty('APP_NAME', 'Firefly III'), + 'env' => envNonEmpty('APP_ENV', 'production'), 'debug' => env('APP_DEBUG', false), - 'url' => env('APP_URL', 'http://localhost'), - 'timezone' => env('TZ', 'UTC'), + 'url' => envNonEmpty('APP_URL', 'http://localhost'), + 'timezone' => envNonEmpty('TZ', 'UTC'), 'locale' => 'en_US', 'fallback_locale' => 'en_US', 'key' => env('APP_KEY'), 'cipher' => 'AES-256-CBC', - 'log' => env('APP_LOG', 'errorlog'), - 'log_level' => env('APP_LOG_LEVEL', 'info'), + 'log' => envNonEmpty('APP_LOG', 'errorlog'), + 'log_level' => envNonEmpty('APP_LOG_LEVEL', 'info'), 'providers' => [ /* diff --git a/config/cache.php b/config/cache.php index d8ac011596..414ea33ea6 100644 --- a/config/cache.php +++ b/config/cache.php @@ -37,7 +37,7 @@ return [ | */ - 'default' => env('CACHE_DRIVER', 'file'), + 'default' => envNonEmpty('CACHE_DRIVER', 'file'), /* |-------------------------------------------------------------------------- diff --git a/config/database.php b/config/database.php index 4f7fd754f6..50c1e8ede9 100644 --- a/config/database.php +++ b/config/database.php @@ -38,19 +38,19 @@ if (!($databaseUrl === false)) { return [ - 'default' => env('DB_CONNECTION', 'mysql'), + 'default' => envNonEmpty('DB_CONNECTION', 'mysql'), 'connections' => [ 'sqlite' => [ 'driver' => 'sqlite', - 'database' => env('DB_DATABASE', storage_path('database/database.sqlite')), + 'database' => envNonEmpty('DB_DATABASE', storage_path('database/database.sqlite')), 'prefix' => '', ], 'mysql' => [ 'driver' => 'mysql', - 'host' => env('DB_HOST', '127.0.0.1'), - 'port' => env('DB_PORT', '3306'), - 'database' => env('DB_DATABASE', 'forge'), - 'username' => env('DB_USERNAME', 'forge'), + 'host' => envNonEmpty('DB_HOST', '127.0.0.1'), + 'port' => envNonEmpty('DB_PORT', '3306'), + 'database' => envNonEmpty('DB_DATABASE', 'forge'), + 'username' => envNonEmpty('DB_USERNAME', 'forge'), 'password' => env('DB_PASSWORD', ''), 'unix_socket' => env('DB_SOCKET', ''), 'charset' => 'utf8mb4', @@ -61,10 +61,10 @@ return [ ], 'pgsql' => [ 'driver' => 'pgsql', - 'host' => env('DB_HOST', $host), - 'port' => env('DB_PORT', '5432'), - 'database' => env('DB_DATABASE', $database), - 'username' => env('DB_USERNAME', $username), + 'host' => envNonEmpty('DB_HOST', $host), + 'port' => envNonEmpty('DB_PORT', '5432'), + 'database' => envNonEmpty('DB_DATABASE', $database), + 'username' => envNonEmpty('DB_USERNAME', $username), 'password' => env('DB_PASSWORD', $password), 'charset' => 'utf8', 'prefix' => '', diff --git a/config/logging.php b/config/logging.php index 78f0ab48dd..3e1dcfd1f3 100644 --- a/config/logging.php +++ b/config/logging.php @@ -34,7 +34,7 @@ return [ | */ - 'default' => env('LOG_CHANNEL', 'daily'), + 'default' => envNonEmpty('LOG_CHANNEL', 'daily'), /* |-------------------------------------------------------------------------- @@ -65,13 +65,13 @@ return [ 'daily' => [ 'driver' => 'daily', 'path' => storage_path('logs/ff3-' . PHP_SAPI . '.log'), - 'level' => env('APP_LOG_LEVEL', 'info'), + 'level' => envNonEmpty('APP_LOG_LEVEL', 'info'), 'days' => 7, ], 'dailytest' => [ 'driver' => 'daily', 'path' => storage_path('logs/test-ff3-' . PHP_SAPI . '.log'), - 'level' => env('APP_LOG_LEVEL', 'info'), + 'level' => envNonEmpty('APP_LOG_LEVEL', 'info'), 'days' => 7, ], @@ -85,12 +85,12 @@ return [ 'syslog' => [ 'driver' => 'syslog', - 'level' => env('APP_LOG_LEVEL', 'info'), + 'level' => envNonEmpty('APP_LOG_LEVEL', 'info'), ], 'errorlog' => [ 'driver' => 'errorlog', - 'level' => env('APP_LOG_LEVEL', 'info'), + 'level' => envNonEmpty('APP_LOG_LEVEL', 'info'), ], ], diff --git a/config/mail.php b/config/mail.php index fb87f15799..5a782feed8 100644 --- a/config/mail.php +++ b/config/mail.php @@ -38,7 +38,7 @@ return [ | */ - 'driver' => env('MAIL_DRIVER', 'log'), + 'driver' => envNonEmpty('MAIL_DRIVER', 'log'), /* |-------------------------------------------------------------------------- @@ -76,7 +76,7 @@ return [ | used globally for all e-mails that are sent by your application. | */ - 'from' => ['address' => env('MAIL_FROM', 'changeme@example.com'), 'name' => 'Firefly III Mailer'], + 'from' => ['address' => envNonEmpty('MAIL_FROM', 'changeme@example.com'), 'name' => 'Firefly III Mailer'], /* diff --git a/config/queue.php b/config/queue.php index a3d2a3e528..eddc6dae49 100644 --- a/config/queue.php +++ b/config/queue.php @@ -37,7 +37,7 @@ return [ | */ - 'default' => env('QUEUE_DRIVER', 'sync'), + 'default' => envNonEmpty('QUEUE_DRIVER', 'sync'), /* |-------------------------------------------------------------------------- @@ -100,7 +100,7 @@ return [ */ 'failed' => [ - 'database' => env('DB_CONNECTION', 'mysql'), + 'database' => envNonEmpty('DB_CONNECTION', 'mysql'), 'table' => 'failed_jobs', ], From 9a0c0f6d2150fc45845e8fb5ce3c572f46f74229 Mon Sep 17 00:00:00 2001 From: James Cole Date: Fri, 27 Apr 2018 06:50:41 +0200 Subject: [PATCH 095/117] Fix #1383 --- app/Console/Commands/UpgradeDatabase.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/Console/Commands/UpgradeDatabase.php b/app/Console/Commands/UpgradeDatabase.php index 7115bb3819..9b5459523e 100644 --- a/app/Console/Commands/UpgradeDatabase.php +++ b/app/Console/Commands/UpgradeDatabase.php @@ -152,7 +152,7 @@ class UpgradeDatabase extends Command RuleTrigger::create( [ 'rule_id' => $rule->id, - 'trigger_type' => 'description_is', + 'trigger_type' => 'description_contains', 'trigger_value' => $match, 'active' => 1, 'stop_processing' => 0, From 246cb3683602e4f68f402af121f286bd8f9ff1dc Mon Sep 17 00:00:00 2001 From: James Cole Date: Fri, 27 Apr 2018 07:01:03 +0200 Subject: [PATCH 096/117] Expand support for trusted proxies configuration. --- app/Http/Middleware/TrustProxies.php | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/app/Http/Middleware/TrustProxies.php b/app/Http/Middleware/TrustProxies.php index 7fbac67e3c..6dc4ee301b 100644 --- a/app/Http/Middleware/TrustProxies.php +++ b/app/Http/Middleware/TrustProxies.php @@ -50,8 +50,14 @@ class TrustProxies extends Middleware public function __construct(Repository $config) { $trustedProxies = env('TRUSTED_PROXIES', null); - if (false !== $trustedProxies && null !== $trustedProxies && strlen($trustedProxies) > 0) { - $this->proxies = (string)$trustedProxies; + if (false !== $trustedProxies && null !== $trustedProxies && \strlen($trustedProxies) > 0) { + if ($trustedProxies === '*' || $trustedProxies === '**') { + $this->proxies = (string)$trustedProxies; + + } + if ($trustedProxies !== '*' && $trustedProxies !== '**') { + $this->proxies = explode(',', $trustedProxies); + } } parent::__construct($config); From 28bcff99f66755811a5e61626ac9ec1281ff126f Mon Sep 17 00:00:00 2001 From: James Cole Date: Fri, 27 Apr 2018 08:50:49 +0200 Subject: [PATCH 097/117] Add config for stale bot. --- .github/stale.yml | 55 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) create mode 100644 .github/stale.yml diff --git a/.github/stale.yml b/.github/stale.yml new file mode 100644 index 0000000000..f9e5be7b89 --- /dev/null +++ b/.github/stale.yml @@ -0,0 +1,55 @@ +# Configuration for probot-stale - https://github.com/probot/stale + +# Number of days of inactivity before an Issue or Pull Request becomes stale +daysUntilStale: 30 + +# Number of days of inactivity before a stale Issue or Pull Request is closed. +# Set to false to disable. If disabled, issues still need to be closed manually, but will remain marked as stale. +daysUntilClose: 7 + +# Issues or Pull Requests with these labels will never be considered stale. Set to `[]` to disable +# - "[Status] Maybe Later" +exemptLabels: + - enhancement + - feature + +# Set to true to ignore issues in a project (defaults to false) +exemptProjects: false + +# Set to true to ignore issues in a milestone (defaults to false) +exemptMilestones: false + +# Label to use when marking as stale +staleLabel: stale + +# Comment to post when marking as stale. Set to `false` to disable +markComment: > + This issue has been automatically marked as stale because it has not had + recent activity. It will be closed if no further activity occurs. Thank you + for your contributions. + +# Comment to post when removing the stale label. +# unmarkComment: > +# Your comment here. + +# Comment to post when closing a stale Issue or Pull Request. +# closeComment: > +# Your comment here. + +# Limit the number of actions per hour, from 1-30. Default is 30 +limitPerRun: 30 + +# Limit to only `issues` or `pulls` +# only: issues + +# Optionally, specify configuration settings that are specific to just 'issues' or 'pulls': +# pulls: +# daysUntilStale: 30 +# markComment: > +# This pull request has been automatically marked as stale because it has not had +# recent activity. It will be closed if no further activity occurs. Thank you +# for your contributions. + +# issues: +# exemptLabels: +# - confirmed \ No newline at end of file From bb251328655617840c79e65693b2a1fd03929e6d Mon Sep 17 00:00:00 2001 From: James Cole Date: Fri, 27 Apr 2018 11:29:09 +0200 Subject: [PATCH 098/117] Fix tests --- app/Api/V1/Requests/BillRequest.php | 1 - app/Http/Controllers/RuleController.php | 4 +- .../Transaction/MassController.php | 7 +-- .../Internal/Update/AccountUpdateService.php | 2 +- app/Transformers/AccountTransformer.php | 2 +- bootstrap/app.php | 30 ++++++------ database/factories/ModelFactory.php | 4 +- phpunit.coverage.specific.xml | 3 ++ phpunit.coverage.xml | 3 ++ phpunit.xml | 3 ++ .../Api/V1/Controllers/BillControllerTest.php | 4 +- .../V1/Controllers/CurrencyControllerTest.php | 14 ++++-- .../Controllers/TransactionControllerTest.php | 4 +- .../Controllers/AccountControllerTest.php | 2 + .../Controllers/PiggyBankControllerTest.php | 6 ++- .../Transaction/BulkControllerTest.php | 49 +++---------------- .../Transaction/MassControllerTest.php | 49 +++---------------- .../Transaction/SingleControllerTest.php | 2 + .../Triggers/HasAnyCategoryTest.php | 2 + .../Triggers/ToAccountEndsTest.php | 8 ++- 20 files changed, 81 insertions(+), 118 deletions(-) diff --git a/app/Api/V1/Requests/BillRequest.php b/app/Api/V1/Requests/BillRequest.php index 64f64127d6..f2e13aaf9f 100644 --- a/app/Api/V1/Requests/BillRequest.php +++ b/app/Api/V1/Requests/BillRequest.php @@ -87,7 +87,6 @@ class BillRequest extends Request case 'PATCH': $bill = $this->route()->parameter('bill'); $rules['name'] .= ',' . $bill->id; - $rules['match'] .= ',' . $bill->id; break; } diff --git a/app/Http/Controllers/RuleController.php b/app/Http/Controllers/RuleController.php index 05cafcd305..03bffefe91 100644 --- a/app/Http/Controllers/RuleController.php +++ b/app/Http/Controllers/RuleController.php @@ -303,7 +303,7 @@ class RuleController extends Controller { $ids = $request->get('actions'); if (\is_array($ids)) { - $this->ruleGroupRepos->reorderRuleActions($rule, $ids); + $this->ruleRepos->reorderRuleActions($rule, $ids); } return response()->json('true'); @@ -320,7 +320,7 @@ class RuleController extends Controller { $ids = $request->get('triggers'); if (\is_array($ids)) { - $this->ruleGroupRepos->reorderRuleTriggers($rule, $ids); + $this->ruleRepos->reorderRuleTriggers($rule, $ids); } return response()->json('true'); diff --git a/app/Http/Controllers/Transaction/MassController.php b/app/Http/Controllers/Transaction/MassController.php index 7b9e5d6744..ede2e9b6ba 100644 --- a/app/Http/Controllers/Transaction/MassController.php +++ b/app/Http/Controllers/Transaction/MassController.php @@ -39,6 +39,7 @@ use Illuminate\Support\Collection; use Preferences; use Symfony\Component\HttpFoundation\ParameterBag; use View; +use Illuminate\View\View as IlluminateView; /** * Class MassController. @@ -69,9 +70,9 @@ class MassController extends Controller /** * @param Collection $journals * - * @return View + * @return IlluminateView */ - public function delete(Collection $journals): View + public function delete(Collection $journals): IlluminateView { $subTitle = trans('firefly.mass_delete_journals'); @@ -121,7 +122,7 @@ class MassController extends Controller * * @return View */ - public function edit(Collection $journals) + public function edit(Collection $journals): IlluminateView { $subTitle = trans('firefly.mass_edit_journals'); diff --git a/app/Services/Internal/Update/AccountUpdateService.php b/app/Services/Internal/Update/AccountUpdateService.php index e286d702d1..b66110e0d3 100644 --- a/app/Services/Internal/Update/AccountUpdateService.php +++ b/app/Services/Internal/Update/AccountUpdateService.php @@ -51,7 +51,7 @@ class AccountUpdateService $account->iban = $data['iban']; $account->save(); - if($data['currency_id'] === 0) { + if(isset($data['currency_id']) && $data['currency_id'] === 0) { unset($data['currency_id']); } diff --git a/app/Transformers/AccountTransformer.php b/app/Transformers/AccountTransformer.php index c238a28dd8..099398fd8c 100644 --- a/app/Transformers/AccountTransformer.php +++ b/app/Transformers/AccountTransformer.php @@ -153,7 +153,7 @@ class AccountTransformer extends TransformerAbstract } $currencyId = (int)$this->repository->getMetaValue($account, 'currency_id'); $currencyCode = null; - $currencySymbol = null; + $currencySymbol = 'x'; $decimalPlaces = 2; if ($currencyId > 0) { $currency = TransactionCurrency::find($currencyId); diff --git a/bootstrap/app.php b/bootstrap/app.php index 1eb38a8791..0abe08a8d8 100644 --- a/bootstrap/app.php +++ b/bootstrap/app.php @@ -36,21 +36,23 @@ declare(strict_types=1); bcscale(12); -/** - * @param string $key - * @param null $default - * - * @return mixed|null - */ -function envNonEmpty(string $key, $default = null) -{ - $result = env($key, $default); - if (is_string($result) && $result === '') { - $result = $default; - } - return $result; -} +if (!function_exists('envNonEmpty')) { + /** + * @param string $key + * @param null $default + * + * @return mixed|null + */ + function envNonEmpty(string $key, $default = null) + { + $result = env($key, $default); + if (is_string($result) && $result === '') { + $result = $default; + } + return $result; + } +} $app = new Illuminate\Foundation\Application( realpath(__DIR__ . '/../') diff --git a/database/factories/ModelFactory.php b/database/factories/ModelFactory.php index e37bd22338..04a90e6a2a 100644 --- a/database/factories/ModelFactory.php +++ b/database/factories/ModelFactory.php @@ -152,10 +152,12 @@ $factory->define( function (Faker\Generator $faker) { return [ 'id' => $faker->unique()->numberBetween(100, 10000), + 'created_at' => new Carbon, + 'updated_at' => new Carbon, 'account_id' => $faker->numberBetween(1, 10), 'name' => $faker->words(3, true), 'target_amount' => '1000.00', - 'startdate' => '2017-01-01', + 'startdate' => new Carbon('2017-01-01'), 'order' => 1, 'active' => 1, 'encrypted' => 0, diff --git a/phpunit.coverage.specific.xml b/phpunit.coverage.specific.xml index 9a25379977..da49035fc3 100644 --- a/phpunit.coverage.specific.xml +++ b/phpunit.coverage.specific.xml @@ -8,6 +8,9 @@ convertWarningsToExceptions="true" processIsolation="false" stopOnFailure="true"> + + + ./tests/Feature diff --git a/phpunit.coverage.xml b/phpunit.coverage.xml index 874f28e793..cfca4f71ee 100644 --- a/phpunit.coverage.xml +++ b/phpunit.coverage.xml @@ -8,6 +8,9 @@ convertWarningsToExceptions="true" processIsolation="false" stopOnFailure="true"> + + + ./tests/Feature diff --git a/phpunit.xml b/phpunit.xml index 1b5e9f6f27..8126efc85c 100644 --- a/phpunit.xml +++ b/phpunit.xml @@ -8,6 +8,9 @@ convertWarningsToExceptions="true" processIsolation="false" stopOnFailure="true"> + + + ./tests/Feature diff --git a/tests/Api/V1/Controllers/BillControllerTest.php b/tests/Api/V1/Controllers/BillControllerTest.php index 22a4b6cdf0..29c61739db 100644 --- a/tests/Api/V1/Controllers/BillControllerTest.php +++ b/tests/Api/V1/Controllers/BillControllerTest.php @@ -144,6 +144,7 @@ class BillControllerTest extends TestCase 'amount_min' => '66.34', 'amount_max' => '45.67', 'date' => '2018-01-01', + 'currency_id' => 1, 'repeat_freq' => 'monthly', 'skip' => 0, 'automatch' => 1, @@ -192,6 +193,7 @@ class BillControllerTest extends TestCase 'skip' => 0, 'automatch' => 1, 'active' => 1, + 'currency_id' => 1, ]; @@ -230,7 +232,7 @@ class BillControllerTest extends TestCase 'skip' => 0, 'automatch' => 1, 'active' => 1, - + 'currency_id' => 1, ]; // test API diff --git a/tests/Api/V1/Controllers/CurrencyControllerTest.php b/tests/Api/V1/Controllers/CurrencyControllerTest.php index 70c18e13a6..551a598d35 100644 --- a/tests/Api/V1/Controllers/CurrencyControllerTest.php +++ b/tests/Api/V1/Controllers/CurrencyControllerTest.php @@ -97,9 +97,17 @@ class CurrencyControllerTest extends TestCase $response = $this->get('/api/v1/currencies'); $response->assertStatus(200); $response->assertJson(['data' => [],]); - $response->assertJson( - ['meta' => ['pagination' => ['total' => $collection->count(), 'count' => $collection->count(), 'per_page' => 50, 'current_page' => 1, - 'total_pages' => 1]],] + $response->assertJson([ + 'meta' => [ + 'pagination' => [ + 'total' => $collection->count(), + 'count' => $collection->count(), + 'per_page' => 100, + 'current_page' => 1, + 'total_pages' => 1, + ], + ], + ] ); $response->assertJson( ['links' => ['self' => true, 'first' => true, 'last' => true,],] diff --git a/tests/Api/V1/Controllers/TransactionControllerTest.php b/tests/Api/V1/Controllers/TransactionControllerTest.php index f03ccf2fb1..8ecf77beb5 100644 --- a/tests/Api/V1/Controllers/TransactionControllerTest.php +++ b/tests/Api/V1/Controllers/TransactionControllerTest.php @@ -341,7 +341,7 @@ class TransactionControllerTest extends TestCase $journalRepos->shouldReceive('setUser')->once(); $accountRepos->shouldReceive('setUser'); $accountRepos->shouldReceive('getAccountsById')->andReturn(new Collection); - $accountRepos->shouldReceive('findByNameNull')->andReturn(null); + $accountRepos->shouldReceive('findByName')->andReturn(null); $data = [ 'description' => 'Some transaction #' . random_int(1, 1000), @@ -1661,7 +1661,7 @@ class TransactionControllerTest extends TestCase $journalRepos->shouldReceive('setUser')->once(); $accountRepos->shouldReceive('setUser'); $accountRepos->shouldReceive('getAccountsById')->andReturn(new Collection); - $accountRepos->shouldReceive('findByNameNull')->andReturn($account); + $accountRepos->shouldReceive('findByName')->andReturn($account); $journalRepos->shouldReceive('store')->andReturn($journal)->once(); diff --git a/tests/Feature/Controllers/AccountControllerTest.php b/tests/Feature/Controllers/AccountControllerTest.php index 4070de576b..c5784c680f 100644 --- a/tests/Feature/Controllers/AccountControllerTest.php +++ b/tests/Feature/Controllers/AccountControllerTest.php @@ -182,6 +182,8 @@ class AccountControllerTest extends TestCase Steam::shouldReceive('balancesByAccounts')->andReturn([$account->id => '100']); Steam::shouldReceive('getLastActivities')->andReturn([]); + $repository->shouldReceive('getMetaValue')->withArgs([Mockery::any(),'accountNumber'])->andReturn('123'); + $this->be($this->user()); $this->changeDateRange($this->user(), $range); $response = $this->get(route('accounts.index', ['asset'])); diff --git a/tests/Feature/Controllers/PiggyBankControllerTest.php b/tests/Feature/Controllers/PiggyBankControllerTest.php index bd78799224..81891d6d98 100644 --- a/tests/Feature/Controllers/PiggyBankControllerTest.php +++ b/tests/Feature/Controllers/PiggyBankControllerTest.php @@ -66,6 +66,8 @@ class PiggyBankControllerTest extends TestCase $journalRepos = $this->mock(JournalRepositoryInterface::class); $journalRepos->shouldReceive('first')->once()->andReturn(new TransactionJournal); $piggyRepos->shouldReceive('getCurrentAmount')->andReturn('0'); + $piggyRepos->shouldReceive('leftOnAccount')->andReturn('0'); + $this->be($this->user()); $response = $this->get(route('piggy-banks.add', [1])); $response->assertStatus(200); @@ -81,6 +83,7 @@ class PiggyBankControllerTest extends TestCase $journalRepos = $this->mock(JournalRepositoryInterface::class); $journalRepos->shouldReceive('first')->once()->andReturn(new TransactionJournal); $piggyRepos->shouldReceive('getCurrentAmount')->andReturn('0'); + $piggyRepos->shouldReceive('leftOnAccount')->andReturn('0'); $this->be($this->user()); $response = $this->get(route('piggy-banks.add-money-mobile', [1])); @@ -200,8 +203,9 @@ class PiggyBankControllerTest extends TestCase $journalRepos->shouldReceive('first')->once()->andReturn(new TransactionJournal); $repository->shouldReceive('getPiggyBanks')->andReturn(new Collection([$one, $two])); $repository->shouldReceive('getCurrentAmount')->andReturn('10'); + $repository->shouldReceive('setUser'); - Steam::shouldReceive('balanceIgnoreVirtual')->twice()->andReturn('1'); + Steam::shouldReceive('balance')->twice()->andReturn('1'); $this->be($this->user()); $response = $this->get(route('piggy-banks.index')); diff --git a/tests/Feature/Controllers/Transaction/BulkControllerTest.php b/tests/Feature/Controllers/Transaction/BulkControllerTest.php index 056d284552..009e0f8946 100644 --- a/tests/Feature/Controllers/Transaction/BulkControllerTest.php +++ b/tests/Feature/Controllers/Transaction/BulkControllerTest.php @@ -86,16 +86,16 @@ class BulkControllerTest extends TestCase $budgetRepos->shouldReceive('getActiveBudgets')->andReturn(new Collection); $journalRepos->shouldReceive('first')->andReturn(new TransactionJournal); $journalRepos->shouldReceive('getJournalSourceAccounts') - ->andReturn(new Collection([1, 2, 3]), new Collection, new Collection, new Collection); + ->andReturn(new Collection([1, 2, 3]), new Collection, new Collection, new Collection, new Collection([1])); $journalRepos->shouldReceive('getJournalDestinationAccounts') - ->andReturn(new Collection, new Collection([1, 2, 3]), new Collection, new Collection); + ->andReturn(new Collection, new Collection([1, 2, 3]), new Collection, new Collection, new Collection([1])); $journalRepos->shouldReceive('getTransactionType') - ->andReturn('Withdrawal', 'Opening balance'); + ->andReturn('Withdrawal', 'Opening balance', 'Withdrawal', 'Withdrawal', 'Withdrawal'); $journalRepos->shouldReceive('isJournalReconciled') - ->andReturn(true, false); + ->andReturn(true, false, false, false, false); // default transactions - $collection = $this->user()->transactionJournals()->take(4)->get(); + $collection = $this->user()->transactionJournals()->take(5)->get(); $allIds = $collection->pluck('id')->toArray(); $route = route('transactions.bulk.edit', implode(',', $allIds)); $this->be($this->user()); @@ -110,43 +110,6 @@ class BulkControllerTest extends TestCase $response->assertSee('multiple destination accounts'); } - /** - * @covers \FireflyIII\Http\Controllers\Transaction\BulkController::edit - */ - public function testEditMultipleNothingLeft() - { - // mock stuff: - $journalRepos = $this->mock(JournalRepositoryInterface::class); - $budgetRepos = $this->mock(BudgetRepositoryInterface::class); - $budgetRepos->shouldReceive('getActiveBudgets')->andReturn(new Collection); - $journalRepos->shouldReceive('first')->andReturn(new TransactionJournal); - $journalRepos->shouldReceive('getJournalSourceAccounts') - ->andReturn(new Collection([1, 2, 3]), new Collection, new Collection, new Collection); - $journalRepos->shouldReceive('getJournalDestinationAccounts') - ->andReturn(new Collection, new Collection([1, 2, 3]), new Collection, new Collection); - $journalRepos->shouldReceive('getTransactionType') - ->andReturn('Withdrawal', 'Opening balance'); - $journalRepos->shouldReceive('isJournalReconciled') - ->andReturn(true, true); - - - // default transactions - $collection = $this->user()->transactionJournals()->take(4)->get(); - $allIds = $collection->pluck('id')->toArray(); - $route = route('transactions.bulk.edit', implode(',', $allIds)); - $this->be($this->user()); - $response = $this->get($route); - $response->assertStatus(200); - $response->assertSee('Bulk edit a number of transactions'); - $response->assertSessionHas('info'); - // has bread crumb - $response->assertSee('