Compare commits

..

114 Commits
5.5.2 ... 5.5.7

Author SHA1 Message Date
James Cole
b47614c965 Merge branch 'release/5.5.7' into main 2021-04-12 06:30:44 +02:00
James Cole
9af458df49 Updates for new release. 2021-04-12 06:30:12 +02:00
James Cole
a67e2b597d Fix #4646 2021-04-12 06:16:00 +02:00
James Cole
3c36eed461 Rebuild frontend. 2021-04-11 07:43:07 +02:00
James Cole
5a7c3bd716 Rebuild v1 2021-04-11 07:27:25 +02:00
James Cole
43476167d8 Remove lots of debug comments. 2021-04-11 07:26:52 +02:00
James Cole
d357eaeb51 Update meta files for new release. 2021-04-11 07:26:37 +02:00
James Cole
2e118c5f22 Fix #4635 2021-04-11 06:49:46 +02:00
James Cole
8e95530ca8 Merge branch 'develop' of github.com:firefly-iii/firefly-iii into develop 2021-04-10 17:56:30 +02:00
James Cole
a04a6845f7 Merge pull request #4627 from devfaz/add_bill_nobill
added has_no_bill and has_any_bill search parameters
2021-04-10 12:01:43 +02:00
Fabian Zimmermann
185e9b66d6 added has_no_bill and has_any_bill search parameters 2021-04-10 10:59:59 +02:00
James Cole
93a7c51dd1 Update meta files 2021-04-10 08:01:55 +02:00
James Cole
f9ac40a811 Improve layout of v2 auth forms 2021-04-10 06:36:28 +02:00
James Cole
b0027acf34 Make sure that migrations work on old MySQL servers. 2021-04-10 06:36:09 +02:00
James Cole
f5e5854479 Rebuild frontend 2021-04-09 19:35:03 +02:00
James Cole
95d72d065b Fix #4628 2021-04-09 16:02:50 +02:00
James Cole
56b2fa69bc Fix for #4625 2021-04-09 09:02:00 +02:00
James Cole
e614427925 Fix some submit issues. 2021-04-09 07:03:19 +02:00
James Cole
34dc1f9f53 Merge branch 'release/5.5.6' into main 2021-04-09 06:20:39 +02:00
James Cole
94d9b78a33 Merge tag '5.5.6' into develop
5.5.6
2021-04-09 06:20:39 +02:00
James Cole
b9d949d259 Changelog and version. 2021-04-09 06:20:10 +02:00
James Cole
3376e1e663 Fix issue in date format. 2021-04-09 06:19:43 +02:00
James Cole
ea98c2631f Merge branch 'release/5.5.5' into main 2021-04-09 06:07:05 +02:00
James Cole
50b9fe649d Merge tag '5.5.5' into develop
5.5.5
2021-04-09 06:07:05 +02:00
James Cole
56054531a3 Jump to 5.5.5 2021-04-09 06:06:41 +02:00
James Cole
1912e46113 Remove strict CSP header for #4622 2021-04-09 06:05:27 +02:00
James Cole
075f951cfe Merge tag '5.5.4' into develop
5.5.4
2021-04-09 03:06:18 +02:00
James Cole
26aad765ae Merge branch 'release/5.5.4' into main 2021-04-09 03:06:16 +02:00
James Cole
73ba78d46d Update libraries for new release. 2021-04-09 03:05:37 +02:00
James Cole
0d5dd40134 Updated changelog. 2021-04-09 02:59:23 +02:00
James Cole
f0d84ad142 Update readme. 2021-04-09 02:55:57 +02:00
James Cole
0b4ebf644d Rebuild frontend 2021-04-09 02:07:34 +02:00
James Cole
5b60db120f Submit was broken. 2021-04-08 17:49:25 +02:00
James Cole
f2073a4494 Fix various issues in forms. 2021-04-08 17:41:19 +02:00
James Cole
3e12d26afd Disable almost all things. 2021-04-08 16:47:16 +02:00
James Cole
e458208966 Rebuild frontend 2021-04-08 16:09:09 +02:00
James Cole
e28a77dc87 Add nonce to build. 2021-04-08 12:30:21 +02:00
James Cole
a709596ccb Add headers. 2021-04-08 12:27:54 +02:00
James Cole
849c7dfe02 Strict headers and CSS nonce 2021-04-08 12:10:04 +02:00
James Cole
e580093a34 Weird headers. 2021-04-08 12:05:08 +02:00
James Cole
4fa7a5c1bc Update headers 2021-04-08 11:58:21 +02:00
James Cole
d668007fee Remove style thing 2021-04-08 11:55:10 +02:00
James Cole
6cbccf3be6 Small change in headers 2021-04-08 11:50:59 +02:00
James Cole
9cd75dda1a Link to issue. 2021-04-08 11:34:24 +02:00
James Cole
56dff7ea67 Rebuild new layout. 2021-04-08 11:21:20 +02:00
James Cole
6160f99e92 Update transactions. 2021-04-08 10:23:35 +02:00
James Cole
115639a004 Clean up some code. 2021-04-08 10:13:35 +02:00
James Cole
a0c98c7d9f Update packages. 2021-04-08 09:54:05 +02:00
James Cole
7842700bf1 Do not report specific error. 2021-04-08 06:50:00 +02:00
James Cole
4ecda4d4e0 Add some special headers. 2021-04-07 20:47:40 +02:00
James Cole
c76d140d0b Allow a new config var 2021-04-07 18:24:06 +02:00
James Cole
4f42eb1796 Fix nullpointers. 2021-04-07 14:18:43 +02:00
James Cole
c67b10e38d Fix nullpointer. 2021-04-07 14:17:03 +02:00
James Cole
614ceabd45 Fix #4593 2021-04-07 11:35:53 +02:00
James Cole
a94b2e8806 Extra if 2021-04-07 10:52:38 +02:00
James Cole
732616984b Fix nullpointer. 2021-04-07 09:32:12 +02:00
James Cole
eddf0c1200 Various code cleanup. 2021-04-07 07:53:05 +02:00
James Cole
49013264d5 Various code cleanup. 2021-04-07 07:32:54 +02:00
James Cole
f12744ad8c Various code cleanup. 2021-04-07 07:28:43 +02:00
James Cole
4ddcb0c965 Do not report on OAuth exceptions. 2021-04-07 05:56:50 +02:00
James Cole
0846d4898f Various code cleanup. 2021-04-07 05:55:51 +02:00
James Cole
cb746200fa Various code cleanup. 2021-04-06 18:48:02 +02:00
James Cole
fe06a1f7a0 Various code cleanup. 2021-04-06 18:36:37 +02:00
James Cole
9c1cee738d Update translations. 2021-04-06 17:12:58 +02:00
James Cole
7cc778673a Various code cleanup. 2021-04-06 17:12:31 +02:00
James Cole
38d0f0427f Various code cleanup. 2021-04-06 17:00:16 +02:00
James Cole
8572280b7b Update CI scripts. 2021-04-06 17:00:00 +02:00
James Cole
69b1769f22 Refactor old methods. 2021-04-06 13:30:09 +02:00
James Cole
5ceef2e9c3 Various code cleanup. 2021-04-06 08:51:27 +02:00
James Cole
d32446b171 Various code cleanup. 2021-04-05 22:12:57 +02:00
James Cole
d8ca39ffea Code for #4607 2021-04-05 22:12:11 +02:00
James Cole
d47bddde62 Change code for #4607 2021-04-05 21:53:28 +02:00
James Cole
e4802ec958 Clean up some code. 2021-04-05 21:52:55 +02:00
James Cole
6d855e119d Update frontend. 2021-04-05 14:18:49 +02:00
James Cole
7ab81e493a Delete accounts. 2021-04-05 12:49:02 +02:00
James Cole
fa0397e431 Fix #4603 2021-04-05 12:42:34 +02:00
James Cole
aba3b361be Update composer. 2021-04-05 12:42:20 +02:00
James Cole
1cf188ee08 Add some if-statements to the migrations. 2021-04-05 10:56:56 +02:00
James Cole
f5983f08fd Rename parameter 2021-04-05 10:56:41 +02:00
James Cole
b812c2e09f Simplify account creation. 2021-04-05 10:56:08 +02:00
James Cole
d7466efbe1 Merge pull request #4602 from firefly-iii/dependabot/composer/develop/predis/predis-1.1.7
Bump predis/predis from 1.1.6 to 1.1.7
2021-04-05 07:19:25 +02:00
dependabot[bot]
dff30af9f2 Bump predis/predis from 1.1.6 to 1.1.7
Bumps [predis/predis](https://github.com/predis/predis) from 1.1.6 to 1.1.7.
- [Release notes](https://github.com/predis/predis/releases)
- [Changelog](https://github.com/predis/predis/blob/v1.1.7/CHANGELOG.md)
- [Commits](https://github.com/predis/predis/compare/v1.1.6...v1.1.7)

Signed-off-by: dependabot[bot] <support@github.com>
2021-04-05 05:06:58 +00:00
James Cole
25dcb73e27 Fix #4600 2021-04-05 06:14:13 +02:00
James Cole
63ed3d09d5 Increase digits in bcscale. 2021-04-04 18:01:16 +02:00
James Cole
caf1e6010b Add browser TZ to debug page. 2021-04-04 17:57:46 +02:00
James Cole
2d97408c1f Move debug view so it can be made universal. 2021-04-04 17:54:11 +02:00
James Cole
01c0d76c5a Add info about reset. 2021-04-04 16:05:35 +02:00
James Cole
7c7032d951 Add info about reset. 2021-04-04 16:04:39 +02:00
James Cole
6e722f5833 Ignore 404's. 2021-04-04 15:53:17 +02:00
James Cole
d3502c56d3 Fix #4593 2021-04-04 12:48:44 +02:00
James Cole
1b8eb3cd68 Move some views. 2021-04-04 08:43:33 +02:00
James Cole
bc7bd84221 Add missing library 2021-04-04 08:33:10 +02:00
James Cole
85b22341a4 Various updates. 2021-04-04 08:31:15 +02:00
James Cole
f8c725e5b2 Merge branch 'feature/api-bulk-transaction-move' into develop 2021-04-04 07:28:54 +02:00
James Cole
e6344e4f51 Update changelog. 2021-04-04 07:28:35 +02:00
James Cole
8eac10bf89 Simplify routine. 2021-04-04 07:25:52 +02:00
James Cole
c1da0eeced Update chart to include time. 2021-04-04 07:25:42 +02:00
James Cole
0a6d5b1766 Fix error views. 2021-04-03 20:51:19 +02:00
James Cole
4035ac09ce Clean up error display. 2021-04-03 20:46:37 +02:00
James Cole
f81a7cfac0 Merge tag '5.5.3' into develop
5.5.3
2021-04-03 18:50:37 +02:00
James Cole
2b086879cc Merge branch 'release/5.5.3' into main 2021-04-03 18:50:36 +02:00
James Cole
a3091f7509 Final code for 5.3.3 2021-04-03 18:48:21 +02:00
James Cole
70a6ac0038 Make it easier to login for demo users. 2021-04-03 14:03:54 +02:00
James Cole
468a53d587 Add API route to move transactions from one account to another. 2021-04-03 13:56:45 +02:00
James Cole
51f3b17ad2 Clean up handler. 2021-04-03 13:19:11 +02:00
James Cole
a864d3bd56 Rebuild frontend 2021-04-03 12:52:50 +02:00
James Cole
a4d5aa0d10 Do not report on authentication exceptions. 2021-04-03 12:46:50 +02:00
James Cole
aff5ac2c0a Update changelog and version. 2021-04-03 12:39:01 +02:00
James Cole
effe92a05c Make sure the email error mails everything. 2021-04-03 12:32:29 +02:00
James Cole
a4ca6dfd38 Update email message paths for #4586 2021-04-03 12:30:34 +02:00
James Cole
e6012e1ca2 Fix email templates and handler for #4586 2021-04-03 12:25:35 +02:00
James Cole
472497cafd Fix #4586 2021-04-03 12:16:29 +02:00
James Cole
34f4b16a63 Rebuild frontend. 2021-04-03 10:40:31 +02:00
James Cole
7f55a870d9 Merge tag '5.5.2' into develop
5.5.2
2021-04-03 07:40:01 +02:00
711 changed files with 8163 additions and 5168 deletions

View File

@@ -10,6 +10,19 @@ parameters:
- '#is neither abstract nor final#'
- '#Control structures using switch should not be used\.#'
- '#has a nullable return type declaration#'
- '#with a nullable type declaration#'
- '#with null as default value#'
- '#Constructor in [a-zA-Z0-9\\_]+ has parameter \$[a-zA-Z0-9\\_]+ with default value#'
-
message: '#Function compact\(\) should not be used.#'
paths:
- ../app/Http/Controllers
- ../app/Support/Http/Controllers/RenderPartialViews.php
- ../app/Support/Form/FormSupport.php
- ../app/Support/Form/CurrencyForm.php
- ../app/Support/Form/AccountForm.php
- ../app/Support/ExpandedForm.php
- ../app/Generator/Report
paths:
- ../app
- ../database
@@ -17,4 +30,4 @@ parameters:
- ../bootstrap/app.php
# The level 8 is the highest level. original was 5
level: 5
level: 2

View File

@@ -21,12 +21,13 @@
#
# Install composer packages
composer install --no-scripts --no-ansi
#composer install --no-scripts --no-ansi
# enable test .env file.
cp .ci/.env.ci .env
# Do static code analysis.
./vendor/bin/phpstan analyse -c .ci/phpstan.neon --no-progress
# ./vendor/bin/phpstan analyse -c .ci/phpstan.neon --no-progress
./vendor/bin/phpstan analyse -c .ci/phpstan.neon
exit 0

View File

@@ -24,6 +24,7 @@
cp .ci/.env.ci ../.env
# download test database
# TODO no longer exists
wget --quiet https://raw.githubusercontent.com/firefly-iii/test-data/main/test_db.sqlite -o storage/database/test_db.sqlite
# run phpunit

View File

@@ -155,8 +155,16 @@ SEND_REPORT_JOURNALS=true
# Set a Mapbox API key here (see mapbox.com) so there might be a map available at various places.
# If you use Docker or similar, you can set this variable from a file by appending it with _FILE
# Take note: it is no longer necessary to set this value, and it will be removed in future versions.
MAPBOX_API_KEY=
#
# Instead of the mapbox API key, just set this value to true if you want to set the location
# of certain things, like transactions. Since this involves an external service, it's optional
# and disabled by default.
#
ENABLE_EXTERNAL_MAP=false
# The map will default to this location:
MAP_DEFAULT_LAT=51.983333
MAP_DEFAULT_LONG=5.916667
@@ -320,6 +328,7 @@ BROADCAST_DRIVER=log
QUEUE_DRIVER=sync
CACHE_PREFIX=firefly
PUSHER_KEY=
IPINFO_TOKEN=
PUSHER_SECRET=
PUSHER_ID=
DEMO_USERNAME=

View File

@@ -66,7 +66,7 @@ class ObjectGroupController extends Controller
$return = [];
$result = $this->repository->search($data['query'], $data['limit']);
/** @var ObjectGroup $account */
/** @var ObjectGroup $objectGroup */
foreach ($result as $objectGroup) {
$return[] = [
'id' => (string)$objectGroup->id,

View File

@@ -86,12 +86,12 @@ class AccountController extends Controller
$defaultSet = $this->repository->getAccountsByType([AccountType::ASSET])->pluck('id')->toArray();
$frontPage = app('preferences')->get('frontPageAccounts', $defaultSet);
$default = app('amount')->getDefaultCurrency();
// @codeCoverageIgnoreStart
if (0 === count($frontPage->data)) {
$frontPage->data = $defaultSet;
$frontPage->save();
}
// @codeCoverageIgnoreEnd
// get accounts:
$accounts = $this->repository->getAccountsById($frontPage->data);
@@ -100,7 +100,7 @@ class AccountController extends Controller
foreach ($accounts as $account) {
$currency = $this->repository->getAccountCurrency($account);
if (null === $currency) {
$currency = $default; // @codeCoverageIgnore
$currency = $default;
}
$currentSet = [
'label' => $account->name,
@@ -108,8 +108,8 @@ class AccountController extends Controller
'currency_code' => $currency->code,
'currency_symbol' => $currency->symbol,
'currency_decimal_places' => $currency->decimal_places,
'start_date' => $start->format('Y-m-d'),
'end_date' => $end->format('Y-m-d'),
'start_date' => $start->toAtomString(),
'end_date' => $end->toAtomString(),
'type' => 'line', // line, area or bar
'yAxisID' => 0, // 0, 1, 2
'entries' => [],
@@ -120,7 +120,7 @@ class AccountController extends Controller
$previous = round((float)array_values($range)[0], 12);
while ($currentStart <= $end) {
$format = $currentStart->format('Y-m-d');
$label = $currentStart->format('Y-m-d');
$label = $currentStart->toAtomString();
$balance = array_key_exists($format, $range) ? round((float)$range[$format], 12) : $previous;
$previous = $balance;
$currentStart->addDay();

View File

@@ -0,0 +1,71 @@
<?php
declare(strict_types=1);
/*
* AccountController.php
* Copyright (c) 2021 james@firefly-iii.org
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
namespace FireflyIII\Api\V1\Controllers\Data\Bulk;
use FireflyIII\Api\V1\Controllers\Controller;
use FireflyIII\Api\V1\Requests\Data\Bulk\MoveTransactionsRequest;
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use FireflyIII\Services\Internal\Destroy\AccountDestroyService;
use Illuminate\Http\JsonResponse;
/**
* Class AccountController
*/
class AccountController extends Controller
{
private AccountRepositoryInterface $repository;
public function __construct()
{
parent::__construct();
$this->middleware(
function ($request, $next) {
$this->repository = app(AccountRepositoryInterface::class);
$this->repository->setUser(auth()->user());
return $next($request);
}
);
}
/**
* @param MoveTransactionsRequest $request
*
* @return JsonResponse
*/
public function moveTransactions(MoveTransactionsRequest $request): JsonResponse
{
$accountIds = $request->getAll();
$original = $this->repository->findNull($accountIds['original_account']);
$destination = $this->repository->findNull($accountIds['destination_account']);
/** @var AccountDestroyService $service */
$service = app(AccountDestroyService::class);
$service->moveTransactions($original, $destination);
return response()->json([], 204);
}
}

View File

@@ -25,7 +25,6 @@ namespace FireflyIII\Api\V1\Controllers\Data\Export;
use FireflyIII\Api\V1\Controllers\Controller;
use FireflyIII\Api\V1\Requests\Data\Export\ExportRequest;
use FireflyIII\Support\Export\ExportDataGenerator;
use FireflyIII\User;
use Illuminate\Http\Response as LaravelResponse;
use League\Csv\CannotInsertRecord;
@@ -44,11 +43,8 @@ class ExportController extends Controller
parent::__construct();
$this->middleware(
function ($request, $next) {
/** @var User $user */
$user = auth()->user();
/** @var ExportDataGenerator $exporter */
$this->exporter = app(ExportDataGenerator::class);
$this->exporter->setUser($user);
$this->exporter->setUser(auth()->user());
return $next($request);
}
@@ -92,7 +88,7 @@ class ExportController extends Controller
->header('Expires', '0')
->header('Cache-Control', 'must-revalidate, post-check=0, pre-check=0')
->header('Pragma', 'public')
->header('Content-Length', strlen($data[$key]));
->header('Content-Length', (string)strlen($data[$key]));
return $response;
}

View File

@@ -44,9 +44,8 @@ class TagController extends Controller
parent::__construct();
$this->middleware(
function ($request, $next) {
$user = auth()->user();
$this->repository = app(TagRepositoryInterface::class);
$this->repository->setUser($user);
$this->repository->setUser(auth()->user());
return $next($request);
}
@@ -128,7 +127,7 @@ class TagController extends Controller
$collector->setTypes([TransactionType::WITHDRAWAL])->setRange($start, $end)->setSourceAccounts($accounts);
$collector->setTags($tags);
$genericSet = $collector->getExtractedJournals();
/** @var array $entry */
/** @var array $journal */
foreach ($genericSet as $journal) {
$currencyId = (int)$journal['currency_id'];
$foreignCurrencyId = (int)$journal['foreign_currency_id'];

View File

@@ -130,7 +130,7 @@ class TagController extends Controller
$collector->setTypes([TransactionType::DEPOSIT])->setRange($start, $end)->setDestinationAccounts($accounts);
$collector->setTags($tags);
$genericSet = $collector->getExtractedJournals();
/** @var array $entry */
/** @var array $journal */
foreach ($genericSet as $journal) {
$currencyId = (int)$journal['currency_id'];
$foreignCurrencyId = (int)$journal['foreign_currency_id'];

View File

@@ -132,7 +132,7 @@ class TagController extends Controller
$collector->setTypes([TransactionType::TRANSFER])->setRange($start, $end)->setDestinationAccounts($accounts);
$collector->setTags($tags);
$genericSet = $collector->getExtractedJournals();
/** @var array $entry */
/** @var array $journal */
foreach ($genericSet as $journal) {
$currencyId = (int)$journal['currency_id'];
$foreignCurrencyId = (int)$journal['foreign_currency_id'];

View File

@@ -100,7 +100,7 @@ class ShowController extends Controller
->header('Expires', '0')
->header('Cache-Control', 'must-revalidate, post-check=0, pre-check=0')
->header('Pragma', 'public')
->header('Content-Length', strlen($content));
->header('Content-Length', (string)strlen($content));
return $response;
}

View File

@@ -46,12 +46,8 @@ class DestroyController extends Controller
parent::__construct();
$this->middleware(
function ($request, $next) {
/** @var User $admin */
$admin = auth()->user();
/** @var BillRepositoryInterface repository */
$this->repository = app(BillRepositoryInterface::class);
$this->repository->setUser($admin);
$this->repository->setUser(auth()->user());
return $next($request);
}

View File

@@ -57,12 +57,8 @@ class ListController extends Controller
parent::__construct();
$this->middleware(
function ($request, $next) {
/** @var User $admin */
$admin = auth()->user();
/** @var BillRepositoryInterface repository */
$this->repository = app(BillRepositoryInterface::class);
$this->repository->setUser($admin);
$this->repository->setUser(auth()->user());
return $next($request);
}

View File

@@ -51,12 +51,8 @@ class ShowController extends Controller
parent::__construct();
$this->middleware(
function ($request, $next) {
/** @var User $admin */
$admin = auth()->user();
/** @var BillRepositoryInterface repository */
$this->repository = app(BillRepositoryInterface::class);
$this->repository->setUser($admin);
$this->repository->setUser(auth()->user());
return $next($request);
}

View File

@@ -52,12 +52,8 @@ class StoreController extends Controller
parent::__construct();
$this->middleware(
function ($request, $next) {
/** @var User $admin */
$admin = auth()->user();
/** @var BillRepositoryInterface repository */
$this->repository = app(BillRepositoryInterface::class);
$this->repository->setUser($admin);
$this->repository->setUser(auth()->user());
return $next($request);
}

View File

@@ -49,12 +49,8 @@ class UpdateController extends Controller
parent::__construct();
$this->middleware(
function ($request, $next) {
/** @var User $admin */
$admin = auth()->user();
/** @var BillRepositoryInterface repository */
$this->repository = app(BillRepositoryInterface::class);
$this->repository->setUser($admin);
$this->repository->setUser(auth()->user());
return $next($request);
}

View File

@@ -46,12 +46,8 @@ class DestroyController extends Controller
parent::__construct();
$this->middleware(
function ($request, $next) {
/** @var User $admin */
$admin = auth()->user();
/** @var CategoryRepositoryInterface repository */
$this->repository = app(CategoryRepositoryInterface::class);
$this->repository->setUser($admin);
$this->repository->setUser(auth()->user());
return $next($request);
}

View File

@@ -56,12 +56,8 @@ class ListController extends Controller
parent::__construct();
$this->middleware(
function ($request, $next) {
/** @var User $admin */
$admin = auth()->user();
/** @var CategoryRepositoryInterface repository */
$this->repository = app(CategoryRepositoryInterface::class);
$this->repository->setUser($admin);
$this->repository->setUser(auth()->user());
return $next($request);
}

View File

@@ -51,12 +51,8 @@ class ShowController extends Controller
parent::__construct();
$this->middleware(
function ($request, $next) {
/** @var User $admin */
$admin = auth()->user();
/** @var CategoryRepositoryInterface repository */
$this->repository = app(CategoryRepositoryInterface::class);
$this->repository->setUser($admin);
$this->repository->setUser(auth()->user());
return $next($request);
}

View File

@@ -49,12 +49,8 @@ class StoreController extends Controller
parent::__construct();
$this->middleware(
function ($request, $next) {
/** @var User $admin */
$admin = auth()->user();
/** @var CategoryRepositoryInterface repository */
$this->repository = app(CategoryRepositoryInterface::class);
$this->repository->setUser($admin);
$this->repository->setUser(auth()->user());
return $next($request);
}

View File

@@ -49,12 +49,8 @@ class UpdateController extends Controller
parent::__construct();
$this->middleware(
function ($request, $next) {
/** @var User $admin */
$admin = auth()->user();
/** @var CategoryRepositoryInterface repository */
$this->repository = app(CategoryRepositoryInterface::class);
$this->repository->setUser($admin);
$this->repository->setUser(auth()->user());
return $next($request);
}

View File

@@ -46,12 +46,8 @@ class DestroyController extends Controller
parent::__construct();
$this->middleware(
function ($request, $next) {
/** @var User $user */
$user = auth()->user();
/** @var RecurringRepositoryInterface repository */
$this->repository = app(RecurringRepositoryInterface::class);
$this->repository->setUser($user);
$this->repository->setUser(auth()->user());
return $next($request);
}

View File

@@ -54,12 +54,8 @@ class ListController extends Controller
parent::__construct();
$this->middleware(
function ($request, $next) {
/** @var User $user */
$user = auth()->user();
/** @var RecurringRepositoryInterface repository */
$this->repository = app(RecurringRepositoryInterface::class);
$this->repository->setUser($user);
$this->repository->setUser(auth()->user());
return $next($request);
}

View File

@@ -51,12 +51,8 @@ class ShowController extends Controller
parent::__construct();
$this->middleware(
function ($request, $next) {
/** @var User $user */
$user = auth()->user();
/** @var RecurringRepositoryInterface repository */
$this->repository = app(RecurringRepositoryInterface::class);
$this->repository->setUser($user);
$this->repository->setUser(auth()->user());
return $next($request);
}

View File

@@ -49,12 +49,8 @@ class StoreController extends Controller
parent::__construct();
$this->middleware(
function ($request, $next) {
/** @var User $user */
$user = auth()->user();
/** @var RecurringRepositoryInterface repository */
$this->repository = app(RecurringRepositoryInterface::class);
$this->repository->setUser($user);
$this->repository->setUser(auth()->user());
return $next($request);
}

View File

@@ -1,86 +0,0 @@
<?php
/*
* TriggerController.php
* Copyright (c) 2021 james@firefly-iii.org
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace FireflyIII\Api\V1\Controllers\Models\Recurrence;
use FireflyIII\Api\V1\Controllers\Controller;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Repositories\Recurring\RecurringRepositoryInterface;
use FireflyIII\Support\Cronjobs\RecurringCronjob;
use FireflyIII\User;
use Illuminate\Http\JsonResponse;
use Log;
/**
* Class TriggerController
*/
class TriggerController extends Controller
{
private RecurringRepositoryInterface $repository;
/**
* RecurrenceController constructor.
*
* @codeCoverageIgnore
*/
public function __construct()
{
parent::__construct();
$this->middleware(
function ($request, $next) {
/** @var User $user */
$user = auth()->user();
/** @var RecurringRepositoryInterface repository */
$this->repository = app(RecurringRepositoryInterface::class);
$this->repository->setUser($user);
return $next($request);
}
);
}
/**
* @return JsonResponse
* @throws FireflyException
* @codeCoverageIgnore
*
* TODO currently unused + unreachable.
*/
public function trigger(): JsonResponse
{
/** @var RecurringCronjob $recurring */
$recurring = app(RecurringCronjob::class);
try {
$result = $recurring->fire();
} catch (FireflyException $e) {
Log::error($e->getMessage());
throw new FireflyException('200022: Error in cron job.', 0, $e);
}
if (false === $result) {
return response()->json([], 204);
}
return response()->json();
}
}

View File

@@ -49,12 +49,8 @@ class UpdateController extends Controller
parent::__construct();
$this->middleware(
function ($request, $next) {
/** @var User $user */
$user = auth()->user();
/** @var RecurringRepositoryInterface repository */
$this->repository = app(RecurringRepositoryInterface::class);
$this->repository->setUser($user);
$this->repository->setUser(auth()->user());
return $next($request);
}

View File

@@ -37,6 +37,7 @@ use Illuminate\Pagination\LengthAwarePaginator;
use Illuminate\Support\Collection;
use League\Fractal\Pagination\IlluminatePaginatorAdapter;
use League\Fractal\Resource\Collection as FractalCollection;
use Exception;
/**
* Class TriggerController

View File

@@ -94,13 +94,13 @@ class StoreController extends Controller
$validator = Validator::make(
['transactions' => [['description' => $e->getMessage()]]], ['transactions.0.description' => new IsDuplicateTransaction]
);
throw new ValidationException($validator);
throw new ValidationException($validator,0, $e);
} catch (FireflyException $e) {
Log::warning('Caught an exception. Return error message.');
Log::error($e->getMessage());
$message = sprintf('Internal exception: %s', $e->getMessage());
$validator = Validator::make(['transactions' => [['description' => $message]]], ['transactions.0.description' => new IsDuplicateTransaction]);
throw new ValidationException($validator);
throw new ValidationException($validator,0, $e);
}
app('preferences')->mark();
event(new StoredTransactionGroup($transactionGroup, $data['apply_rules'] ?? true));

View File

@@ -96,7 +96,7 @@ class UpdateController extends Controller
$selectedGroup = $collector->getGroups()->first();
if (null === $selectedGroup) {
throw new NotFoundHttpException(); // @codeCoverageIgnore
throw new NotFoundHttpException();
}
/** @var TransactionGroupTransformer $transformer */
$transformer = app(TransactionGroupTransformer::class);

View File

@@ -50,13 +50,9 @@ class DestroyController extends Controller
parent::__construct();
$this->middleware(
function ($request, $next) {
/** @var User $admin */
$admin = auth()->user();
/** @var CurrencyRepositoryInterface repository */
$this->repository = app(CurrencyRepositoryInterface::class);
$this->userRepository = app(UserRepositoryInterface::class);
$this->repository->setUser($admin);
$this->repository->setUser(auth()->user());
return $next($request);
}
@@ -79,13 +75,13 @@ class DestroyController extends Controller
if (!$this->userRepository->hasRole($admin, 'owner')) {
// access denied:
throw new FireflyException('200005: You need the "owner" role to do this.'); // @codeCoverageIgnore
throw new FireflyException('200005: You need the "owner" role to do this.');
}
if ($this->repository->currencyInUse($currency)) {
throw new FireflyException('200006: Currency in use.'); // @codeCoverageIgnore
throw new FireflyException('200006: Currency in use.');
}
if ($this->repository->isFallbackCurrency($currency)) {
throw new FireflyException('200026: Currency is fallback.'); // @codeCoverageIgnore
throw new FireflyException('200026: Currency is fallback.');
}
$this->repository->destroy($currency);

View File

@@ -77,13 +77,9 @@ class ListController extends Controller
parent::__construct();
$this->middleware(
function ($request, $next) {
/** @var User $admin */
$admin = auth()->user();
/** @var CurrencyRepositoryInterface repository */
$this->repository = app(CurrencyRepositoryInterface::class);
$this->userRepository = app(UserRepositoryInterface::class);
$this->repository->setUser($admin);
$this->repository->setUser(auth()->user());
return $next($request);
}

View File

@@ -56,12 +56,8 @@ class ShowController extends Controller
parent::__construct();
$this->middleware(
function ($request, $next) {
/** @var User $admin */
$admin = auth()->user();
/** @var CurrencyRepositoryInterface repository */
$this->repository = app(CurrencyRepositoryInterface::class);
$this->repository->setUser($admin);
$this->repository->setUser(auth()->user());
return $next($request);
}

View File

@@ -56,13 +56,9 @@ class StoreController extends Controller
parent::__construct();
$this->middleware(
function ($request, $next) {
/** @var User $admin */
$admin = auth()->user();
/** @var CurrencyRepositoryInterface repository */
$this->repository = app(CurrencyRepositoryInterface::class);
$this->userRepository = app(UserRepositoryInterface::class);
$this->repository->setUser($admin);
$this->repository->setUser(auth()->user());
return $next($request);
}

View File

@@ -56,13 +56,9 @@ class UpdateController extends Controller
parent::__construct();
$this->middleware(
function ($request, $next) {
/** @var User $admin */
$admin = auth()->user();
/** @var CurrencyRepositoryInterface repository */
$this->repository = app(CurrencyRepositoryInterface::class);
$this->userRepository = app(UserRepositoryInterface::class);
$this->repository->setUser($admin);
$this->repository->setUser(auth()->user());
return $next($request);
}

View File

@@ -80,7 +80,7 @@ class StoreController extends Controller
$admin = auth()->user();
if (!$this->userRepository->hasRole($admin, 'owner')) {
throw new FireflyException('200005: You need the "owner" role to do this.'); // @codeCoverageIgnore
throw new FireflyException('200005: You need the "owner" role to do this.');
}
$data = $request->getAll();
// if currency ID is 0, find the currency by the code:

View File

@@ -86,7 +86,7 @@ class UpdateController extends Controller
$admin = auth()->user();
if (!$this->userRepository->hasRole($admin, 'owner')) {
throw new FireflyException('200005: You need the "owner" role to do this.'); // @codeCoverageIgnore
throw new FireflyException('200005: You need the "owner" role to do this.');
}
$data = $request->getAll();

View File

@@ -64,7 +64,7 @@ class ConfigurationController extends Controller
} catch (FireflyException $e) {
Log::error($e->getMessage());
Log::error($e->getTraceAsString());
throw new FireflyException('200030: Could not load config variables.');
throw new FireflyException('200030: Could not load config variables.', 0, $e);
}
$staticData = $this->getStaticConfiguration();
$return = [];
@@ -161,7 +161,7 @@ class ConfigurationController extends Controller
public function update(UpdateRequest $request, string $name): JsonResponse
{
if (!$this->repository->hasRole(auth()->user(), 'owner')) {
throw new FireflyException('200005: You need the "owner" role to do this.'); // @codeCoverageIgnore
throw new FireflyException('200005: You need the "owner" role to do this.');
}
$data = $request->getAll();
$shortName = str_replace('configuration.', '', $name);

View File

@@ -54,7 +54,6 @@ class UserController extends Controller
parent::__construct();
$this->middleware(
function ($request, $next) {
/** @var UserRepositoryInterface repository */
$this->repository = app(UserRepositoryInterface::class);
return $next($request);
@@ -84,7 +83,7 @@ class UserController extends Controller
return response()->json([], 204);
}
throw new FireflyException('200025: No access to function.'); // @codeCoverageIgnore
throw new FireflyException('200025: No access to function.');
}
/**

View File

@@ -53,12 +53,8 @@ class AttemptController extends Controller
parent::__construct();
$this->middleware(
function ($request, $next) {
/** @var User $admin */
$admin = auth()->user();
/** @var WebhookRepositoryInterface repository */
$this->repository = app(WebhookRepositoryInterface::class);
$this->repository->setUser($admin);
$this->repository->setUser(auth()->user());
return $next($request);
}

View File

@@ -48,12 +48,8 @@ class DestroyController extends Controller
parent::__construct();
$this->middleware(
function ($request, $next) {
/** @var User $admin */
$admin = auth()->user();
/** @var WebhookRepositoryInterface repository */
$this->repository = app(WebhookRepositoryInterface::class);
$this->repository->setUser($admin);
$this->repository->setUser(auth()->user());
return $next($request);
}

View File

@@ -49,12 +49,8 @@ class MessageController extends Controller
parent::__construct();
$this->middleware(
function ($request, $next) {
/** @var User $admin */
$admin = auth()->user();
/** @var WebhookRepositoryInterface repository */
$this->repository = app(WebhookRepositoryInterface::class);
$this->repository->setUser($admin);
$this->repository->setUser(auth()->user());
return $next($request);
}

View File

@@ -50,12 +50,8 @@ class ShowController extends Controller
parent::__construct();
$this->middleware(
function ($request, $next) {
/** @var User $admin */
$admin = auth()->user();
/** @var WebhookRepositoryInterface repository */
$this->repository = app(WebhookRepositoryInterface::class);
$this->repository->setUser($admin);
$this->repository->setUser(auth()->user());
return $next($request);
}

View File

@@ -47,12 +47,8 @@ class StoreController extends Controller
parent::__construct();
$this->middleware(
function ($request, $next) {
/** @var User $admin */
$admin = auth()->user();
/** @var WebhookRepositoryInterface repository */
$this->repository = app(WebhookRepositoryInterface::class);
$this->repository->setUser($admin);
$this->repository->setUser(auth()->user());
return $next($request);
}

View File

@@ -27,7 +27,6 @@ use FireflyIII\Api\V1\Controllers\Controller;
use FireflyIII\Jobs\SendWebhookMessage;
use FireflyIII\Models\Webhook;
use FireflyIII\Repositories\Webhook\WebhookRepositoryInterface;
use FireflyIII\User;
use Illuminate\Http\JsonResponse;
/**
@@ -45,12 +44,8 @@ class SubmitController extends Controller
parent::__construct();
$this->middleware(
function ($request, $next) {
/** @var User $admin */
$admin = auth()->user();
/** @var WebhookRepositoryInterface repository */
$this->repository = app(WebhookRepositoryInterface::class);
$this->repository->setUser($admin);
$this->repository->setUser(auth()->user());
return $next($request);
}

View File

@@ -47,12 +47,8 @@ class UpdateController extends Controller
parent::__construct();
$this->middleware(
function ($request, $next) {
/** @var User $admin */
$admin = auth()->user();
/** @var WebhookRepositoryInterface repository */
$this->repository = app(WebhookRepositoryInterface::class);
$this->repository->setUser($admin);
$this->repository->setUser(auth()->user());
return $next($request);
}

View File

@@ -41,7 +41,7 @@ class ApiDemoUser
*/
public function handle(Request $request, Closure $next)
{
/** @var User $user */
/** @var User|null $user */
$user = $request->user();
if (null === $user) {

View File

@@ -0,0 +1,105 @@
<?php
declare(strict_types=1);
/*
* MoveTransactionsRequest.php
* Copyright (c) 2021 james@firefly-iii.org
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
namespace FireflyIII\Api\V1\Requests\Data\Bulk;
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use FireflyIII\Support\Request\ChecksLogin;
use FireflyIII\Support\Request\ConvertsDataTypes;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Validation\Validator;
/**
* Class MoveTransactionsRequest
*/
class MoveTransactionsRequest extends FormRequest
{
use ChecksLogin, ConvertsDataTypes;
/**
* @return array
*/
public function getAll(): array
{
return [
'original_account' => $this->integer('original_account'),
'destination_account' => $this->integer('destination_account'),
];
}
/**
* @return string[]
*/
public function rules(): array
{
return [
'original_account' => 'required|different:destination_account|belongsToUser:accounts,id',
'destination_account' => 'required|different:original_account|belongsToUser:accounts,id',
];
}
/**
* Configure the validator instance with special rules for after the basic validation rules.
*
* @param Validator $validator
* TODO duplicate code.
*
* @return void
*/
public function withValidator(Validator $validator): void
{
$validator->after(
function (Validator $validator) {
// validate start before end only if both are there.
$data = $validator->getData();
if (array_key_exists('original_account', $data) && array_key_exists('destination_account', $data)) {
$repository = app(AccountRepositoryInterface::class);
$repository->setUser(auth()->user());
$original = $repository->findNull((int)$data['original_account']);
$destination = $repository->findNull((int)$data['destination_account']);
if ($original->accountType->type !== $destination->accountType->type) {
$validator->errors()->add('title', (string)trans('validation.same_account_type'));
return;
}
// get currency pref:
$originalCurrency = $repository->getAccountCurrency($original);
$destinationCurrency = $repository->getAccountCurrency($destination);
if (null === $originalCurrency xor null === $destinationCurrency) {
$validator->errors()->add('title', (string)trans('validation.same_account_currency'));
return;
}
if (null === $originalCurrency && null === $destinationCurrency) {
// this is OK
return;
}
if ($originalCurrency->code !== $destinationCurrency->code) {
$validator->errors()->add('title', (string)trans('validation.same_account_currency'));
return;
}
}
}
);
}
}

View File

@@ -86,9 +86,6 @@ class GenericRequest extends FormRequest
*/
private function parseAccounts(): void
{
if (null === $this->accounts) {
$this->accounts = new Collection;
}
if (0 !== $this->accounts->count()) {
return;
}
@@ -121,9 +118,6 @@ class GenericRequest extends FormRequest
*/
private function parseBills(): void
{
if (null === $this->bills) {
$this->bills = new Collection;
}
if (0 !== $this->bills->count()) {
return;
}
@@ -156,9 +150,6 @@ class GenericRequest extends FormRequest
*/
private function parseBudgets(): void
{
if (null === $this->budgets) {
$this->budgets = new Collection;
}
if (0 !== $this->budgets->count()) {
return;
}
@@ -191,9 +182,6 @@ class GenericRequest extends FormRequest
*/
private function parseCategories(): void
{
if (null === $this->categories) {
$this->categories = new Collection;
}
if (0 !== $this->categories->count()) {
return;
}
@@ -284,9 +272,6 @@ class GenericRequest extends FormRequest
*/
private function parseTags(): void
{
if (null === $this->tags) {
$this->tags = new Collection;
}
if (0 !== $this->tags->count()) {
return;
}
@@ -311,7 +296,7 @@ class GenericRequest extends FormRequest
*/
public function rules(): array
{
// this is cheating but it works:
// this is cheating but it works to initialize the collections.
$this->accounts = new Collection;
$this->budgets = new Collection;
$this->categories = new Collection;

View File

@@ -59,7 +59,7 @@ class StoreRequest extends FormRequest
'name' => $this->string('name'),
'active' => $active,
'include_net_worth' => $includeNetWorth,
'account_type' => $this->string('type'),
'account_type_name' => $this->string('type'),
'account_type_id' => null,
'currency_id' => $this->integer('currency_id'),
'order' => $this->integer('order'),
@@ -73,17 +73,17 @@ class StoreRequest extends FormRequest
'opening_balance_date' => $this->date('opening_balance_date'),
'cc_type' => $this->string('credit_card_type'),
'cc_monthly_payment_date' => $this->string('monthly_payment_date'),
'notes' => $this->nlString('notes'),
'notes' => $this->stringWithNewlines('notes'),
'interest' => $this->string('interest'),
'interest_period' => $this->string('interest_period'),
];
// append Location information.
$data = $this->appendLocationData($data, null);
if ('liability' === $data['account_type'] || 'liabilities' === $data['account_type']) {
if ('liability' === $data['account_type_name'] || 'liabilities' === $data['account_type_name']) {
$data['opening_balance'] = bcmul($this->string('liability_amount'), '-1');
$data['opening_balance_date'] = $this->date('liability_start_date');
$data['account_type'] = $this->string('liability_type');
$data['account_type_name'] = $this->string('liability_type');
$data['account_type_id'] = null;
}

View File

@@ -51,7 +51,7 @@ class UpdateRequest extends FormRequest
'name' => ['name', 'string'],
'active' => ['active', 'boolean'],
'include_net_worth' => ['include_net_worth', 'boolean'],
'account_type' => ['type', 'string'],
'account_type_name' => ['type', 'string'],
'virtual_balance' => ['virtual_balance', 'string'],
'iban' => ['iban', 'string'],
'BIC' => ['bic', 'string'],
@@ -62,7 +62,7 @@ class UpdateRequest extends FormRequest
'opening_balance_date' => ['opening_balance_date', 'date'],
'cc_type' => ['credit_card_type', 'string'],
'cc_monthly_payment_date' => ['monthly_payment_date', 'string'],
'notes' => ['notes', 'nlString'],
'notes' => ['notes', 'stringWithNewlines'],
'interest' => ['interest', 'string'],
'interest_period' => ['interest_period', 'string'],
'order' => ['order', 'integer'],
@@ -72,10 +72,10 @@ class UpdateRequest extends FormRequest
$data = $this->getAllData($fields);
$data = $this->appendLocationData($data, null);
if (array_key_exists('account_type', $data) && 'liability' === $data['account_type']) {
$data['opening_balance'] = bcmul($this->nullableString('liability_amount'), '-1');
if (array_key_exists('account_type_name', $data) && 'liability' === $data['account_type_name']) {
$data['opening_balance'] = bcmul($this->string('liability_amount'), '-1');
$data['opening_balance_date'] = $this->date('liability_start_date');
$data['account_type'] = $this->nullableString('liability_type');
$data['account_type_name'] = $this->string('liability_type');
$data['account_type_id'] = null;
}
@@ -97,9 +97,9 @@ class UpdateRequest extends FormRequest
$rules = [
'name' => sprintf('min:1|uniqueAccountForUser:%d', $account->id),
'type' => sprintf('in:%s', $types),
'iban' => ['iban', 'nullable', new UniqueIban($account, $this->nullableString('type'))],
'iban' => ['iban', 'nullable', new UniqueIban($account, $this->string('type'))],
'bic' => 'bic|nullable',
'account_number' => ['between:1,255', 'nullable', new UniqueAccountNumber($account, $this->nullableString('type'))],
'account_number' => ['between:1,255', 'nullable', new UniqueAccountNumber($account, $this->string('type'))],
'opening_balance' => 'numeric|required_with:opening_balance_date|nullable',
'opening_balance_date' => 'date|required_with:opening_balance|nullable',
'virtual_balance' => 'numeric|nullable',

View File

@@ -47,7 +47,7 @@ class StoreRequest extends FormRequest
return [
'filename' => $this->string('filename'),
'title' => $this->string('title'),
'notes' => $this->nlString('notes'),
'notes' => $this->stringWithNewlines('notes'),
'attachable_type' => $this->string('attachable_type'),
'attachable_id' => $this->integer('attachable_id'),
];

View File

@@ -47,7 +47,7 @@ class UpdateRequest extends FormRequest
$fields = [
'filename' => ['filename', 'string'],
'title' => ['title', 'string'],
'notes' => ['notes', 'nlString'],
'notes' => ['notes', 'stringWithNewlines'],
'attachable_type' => ['attachable_type', 'string'],
'attachable_id' => ['attachable_id', 'integer'],
];

View File

@@ -59,7 +59,7 @@ class StoreRequest extends FormRequest
'skip' => ['skip', 'integer'],
'active' => ['active', 'boolean'],
'order' => ['order', 'integer'],
'notes' => ['notes', 'nlString'],
'notes' => ['notes', 'stringWithNewlines'],
'object_group_id' => ['object_group_id', 'integer'],
'object_group_title' => ['object_group_title', 'string'],
];

View File

@@ -57,7 +57,7 @@ class UpdateRequest extends FormRequest
'skip' => ['skip', 'integer'],
'active' => ['active', 'boolean'],
'order' => ['order', 'integer'],
'notes' => ['notes', 'nlString'],
'notes' => ['notes', 'stringWithNewlines'],
'object_group_id' => ['object_group_id', 'integer'],
'object_group_title' => ['object_group_title', 'string'],
];

View File

@@ -46,7 +46,7 @@ class StoreRequest extends FormRequest
{
return [
'name' => $this->string('name'),
'notes' => $this->nlString('notes'),
'notes' => $this->stringWithNewlines('notes'),
];
}

View File

@@ -45,7 +45,7 @@ class UpdateRequest extends FormRequest
{
$fields = [
'name' => ['name', 'string'],
'notes' => ['notes', 'nlString'],
'notes' => ['notes', 'stringWithNewlines'],
];
return $this->getAllData($fields);

View File

@@ -53,7 +53,7 @@ class StoreRequest extends FormRequest
$data['current_amount'] = $this->string('current_amount');
$data['startdate'] = $this->date('start_date');
$data['targetdate'] = $this->date('target_date');
$data['notes'] = $this->nlString('notes');
$data['notes'] = $this->stringWithNewlines('notes');
$data['object_group_id'] = $this->integer('object_group_id');
$data['object_group_title'] = $this->string('object_group_title');

View File

@@ -52,7 +52,7 @@ class UpdateRequest extends FormRequest
'current_amount' => ['current_amount', 'string'],
'startdate' => ['start_date', 'date'],
'targetdate' => ['target_date', 'string'],
'notes' => ['notes', 'nlString'],
'notes' => ['notes', 'stringWithNewlines'],
'order' => ['order', 'integer'],
'object_group_title' => ['object_group_title', 'string'],
'object_group_id' => ['object_group_id', 'integer'],

View File

@@ -58,7 +58,7 @@ class StoreRequest extends FormRequest
'nr_of_repetitions' => ['nr_of_repetitions', 'integer'],
'apply_rules' => ['apply_rules', 'boolean'],
'active' => ['active', 'boolean'],
'notes' => ['notes', 'nlString'],
'notes' => ['notes', 'stringWithNewlines'],
];
$recurrence = $this->getAllData($fields);
@@ -79,7 +79,7 @@ class StoreRequest extends FormRequest
{
$return = [];
// transaction data:
/** @var array $transactions */
/** @var array|null $transactions */
$transactions = $this->get('transactions');
if (null === $transactions) {
return [];
@@ -101,7 +101,7 @@ class StoreRequest extends FormRequest
{
$return = [];
// repetition data:
/** @var array $repetitions */
/** @var array|null $repetitions */
$repetitions = $this->get('repetitions');
if (null === $repetitions) {
return [];

View File

@@ -84,7 +84,7 @@ class UpdateRequest extends FormRequest
{
$return = [];
// repetition data:
/** @var array $repetitions */
/** @var array|null $repetitions */
$repetitions = $this->get('repetitions');
if (null === $repetitions) {
return null;
@@ -126,7 +126,7 @@ class UpdateRequest extends FormRequest
{
$return = [];
// transaction data:
/** @var array $transactions */
/** @var array|null $transactions */
$transactions = $this->get('transactions');
if (null === $transactions) {
return null;

View File

@@ -47,7 +47,7 @@ class UpdateRequest extends FormRequest
{
$fields = [
'title' => ['title', 'string'],
'description' => ['description', 'nlString'],
'description' => ['description', 'stringWithNewlines'],
'rule_group_id' => ['rule_group_id', 'integer'],
'trigger' => ['trigger', 'string'],
'strict' => ['strict', 'boolean'],

View File

@@ -46,7 +46,7 @@ class UpdateRequest extends FormRequest
// This is the way.
$fields = [
'title' => ['title', 'string'],
'description' => ['description', 'nlString'],
'description' => ['description', 'stringWithNewlines'],
'active' => ['active', 'boolean'],
'order' => ['order', 'integer'],
];

View File

@@ -78,75 +78,75 @@ class StoreRequest extends FormRequest
foreach ($this->get('transactions') as $transaction) {
$object = new NullArrayObject($transaction);
$return[] = [
'type' => $this->stringFromValue($object['type']),
'type' => $this->clearString($object['type'], false),
'date' => $this->dateFromValue($object['date']),
'order' => $this->integerFromValue((string)$object['order']),
'currency_id' => $this->integerFromValue((string)$object['currency_id']),
'currency_code' => $this->stringFromValue($object['currency_code']),
'currency_code' => $this->clearString((string)$object['currency_code'], false),
// foreign currency info:
'foreign_currency_id' => $this->integerFromValue((string)$object['foreign_currency_id']),
'foreign_currency_code' => $this->stringFromValue((string)$object['foreign_currency_code']),
'foreign_currency_code' => $this->clearString((string)$object['foreign_currency_code'], false),
// amount and foreign amount. Cannot be 0.
'amount' => $this->stringFromValue((string)$object['amount']),
'foreign_amount' => $this->stringFromValue((string)$object['foreign_amount']),
'amount' => $this->clearString((string)$object['amount'], false),
'foreign_amount' => $this->clearString((string)$object['foreign_amount'], false),
// description.
'description' => $this->stringFromValue($object['description']),
'description' => $this->clearString($object['description'], false),
// source of transaction. If everything is null, assume cash account.
'source_id' => $this->integerFromValue((string)$object['source_id']),
'source_name' => $this->stringFromValue((string)$object['source_name']),
'source_iban' => $this->stringFromValue((string)$object['source_iban']),
'source_number' => $this->stringFromValue((string)$object['source_number']),
'source_bic' => $this->stringFromValue((string)$object['source_bic']),
'source_name' => $this->clearString($object['source_name'], false),
'source_iban' => $this->clearString($object['source_iban'], false),
'source_number' => $this->clearString($object['source_number'], false),
'source_bic' => $this->clearString($object['source_bic'], false),
// destination of transaction. If everything is null, assume cash account.
'destination_id' => $this->integerFromValue((string)$object['destination_id']),
'destination_name' => $this->stringFromValue((string)$object['destination_name']),
'destination_iban' => $this->stringFromValue((string)$object['destination_iban']),
'destination_number' => $this->stringFromValue((string)$object['destination_number']),
'destination_bic' => $this->stringFromValue((string)$object['destination_bic']),
'destination_name' => $this->clearString($object['destination_name'], false),
'destination_iban' => $this->clearString($object['destination_iban'], false),
'destination_number' => $this->clearString($object['destination_number'], false),
'destination_bic' => $this->clearString($object['destination_bic'], false),
// budget info
'budget_id' => $this->integerFromValue((string)$object['budget_id']),
'budget_name' => $this->stringFromValue((string)$object['budget_name']),
'budget_name' => $this->clearString((string)$object['budget_name'], false),
// category info
'category_id' => $this->integerFromValue((string)$object['category_id']),
'category_name' => $this->stringFromValue((string)$object['category_name']),
'category_name' => $this->clearString((string)$object['category_name'], false),
// journal bill reference. Optional. Will only work for withdrawals
'bill_id' => $this->integerFromValue((string)$object['bill_id']),
'bill_name' => $this->stringFromValue((string)$object['bill_name']),
'bill_name' => $this->clearString((string)$object['bill_name'], false),
// piggy bank reference. Optional. Will only work for transfers
'piggy_bank_id' => $this->integerFromValue((string)$object['piggy_bank_id']),
'piggy_bank_name' => $this->stringFromValue((string)$object['piggy_bank_name']),
'piggy_bank_name' => $this->clearString((string)$object['piggy_bank_name'], false),
// some other interesting properties
'reconciled' => $this->convertBoolean((string)$object['reconciled']),
'notes' => $this->nlStringFromValue((string)$object['notes']),
'notes' => $this->clearString((string)$object['notes']),
'tags' => $this->arrayFromValue($object['tags']),
// all custom fields:
'internal_reference' => $this->stringFromValue((string)$object['internal_reference']),
'external_id' => $this->stringFromValue((string)$object['external_id']),
'internal_reference' => $this->clearString((string)$object['internal_reference'], false),
'external_id' => $this->clearString((string)$object['external_id'], false),
'original_source' => sprintf('ff3-v%s|api-v%s', config('firefly.version'), config('firefly.api_version')),
'recurrence_id' => $this->integerFromValue($object['recurrence_id']),
'bunq_payment_id' => $this->stringFromValue((string)$object['bunq_payment_id']),
'external_uri' => $this->stringFromValue((string)$object['external_uri']),
'bunq_payment_id' => $this->clearString((string)$object['bunq_payment_id'], false),
'external_uri' => $this->clearString((string)$object['external_uri'], false),
'sepa_cc' => $this->stringFromValue($object['sepa_cc']),
'sepa_ct_op' => $this->stringFromValue($object['sepa_ct_op']),
'sepa_ct_id' => $this->stringFromValue($object['sepa_ct_id']),
'sepa_db' => $this->stringFromValue($object['sepa_db']),
'sepa_country' => $this->stringFromValue($object['sepa_country']),
'sepa_ep' => $this->stringFromValue($object['sepa_ep']),
'sepa_ci' => $this->stringFromValue($object['sepa_ci']),
'sepa_batch_id' => $this->stringFromValue($object['sepa_batch_id']),
'sepa_cc' => $this->clearString((string)$object['sepa_cc'], false),
'sepa_ct_op' => $this->clearString((string)$object['sepa_ct_op'], false),
'sepa_ct_id' => $this->clearString((string)$object['sepa_ct_id'], false),
'sepa_db' => $this->clearString((string)$object['sepa_db'], false),
'sepa_country' => $this->clearString((string)$object['sepa_country'], false),
'sepa_ep' => $this->clearString((string)$object['sepa_ep'], false),
'sepa_ci' => $this->clearString((string)$object['sepa_ci'], false),
'sepa_batch_id' => $this->clearString((string)$object['sepa_batch_id'], false),
// custom date fields. Must be Carbon objects. Presence is optional.
'interest_date' => $this->dateFromValue($object['interest_date']),
'book_date' => $this->dateFromValue($object['book_date']),

View File

@@ -150,10 +150,7 @@ class UpdateRequest extends FormRequest
return $return;
}
/**
* @var int $index
* @var array $transaction
*/
/** @var array $transaction */
foreach ($this->get('transactions') as $transaction) {
// default response is to update nothing in the transaction:
$current = [];
@@ -197,7 +194,7 @@ class UpdateRequest extends FormRequest
{
foreach ($this->stringFields as $fieldName) {
if (array_key_exists($fieldName, $transaction)) {
$current[$fieldName] = $this->stringFromValue((string)$transaction[$fieldName]);
$current[$fieldName] = $this->clearString((string)$transaction[$fieldName], false);
}
}
@@ -214,7 +211,7 @@ class UpdateRequest extends FormRequest
{
foreach ($this->textareaFields as $fieldName) {
if (array_key_exists($fieldName, $transaction)) {
$current[$fieldName] = $this->nlStringFromValue((string)$transaction[$fieldName]);
$current[$fieldName] = $this->clearString((string)$transaction[$fieldName]);
}
}

View File

@@ -50,7 +50,7 @@ class StoreRequest extends FormRequest
'link_type_name' => $this->string('link_type_name'),
'inward_id' => $this->integer('inward_id'),
'outward_id' => $this->integer('outward_id'),
'notes' => $this->nlString('notes'),
'notes' => $this->stringWithNewlines('notes'),
];
}

View File

@@ -50,7 +50,7 @@ class UpdateRequest extends FormRequest
'link_type_name' => $this->string('link_type_name'),
'inward_id' => $this->integer('inward_id'),
'outward_id' => $this->integer('outward_id'),
'notes' => $this->nullableNlString('notes'),
'notes' => $this->stringWithNewlines('notes'),
];
}
@@ -117,12 +117,6 @@ class UpdateRequest extends FormRequest
$validator->errors()->add('outward_id', 'Inward ID must be different from outward ID.');
}
if (null === $inward) {
$validator->errors()->add('inward_id', 'This is not a valid inward journal.');
}
if (null === $outward) {
$validator->errors()->add('inward_id', 'This is not a valid outward journal.');
}
$inDB = $repository->findSpecificLink($existing->linkType, $inward, $outward);
if (null === $inDB) {
return;

View File

@@ -57,7 +57,7 @@ class UpdateRequest extends FormRequest
return ['value' => $this->integer('value')];
}
return ['value' => $this->string('value')]; // @codeCoverageIgnore
return ['value' => $this->string('value')];
}
/**
@@ -80,6 +80,6 @@ class UpdateRequest extends FormRequest
return ['value' => 'required|numeric|min:464272080'];
}
return ['value' => 'required']; // @codeCoverageIgnore
return ['value' => 'required'];
}
}

View File

@@ -77,11 +77,11 @@ class DeleteEmptyJournals extends Command
// uneven number, delete journal and transactions:
try {
TransactionJournal::find((int)$row->transaction_journal_id)->delete();
// @codeCoverageIgnoreStart
} catch (Exception $e) {
} catch (Exception $e) { // @phpstan-ignore-line
Log::info(sprintf('Could not delete journal: %s', $e->getMessage()));
}
// @codeCoverageIgnoreEnd
Transaction::where('transaction_journal_id', (int)$row->transaction_journal_id)->delete();
$this->info(sprintf('Deleted transaction journal #%d because it had an uneven number of transactions.', $row->transaction_journal_id));
@@ -105,11 +105,11 @@ class DeleteEmptyJournals extends Command
foreach ($set as $entry) {
try {
TransactionJournal::find($entry->id)->delete();
// @codeCoverageIgnoreStart
} catch (Exception $e) {
} catch (Exception $e) { // @phpstan-ignore-line
Log::info(sprintf('Could not delete entry: %s', $e->getMessage()));
}
// @codeCoverageIgnoreEnd
$this->info(sprintf('Deleted empty transaction journal #%d', $entry->id));
++$count;

View File

@@ -118,11 +118,11 @@ class DeleteOrphanedTransactions extends Command
if ($journal) {
try {
$journal->delete();
// @codeCoverageIgnoreStart
} catch (Exception $e) {
} catch (Exception $e) { // @phpstan-ignore-line
Log::info(sprintf('Could not delete journal %s', $e->getMessage()));
}
// @codeCoverageIgnoreEnd
}
Transaction::where('transaction_journal_id', (int)$transaction->transaction_journal_id)->delete();
$this->line(

View File

@@ -64,11 +64,11 @@ class DeleteZeroAmount extends Command
$this->info(sprintf('Deleted transaction journal #%d because the amount is zero (0.00).', $journal->id));
try {
$journal->delete();
// @codeCoverageIgnoreStart
} catch (Exception $e) {
} catch (Exception $e) { // @phpstan-ignore-line
$this->line($e->getMessage());
}
// @codeCoverageIgnoreEnd
Transaction::where('transaction_journal_id', $journal->id)->delete();
}
if (0 === $journals->count()) {

View File

@@ -121,12 +121,12 @@ class FixAccountTypes extends Command
$destAccountType = $destAccount->accountType->type;
if (!array_key_exists($type, $this->expected)) {
// @codeCoverageIgnoreStart
Log::info(sprintf('No source/destination info for transaction type %s.', $type));
$this->info(sprintf('No source/destination info for transaction type %s.', $type));
return;
// @codeCoverageIgnoreEnd
}
if (!array_key_exists($sourceAccountType, $this->expected[$type])) {
Log::debug(sprintf('Going to fix journal #%d', $journal->id));

View File

@@ -70,14 +70,14 @@ class FixPiggies extends Command
}
/** @var TransactionJournal $journal */
$journal = $event->transactionJournal;
// @codeCoverageIgnoreStart
if (null === $journal) {
$event->transaction_journal_id = null;
$event->save();
$this->count++;
continue;
}
// @codeCoverageIgnoreEnd
$type = $journal->transactionType->type;
if (TransactionType::TRANSFER !== $type) {

View File

@@ -91,7 +91,7 @@ class FixUnevenAmount extends Command
// one of the transactions is bad.
$journal = TransactionJournal::find($param);
if (!$journal) {
return; // @codeCoverageIgnore
return;
}
/** @var Transaction $source */
$source = $journal->transactions()->where('amount', '<', 0)->first();

View File

@@ -188,7 +188,7 @@ class DecryptDatabase extends Command
$value = Crypt::decrypt($value);
} catch (DecryptException $e) {
if ('The MAC is invalid.' === $e->getMessage()) {
throw new FireflyException($e->getMessage()); // @codeCoverageIgnore
throw new FireflyException($e->getMessage(), 0, $e);
}
}

View File

@@ -124,11 +124,11 @@ class ExportData extends Command
$exporter->setExportBills($options['export']['bills']);
$exporter->setExportPiggies($options['export']['piggies']);
$data = $exporter->export();
if (empty($data)) {
if (0 === count($data)) {
$this->error('You must export *something*. Use --export-transactions or another option. See docs.firefly-iii.org');
}
$returnCode = 0;
if (!empty($data)) {
if (0 !== count($data)) {
try {
$this->exportData($options, $data);
app('telemetry')->feature('system.command.executed', $this->signature);
@@ -162,8 +162,9 @@ class ExportData extends Command
*/
private function parseOptions(): array
{
$start = $this->getDateParameter('start');
$end = $this->getDateParameter('end');
$start = $this->getDateParameter('start');
$end = $this->getDateParameter('end');
exit;
$accounts = $this->getAccountsParameter();
$export = $this->getExportDirectory();
@@ -199,24 +200,27 @@ class ExportData extends Command
$error = false;
if (null !== $this->option($field)) {
try {
$date = Carbon::createFromFormat('Y-m-d', $this->option($field));
$date = Carbon::createFromFormat('!Y-m-d', $this->option($field));
} catch (InvalidArgumentException $e) {
Log::error($e->getMessage());
$this->error(sprintf('%s date "%s" must be formatted YYYY-MM-DD. Field will be ignored.', $field, $this->option('start')));
$error = true;
}
}
if (false === $error && 'start' === $field) {
if (true === $error && 'start' === $field) {
$journal = $this->journalRepository->firstNull();
$date = null === $journal ? Carbon::now()->subYear() : $journal->date;
$date->startOfDay();
}
if (false === $error && 'end' === $field) {
if (true === $error && 'end' === $field) {
$date = today(config('app.timezone'));
$date->endOfDay();
}
if ('end' === $field) {
$date->endOfDay();
}
// fallback
return $date;
}

View File

@@ -214,14 +214,6 @@ class ApplyRules extends Command
$finalList = new Collection;
$accountList = explode(',', $accountString);
// @codeCoverageIgnoreStart
if (0 === count($accountList)) {
$this->error('Please use the --accounts option to indicate the accounts to apply rules to.');
return false;
}
// @codeCoverageIgnoreEnd
/** @var AccountRepositoryInterface $accountRepository */
$accountRepository = app(AccountRepositoryInterface::class);
$accountRepository->setUser($this->getUser());
@@ -255,12 +247,7 @@ class ApplyRules extends Command
return true;
}
$ruleGroupList = explode(',', $ruleGroupString);
// @codeCoverageIgnoreStart
if (0 === count($ruleGroupList)) {
// can be empty.
return true;
}
// @codeCoverageIgnoreEnd
foreach ($ruleGroupList as $ruleGroupId) {
$ruleGroup = $this->ruleGroupRepository->find((int)$ruleGroupId);
if ($ruleGroup->active) {
@@ -286,14 +273,6 @@ class ApplyRules extends Command
}
$ruleList = explode(',', $ruleString);
// @codeCoverageIgnoreStart
if (0 === count($ruleList)) {
// can be empty.
return true;
}
// @codeCoverageIgnoreEnd
foreach ($ruleList as $ruleId) {
$rule = $this->ruleRepository->find((int)$ruleId);
if (null !== $rule && $rule->active) {

View File

@@ -65,9 +65,8 @@ class Cron extends Command
$date = null;
try {
$date = new Carbon($this->option('date'));
} catch (InvalidArgumentException | Exception $e) {
} catch (InvalidArgumentException $e) {
$this->error(sprintf('"%s" is not a valid date', $this->option('date')));
$e->getMessage();
}
$force = (bool)$this->option('force');
@@ -127,13 +126,15 @@ class Cron extends Command
$recurring->setDate($date);
}
$result = $recurring->fire();
if (false === $result) {
$this->line('The recurring transaction cron job did not fire.');
$recurring->fire();
if($recurring->jobErrored) {
$this->error(sprintf('Error in "create recurring transactions" cron: %s', $recurring->message));
}
if (true === $result) {
$this->line('The recurring transaction cron job fired successfully.');
if($recurring->jobFired) {
$this->error(sprintf('"Create recurring transactions" cron fired: %s', $recurring->message));
}
if($recurring->jobSucceeded) {
$this->error(sprintf('"Create recurring transactions" cron ran with success: %s', $recurring->message));
}
}
@@ -142,7 +143,6 @@ class Cron extends Command
* @param Carbon|null $date
*
* @throws FireflyException
* @throws Exception
*/
private function autoBudgetCronJob(bool $force, ?Carbon $date): void
{
@@ -153,13 +153,16 @@ class Cron extends Command
$autoBudget->setDate($date);
}
$result = $autoBudget->fire();
$autoBudget->fire();
if (false === $result) {
$this->line('The auto budget cron job did not fire.');
if($autoBudget->jobErrored) {
$this->error(sprintf('Error in "create auto budgets" cron: %s', $autoBudget->message));
}
if (true === $result) {
$this->line('The auto budget cron job fired successfully.');
if($autoBudget->jobFired) {
$this->error(sprintf('"Create auto budgets" cron fired: %s', $autoBudget->message));
}
if($autoBudget->jobSucceeded) {
$this->error(sprintf('"Create auto budgets" cron ran with success: %s', $autoBudget->message));
}
}
@@ -167,6 +170,8 @@ class Cron extends Command
/**
* @param bool $force
* @param Carbon|null $date
*
* @throws FireflyException
*/
private function telemetryCronJob(bool $force, ?Carbon $date): void
{
@@ -182,13 +187,16 @@ class Cron extends Command
$telemetry->setDate($date);
}
$result = $telemetry->fire();
$telemetry->fire();
if (false === $result) {
$this->line('The telemetry cron job did not fire.');
if($telemetry->jobErrored) {
$this->error(sprintf('Error in "send telemetry" cron: %s', $telemetry->message));
}
if (true === $result) {
$this->line('The telemetry cron job fired successfully.');
if($telemetry->jobFired) {
$this->error(sprintf('"Send telemetry" cron fired: %s', $telemetry->message));
}
if($telemetry->jobSucceeded) {
$this->error(sprintf('"Send telemetry" cron ran with success: %s', $telemetry->message));
}
}

View File

@@ -114,7 +114,7 @@ class AccountCurrencies extends Command
return (bool)$configVar->data;
}
return false; // @codeCoverageIgnore
return false;
}
/**
@@ -148,7 +148,7 @@ class AccountCurrencies extends Command
}
Log::debug(sprintf('Users currency pref is %s', $defaultCurrencyCode));
/** @var TransactionCurrency $defaultCurrency */
/** @var TransactionCurrency|null $defaultCurrency */
$defaultCurrency = TransactionCurrency::where('code', $defaultCurrencyCode)->first();
if (null === $defaultCurrency) {

View File

@@ -73,11 +73,8 @@ class AppendBudgetLimitPeriods extends Command
private function isExecuted(): bool
{
$configVar = app('fireflyconfig')->get(self::CONFIG_NAME, false);
if (null !== $configVar) {
return (bool)$configVar->data;
}
return false; // @codeCoverageIgnore
return (bool)$configVar->data;
}
/**

View File

@@ -58,7 +58,7 @@ class BackToJournals extends Command
*/
public function handle(): int
{
// @codeCoverageIgnoreStart
$start = microtime(true);
if (!$this->isMigrated()) {
$this->error('Please run firefly-iii:migrate-to-groups first.');
@@ -71,7 +71,7 @@ class BackToJournals extends Command
if (true === $this->option('force')) {
$this->warn('Forcing the command.');
}
// @codeCoverageIgnoreEnd
$this->migrateAll();
$end = round(microtime(true) - $start, 2);
@@ -87,11 +87,8 @@ class BackToJournals extends Command
private function isMigrated(): bool
{
$configVar = app('fireflyconfig')->get(MigrateToGroups::CONFIG_NAME, false);
if (null !== $configVar) {
return (bool)$configVar->data;
}
return false; // @codeCoverageIgnore
return (bool)$configVar->data;
}
/**
@@ -100,11 +97,8 @@ class BackToJournals extends Command
private function isExecuted(): bool
{
$configVar = app('fireflyconfig')->get(self::CONFIG_NAME, false);
if (null !== $configVar) {
return (bool)$configVar->data;
}
return false; // @codeCoverageIgnore
return (bool)$configVar->data;
}
/**
@@ -145,15 +139,13 @@ class BackToJournals extends Command
*/
private function getIdsForBudgets(): array
{
$transactions = DB::table('budget_transaction')->distinct()->get(['transaction_id'])->pluck('transaction_id')->toArray();
$transactions = DB::table('budget_transaction')->distinct()->get(['transaction_id'])->pluck('transaction_id')->toArray(); // @phpstan-ignore-line
$array = [];
$chunks = array_chunk($transactions, 500);
foreach ($chunks as $chunk) {
$set = DB::table('transactions')
->whereIn('transactions.id', $chunk)
$set = DB::table('transactions')->whereIn('transactions.id', $chunk)
->get(['transaction_journal_id'])->pluck('transaction_journal_id')->toArray();
/** @noinspection SlowArrayOperationsInLoopInspection */
$array = array_merge($array, $set);
}
@@ -170,11 +162,11 @@ class BackToJournals extends Command
/** @var Transaction $transaction */
$transaction = $journal->transactions->first();
if (null === $transaction) {
// @codeCoverageIgnoreStart
$this->info(sprintf('Transaction journal #%d has no transactions. Will be fixed later.', $journal->id));
return;
// @codeCoverageIgnoreEnd
}
/** @var Budget $budget */
$budget = $transaction->budgets->first();
@@ -225,12 +217,12 @@ class BackToJournals extends Command
*/
private function getIdsForCategories(): array
{
$transactions = DB::table('category_transaction')->distinct()->get(['transaction_id'])->pluck('transaction_id')->toArray();
$transactions = DB::table('category_transaction')->distinct()->get(['transaction_id'])->pluck('transaction_id')->toArray(); // @phpstan-ignore-line
$array = [];
$chunks = array_chunk($transactions, 500);
foreach ($chunks as $chunk) {
$set = DB::table('transactions')
$set = DB::table('transactions') // @phpstan-ignore-line
->whereIn('transactions.id', $chunk)
->get(['transaction_journal_id'])->pluck('transaction_journal_id')->toArray();
/** @noinspection SlowArrayOperationsInLoopInspection */
@@ -249,11 +241,11 @@ class BackToJournals extends Command
/** @var Transaction $transaction */
$transaction = $journal->transactions->first();
if (null === $transaction) {
// @codeCoverageIgnoreStart
$this->info(sprintf('Transaction journal #%d has no transactions. Will be fixed later.', $journal->id));
return;
// @codeCoverageIgnoreEnd
}
/** @var Category $category */
$category = $transaction->categories->first();

View File

@@ -54,13 +54,13 @@ class BudgetLimitCurrency extends Command
public function handle(): int
{
$start = microtime(true);
// @codeCoverageIgnoreStart
if ($this->isExecuted() && true !== $this->option('force')) {
$this->warn('This command has already been executed.');
return 0;
}
// @codeCoverageIgnoreEnd
$count = 0;
$budgetLimits = BudgetLimit::get();
@@ -104,7 +104,7 @@ class BudgetLimitCurrency extends Command
return (bool)$configVar->data;
}
return false; // @codeCoverageIgnore
return false;
}
/**

View File

@@ -56,13 +56,13 @@ class CCLiabilities extends Command
{
$start = microtime(true);
// @codeCoverageIgnoreStart
if ($this->isExecuted() && true !== $this->option('force')) {
$this->warn('This command has already been executed.');
return 0;
}
// @codeCoverageIgnoreEnd
$ccType = AccountType::where('type', AccountType::CREDITCARD)->first();
$debtType = AccountType::where('type', AccountType::DEBT)->first();
@@ -101,7 +101,7 @@ class CCLiabilities extends Command
return (bool)$configVar->data;
}
return false; // @codeCoverageIgnore
return false;
}
/**

View File

@@ -54,14 +54,14 @@ class MigrateAttachments extends Command
*/
public function handle(): int
{
// @codeCoverageIgnoreStart
$start = microtime(true);
if ($this->isExecuted() && true !== $this->option('force')) {
$this->warn('This command has already been executed.');
return 0;
}
// @codeCoverageIgnoreEnd
$attachments = Attachment::get();
$count = 0;
@@ -113,7 +113,7 @@ class MigrateAttachments extends Command
return (bool)$configVar->data;
}
return false; // @codeCoverageIgnore
return false;
}
/**

View File

@@ -56,13 +56,13 @@ class MigrateJournalNotes extends Command
public function handle(): int
{
$start = microtime(true);
// @codeCoverageIgnoreStart
if ($this->isExecuted() && true !== $this->option('force')) {
$this->warn('This command has already been executed.');
return 0;
}
// @codeCoverageIgnoreEnd
$count = 0;
/** @noinspection PhpUndefinedMethodInspection */
$set = TransactionJournalMeta::whereName('notes')->get();
@@ -80,11 +80,11 @@ class MigrateJournalNotes extends Command
Log::debug(sprintf('Migrated meta note #%d to Note #%d', $meta->id, $note->id));
try {
$meta->delete();
// @codeCoverageIgnoreStart
} catch (Exception $e) {
} catch (Exception $e) { // @phpstan-ignore-line
Log::error(sprintf('Could not delete old meta entry #%d: %s', $meta->id, $e->getMessage()));
}
// @codeCoverageIgnoreEnd
$count++;
}
@@ -112,7 +112,7 @@ class MigrateJournalNotes extends Command
return (bool)$configVar->data;
}
return false; // @codeCoverageIgnore
return false;
}
/**

View File

@@ -87,7 +87,7 @@ class MigrateRecurrenceMeta extends Command
return (bool)$configVar->data;
}
return false; // @codeCoverageIgnore
return false;
}
/**

View File

@@ -82,7 +82,7 @@ class MigrateRecurrenceType extends Command
return (bool)$configVar->data;
}
return false; // @codeCoverageIgnore
return false;
}
/**

View File

@@ -80,7 +80,7 @@ class MigrateTagLocations extends Command
return (bool)$configVar->data;
}
return false; // @codeCoverageIgnore
return false;
}
private function migrateTagLocations(): void

View File

@@ -75,7 +75,7 @@ class MigrateToGroups extends Command
{
$this->stupidLaravel();
$start = microtime(true);
// @codeCoverageIgnoreStart
if ($this->isMigrated() && true !== $this->option('force')) {
$this->info('Database already seems to be migrated.');
@@ -85,7 +85,7 @@ class MigrateToGroups extends Command
if (true === $this->option('force')) {
$this->warn('Forcing the migration.');
}
// @codeCoverageIgnoreEnd
Log::debug('---- start group migration ----');
$this->makeGroupsFromSplitJournals();
@@ -135,7 +135,7 @@ class MigrateToGroups extends Command
return (bool)$configVar->data;
}
return false; // @codeCoverageIgnore
return false;
}
/**
@@ -165,11 +165,11 @@ class MigrateToGroups extends Command
{
// double check transaction count.
if ($journal->transactions->count() <= 2) {
// @codeCoverageIgnoreStart
Log::debug(sprintf('Will not try to convert journal #%d because it has 2 or less transactions.', $journal->id));
return;
// @codeCoverageIgnoreEnd
}
Log::debug(sprintf('Will now try to convert journal #%d', $journal->id));
@@ -217,7 +217,7 @@ class MigrateToGroups extends Command
$opposingTr = $this->findOpposingTransaction($journal, $transaction);
if (null === $opposingTr) {
// @codeCoverageIgnoreStart
$this->error(
sprintf(
'Journal #%d has no opposing transaction for transaction #%d. Cannot upgrade this entry.',
@@ -226,7 +226,7 @@ class MigrateToGroups extends Command
)
);
continue;
// @codeCoverageIgnoreEnd
}
// overrule journal category with transaction category.

View File

@@ -73,13 +73,13 @@ class MigrateToRules extends Command
$this->stupidLaravel();
$start = microtime(true);
// @codeCoverageIgnoreStart
if ($this->isExecuted() && true !== $this->option('force')) {
$this->warn('This command has already been executed.');
return 0;
}
// @codeCoverageIgnoreEnd
$users = $this->userRepository->all();
/** @var User $user */
@@ -127,7 +127,7 @@ class MigrateToRules extends Command
return (bool)$configVar->data;
}
return false; // @codeCoverageIgnore
return false;
}
/**

View File

@@ -75,13 +75,13 @@ class OtherCurrenciesCorrections extends Command
{
$this->stupidLaravel();
$start = microtime(true);
// @codeCoverageIgnoreStart
if ($this->isExecuted() && true !== $this->option('force')) {
$this->warn('This command has already been executed.');
return 0;
}
// @codeCoverageIgnoreEnd
$this->updateOtherJournalsCurrencies();
$this->markAsExecuted();
@@ -120,7 +120,7 @@ class OtherCurrenciesCorrections extends Command
return (bool)$configVar->data;
}
return false; // @codeCoverageIgnore
return false;
}
/**
@@ -154,18 +154,18 @@ class OtherCurrenciesCorrections extends Command
$leadTransaction = $this->getLeadTransaction($journal);
if (null === $leadTransaction) {
// @codeCoverageIgnoreStart
$this->error(sprintf('Could not reliably determine which transaction is in the lead for transaction journal #%d.', $journal->id));
return;
// @codeCoverageIgnoreEnd
}
/** @var Account $account */
$account = $leadTransaction->account;
$currency = $this->getCurrency($account);
if (null === $currency) {
// @codeCoverageIgnoreStart
$this->error(
sprintf(
'Account #%d ("%s") has no currency preference, so transaction journal #%d can\'t be corrected', $account->id, $account->name, $journal->id
@@ -174,7 +174,7 @@ class OtherCurrenciesCorrections extends Command
$this->count++;
return;
// @codeCoverageIgnoreEnd
}
// fix each transaction:
$journal->transactions->each(
@@ -246,18 +246,18 @@ class OtherCurrenciesCorrections extends Command
{
$accountId = $account->id;
if (array_key_exists($accountId, $this->accountCurrencies) && 0 === $this->accountCurrencies[$accountId]) {
return null; // @codeCoverageIgnore
return null;
}
if (array_key_exists($accountId, $this->accountCurrencies) && $this->accountCurrencies[$accountId] instanceof TransactionCurrency) {
return $this->accountCurrencies[$accountId]; // @codeCoverageIgnore
return $this->accountCurrencies[$accountId];
}
$currency = $this->accountRepos->getAccountCurrency($account);
if (null === $currency) {
// @codeCoverageIgnoreStart
$this->accountCurrencies[$accountId] = 0;
return null;
// @codeCoverageIgnoreEnd
}
$this->accountCurrencies[$accountId] = $currency;

View File

@@ -53,13 +53,13 @@ class RenameAccountMeta extends Command
public function handle(): int
{
$start = microtime(true);
// @codeCoverageIgnoreStart
if ($this->isExecuted() && true !== $this->option('force')) {
$this->warn('This command has already been executed.');
return 0;
}
// @codeCoverageIgnoreEnd
$array = [
'accountRole' => 'account_role',
'ccType' => 'cc_type',
@@ -104,7 +104,7 @@ class RenameAccountMeta extends Command
return (bool)$configVar->data;
}
return false; // @codeCoverageIgnore
return false;
}
/**

View File

@@ -72,7 +72,7 @@ class TransactionIdentifier extends Command
{
$this->stupidLaravel();
$start = microtime(true);
// @codeCoverageIgnoreStart
if ($this->isExecuted() && true !== $this->option('force')) {
$this->warn('This command has already been executed.');
@@ -83,7 +83,7 @@ class TransactionIdentifier extends Command
if (!Schema::hasTable('transaction_journals')) {
return 0;
}
// @codeCoverageIgnoreEnd
$journals = $this->cliRepository->getSplitJournals();
/** @var TransactionJournal $journal */
foreach ($journals as $journal) {
@@ -128,7 +128,7 @@ class TransactionIdentifier extends Command
return (bool)$configVar->data;
}
return false; // @codeCoverageIgnore
return false;
}
/**
@@ -178,7 +178,7 @@ class TransactionIdentifier extends Command
->where('amount', $amount)->where('identifier', '=', 0)
->whereNotIn('id', $exclude)
->first();
// @codeCoverageIgnoreStart
} catch (QueryException $e) {
Log::error($e->getMessage());
$this->error('Firefly III could not find the "identifier" field in the "transactions" table.');
@@ -188,9 +188,6 @@ class TransactionIdentifier extends Command
return null;
}
// @codeCoverageIgnoreEnd
return $opposing;
}

View File

@@ -72,13 +72,13 @@ class TransferCurrenciesCorrections extends Command
{
$this->stupidLaravel();
$start = microtime(true);
// @codeCoverageIgnoreStart
if ($this->isExecuted() && true !== $this->option('force')) {
$this->warn('This command has already been executed.');
return 0;
}
// @codeCoverageIgnoreEnd
$this->startUpdateRoutine();
$this->markAsExecuted();
@@ -140,7 +140,7 @@ class TransferCurrenciesCorrections extends Command
return (bool)$configVar->data;
}
return false; // @codeCoverageIgnore
return false;
}
/**
@@ -167,27 +167,27 @@ class TransferCurrenciesCorrections extends Command
{
$this->resetInformation();
// @codeCoverageIgnoreStart
if ($this->isSplitJournal($transfer)) {
$this->line(sprintf(sprintf('Transaction journal #%d is a split journal. Cannot continue.', $transfer->id)));
return;
}
// @codeCoverageIgnoreEnd
$this->getSourceInformation($transfer);
$this->getDestinationInformation($transfer);
// unexpectedly, either one is null:
// @codeCoverageIgnoreStart
if ($this->isEmptyTransactions()) {
$this->error(sprintf('Source or destination information for transaction journal #%d is null. Cannot fix this one.', $transfer->id));
return;
}
// @codeCoverageIgnoreEnd
// both accounts must have currency preference:
// @codeCoverageIgnoreStart
if ($this->isNoCurrencyPresent()) {
$this->error(
sprintf('Source or destination accounts for transaction journal #%d have no currency information. Cannot fix this one.', $transfer->id)
@@ -195,7 +195,7 @@ class TransferCurrenciesCorrections extends Command
return;
}
// @codeCoverageIgnoreEnd
// fix source transaction having no currency.
$this->fixSourceNoCurrency();
@@ -270,18 +270,18 @@ class TransferCurrenciesCorrections extends Command
{
$accountId = $account->id;
if (array_key_exists($accountId, $this->accountCurrencies) && 0 === $this->accountCurrencies[$accountId]) {
return null; // @codeCoverageIgnore
return null;
}
if (array_key_exists($accountId, $this->accountCurrencies) && $this->accountCurrencies[$accountId] instanceof TransactionCurrency) {
return $this->accountCurrencies[$accountId]; // @codeCoverageIgnore
return $this->accountCurrencies[$accountId];
}
$currency = $this->accountRepos->getAccountCurrency($account);
if (null === $currency) {
// @codeCoverageIgnoreStart
$this->accountCurrencies[$accountId] = 0;
return null;
// @codeCoverageIgnoreEnd
}
$this->accountCurrencies[$accountId] = $currency;

View File

@@ -56,7 +56,7 @@ class UpgradeSkeleton extends Command
return (bool)$configVar->data;
}
return false; // @codeCoverageIgnore
return false;
}

View File

@@ -73,7 +73,7 @@ class UpgradeFireflyInstructions extends Command
try {
app('telemetry')->feature('system.users.count', (string)User::count());
} catch (QueryException $e) {
// ignore error.
// @ignoreException
}
return 0;

View File

@@ -27,14 +27,17 @@ declare(strict_types=1);
namespace FireflyIII\Exceptions;
use ErrorException;
use Exception;
use FireflyIII\Jobs\MailError;
use Illuminate\Auth\AuthenticationException;
use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
use Illuminate\Http\Request;
use Illuminate\Session\TokenMismatchException;
use Illuminate\Support\Arr;
use Illuminate\Validation\ValidationException as LaravelValidationException;
use League\OAuth2\Server\Exception\OAuthServerException;
use Laravel\Passport\Exceptions\OAuthServerException as LaravelOAuthException;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Symfony\Component\HttpKernel\Exception\HttpException;
use Throwable;
/**
@@ -44,33 +47,47 @@ use Throwable;
*/
class Handler extends ExceptionHandler
{
/**
* @var array
*/
protected $dontReport
= [
AuthenticationException::class,
LaravelValidationException::class,
NotFoundHttpException::class,
OAuthServerException::class,
LaravelOAuthException::class,
TokenMismatchException::class,
HttpException::class
];
/**
* Render an exception into an HTTP response.
*
* @param Request $request
* @param Exception $exception
* @param Throwable $e
*
* @return mixed
*/
public function render($request, Throwable $exception)
public function render($request, Throwable $e)
{
if ($exception instanceof LaravelValidationException && $request->expectsJson()) {
if ($e instanceof LaravelValidationException && $request->expectsJson()) {
// ignore it: controller will handle it.
return parent::render($request, $exception);
return parent::render($request, $e);
}
if ($exception instanceof NotFoundHttpException && $request->expectsJson()) {
if ($e instanceof NotFoundHttpException && $request->expectsJson()) {
// JSON error:
return response()->json(['message' => 'Resource not found', 'exception' => 'NotFoundHttpException'], 404);
}
if ($exception instanceof AuthenticationException && $request->expectsJson()) {
if ($e instanceof AuthenticationException && $request->expectsJson()) {
// somehow Laravel handler does not catch this:
return response()->json(['message' => 'Unauthenticated', 'exception' => 'AuthenticationException'], 401);
}
if ($exception instanceof OAuthServerException && $request->expectsJson()) {
if ($e instanceof OAuthServerException && $request->expectsJson()) {
// somehow Laravel handler does not catch this:
return response()->json(['message' => $exception->getMessage(), 'exception' => 'OAuthServerException'], 401);
return response()->json(['message' => $e->getMessage(), 'exception' => 'OAuthServerException'], 401);
}
if ($request->expectsJson()) {
@@ -78,33 +95,33 @@ class Handler extends ExceptionHandler
if ($isDebug) {
return response()->json(
[
'message' => $exception->getMessage(),
'exception' => get_class($exception),
'line' => $exception->getLine(),
'file' => $exception->getFile(),
'trace' => $exception->getTrace(),
'message' => $e->getMessage(),
'exception' => get_class($e),
'line' => $e->getLine(),
'file' => $e->getFile(),
'trace' => $e->getTrace(),
],
500
);
}
return response()->json(
['message' => sprintf('Internal Firefly III Exception: %s', $exception->getMessage()), 'exception' => get_class($exception)], 500
['message' => sprintf('Internal Firefly III Exception: %s', $e->getMessage()), 'exception' => get_class($e)], 500
);
}
if ($exception instanceof NotFoundHttpException) {
if ($e instanceof NotFoundHttpException) {
$handler = app(GracefulNotFoundHandler::class);
return $handler->render($request, $exception);
return $handler->render($request, $e);
}
if ($exception instanceof FireflyException || $exception instanceof ErrorException || $exception instanceof OAuthServerException) {
if ($e instanceof FireflyException || $e instanceof ErrorException || $e instanceof OAuthServerException) {
$isDebug = config('app.debug');
return response()->view('errors.FireflyException', ['exception' => $exception, 'debug' => $isDebug], 500);
return response()->view('errors.FireflyException', ['exception' => $e, 'debug' => $isDebug], 500);
}
return parent::render($request, $exception);
return parent::render($request, $e);
}
/**
@@ -112,49 +129,63 @@ class Handler extends ExceptionHandler
*
* This is a great spot to send exceptions to Sentry etc.
*
* // it's five its fine.
*
* @param Exception $exception
* @param Throwable $e
*
* @return void
* @throws Exception
* @throws Throwable
*
*/
public function report(Throwable $exception)
public function report(Throwable $e)
{
$doMailError = config('firefly.send_error_message');
// if the user wants us to mail:
if (true === $doMailError
// and if is one of these error instances
&& ($exception instanceof FireflyException || $exception instanceof ErrorException)) {
$userData = [
'id' => 0,
'email' => 'unknown@example.com',
];
if (auth()->check()) {
$userData['id'] = auth()->user()->id;
$userData['email'] = auth()->user()->email;
}
$data = [
'class' => get_class($exception),
'errorMessage' => $exception->getMessage(),
'time' => date('r'),
'stackTrace' => $exception->getTraceAsString(),
'file' => $exception->getFile(),
'line' => $exception->getLine(),
'code' => $exception->getCode(),
'version' => config('firefly.version'),
'url' => request()->fullUrl(),
'userAgent' => request()->userAgent(),
'json' => request()->acceptsJson(),
];
if ($this->shouldntReportLocal($e) || !$doMailError) {
parent::report($e);
// create job that will mail.
$ipAddress = request()->ip() ?? '0.0.0.0';
$job = new MailError($userData, (string)config('firefly.site_owner'), $ipAddress, $data);
dispatch($job);
return;
}
$userData = [
'id' => 0,
'email' => 'unknown@example.com',
];
if (auth()->check()) {
$userData['id'] = auth()->user()->id;
$userData['email'] = auth()->user()->email;
}
$data = [
'class' => get_class($e),
'errorMessage' => $e->getMessage(),
'time' => date('r'),
'stackTrace' => $e->getTraceAsString(),
'file' => $e->getFile(),
'line' => $e->getLine(),
'code' => $e->getCode(),
'version' => config('firefly.version'),
'url' => request()->fullUrl(),
'userAgent' => request()->userAgent(),
'json' => request()->acceptsJson(),
];
parent::report($exception);
// create job that will mail.
$ipAddress = request()->ip() ?? '0.0.0.0';
$job = new MailError($userData, (string)config('firefly.site_owner'), $ipAddress, $data);
dispatch($job);
parent::report($e);
}
/**
* @param Throwable $e
*
* @return bool
*/
private function shouldntReportLocal(Throwable $e): bool
{
return !is_null(
Arr::first(
$this->dontReport, function ($type) use ($e) {
return $e instanceof $type;
}
)
);
}
}

View File

@@ -57,12 +57,11 @@ class AccountFactory
*/
public function __construct()
{
$this->canHaveVirtual = [AccountType::ASSET, AccountType::DEBT, AccountType::LOAN, AccountType::MORTGAGE, AccountType::CREDITCARD];
$this->accountRepository = app(AccountRepositoryInterface::class);
$this->validAssetFields = ['account_role', 'account_number', 'currency_id', 'BIC', 'include_net_worth'];
$this->validCCFields = ['account_role', 'cc_monthly_payment_date', 'cc_type', 'account_number', 'currency_id', 'BIC', 'include_net_worth'];
$this->validFields = ['account_number', 'currency_id', 'BIC', 'interest', 'interest_period', 'include_net_worth'];
$this->canHaveVirtual = config('firefly.can_have_virtual_amounts');
$this->validAssetFields = config('firefly.valid_asset_fields');
$this->validCCFields = config('firefly.valid_cc_fields');
$this->validFields = config('firefly.valid_account_fields');
}
/**
@@ -74,16 +73,26 @@ class AccountFactory
*/
public function findOrCreate(string $accountName, string $accountType): Account
{
Log::debug(sprintf('Searching for "%s" of type "%s"', $accountName, $accountType));
/** @var AccountType $type */
$type = AccountType::whereType($accountType)->first();
Log::debug(sprintf('findOrCreate("%s", "%s")', $accountName, $accountType));
$type = $this->accountRepository->getAccountTypeByType($accountType);
if (null === $type) {
throw new FireflyException(sprintf('Cannot find account type "%s"', $accountType));
}
$return = $this->user->accounts->where('account_type_id', $type->id)->where('name', $accountName)->first();
if (null === $return) {
Log::debug('Found nothing. Will create a new one.');
$return = $this->create(
['user_id' => $this->user->id, 'name' => $accountName, 'account_type_id' => $type->id, 'account_type' => null, 'virtual_balance' => '0',
'iban' => null, 'active' => true,]
[
'user_id' => $this->user->id,
'name' => $accountName,
'account_type_id' => $type->id,
'account_type_name' => null,
'virtual_balance' => '0',
'iban' => null,
'active' => true,
]
);
}
@@ -98,118 +107,51 @@ class AccountFactory
*/
public function create(array $data): Account
{
$type = $this->getAccountType($data['account_type_id'] ?? null, $data['account_type'] ?? null);
if (null === $type) {
throw new FireflyException(
sprintf('AccountFactory::create() was unable to find account type #%d ("%s").', $data['account_type_id'] ?? null, $data['account_type'] ?? null)
);
}
$type = $this->getAccountType($data);
$data['iban'] = $this->filterIban($data['iban'] ?? null);
// account may exist already:
Log::debug('Data array is as follows', $data);
$return = $this->find($data['name'], $type->type);
if (null === $return) {
$this->accountRepository->resetAccountOrder();
// create it:
$databaseData = ['user_id' => $this->user->id,
'account_type_id' => $type->id,
'name' => $data['name'],
'order' => 25000,
'virtual_balance' => $data['virtual_balance'] ?? null, 'active' => true === $data['active'], 'iban' => $data['iban'],];
$currency = $this->getCurrency((int)($data['currency_id'] ?? null), (string)($data['currency_code'] ?? null));
unset($data['currency_code']);
$data['currency_id'] = $currency->id;
// remove virtual balance when not an asset account or a liability
if (!in_array($type->type, $this->canHaveVirtual, true)) {
$databaseData['virtual_balance'] = null;
}
// fix virtual balance when it's empty
if ('' === (string)$databaseData['virtual_balance']) {
$databaseData['virtual_balance'] = null;
}
$return = Account::create($databaseData);
$this->updateMetaData($return, $data);
// if it can have a virtual balance, it can also have an opening balance.
if (in_array($type->type, $this->canHaveVirtual, true)) {
if ($this->validOBData($data)) {
$this->updateOBGroup($return, $data);
}
if (!$this->validOBData($data)) {
$this->deleteOBGroup($return);
}
}
$this->updateNote($return, $data['notes'] ?? '');
// store location
$this->storeNewLocation($return, $data);
// update order to be correct:
// set new order:
$maxOrder = $this->accountRepository->maxOrder($type->type);
$order = null;
if (!array_key_exists('order', $data)) {
// take maxOrder + 1
$order = $maxOrder + 1;
}
if (array_key_exists('order', $data)) {
// limit order
$order = (int)($data['order'] > $maxOrder ? $maxOrder + 1 : $data['order']);
$order = 0 === $order ? $maxOrder + 1 : $order;
}
$updateService = app(AccountUpdateService::class);
$updateService->setUser($return->user);
Log::debug(sprintf('Will set order to %d', $order));
$return = $updateService->update($return, ['order' => $order]);
$return = $this->createAccount($type, $data);
}
return $return;
}
/**
* @param int|null $accountTypeId
* @param null|string $accountType
* @param array $data
*
* @return AccountType|null
*/
protected function getAccountType(?int $accountTypeId, ?string $accountType): ?AccountType
protected function getAccountType(array $data): ?AccountType
{
$accountTypeId = (int)$accountTypeId;
$result = null;
$accountTypeId = array_key_exists('account_type_id', $data) ? (int)$data['account_type_id'] : 0;
$accountTypeName = array_key_exists('account_type_name', $data) ? $data['account_type_name'] : null;
$result = null;
// find by name or ID
if ($accountTypeId > 0) {
$result = AccountType::find($accountTypeId);
}
if (null !== $accountTypeName) {
$result = $this->accountRepository->getAccountTypeByType($accountTypeName);
}
// try with type:
if (null === $result) {
Log::debug(sprintf('No account type found by ID, continue search for "%s".', $accountType));
/** @var array $types */
$types = config('firefly.accountTypeByIdentifier.' . $accountType) ?? [];
$types = config(sprintf('firefly.accountTypeByIdentifier.%s', $accountTypeName)) ?? [];
if (count($types) > 0) {
Log::debug(sprintf('%d accounts in list from config', count($types)), $types);
$result = AccountType::whereIn('type', $types)->first();
}
if (null === $result && null !== $accountType) {
// try as full name:
$result = AccountType::whereType($accountType)->first();
}
}
if (null === $result) {
Log::warning(sprintf('Found NO account type based on %d and "%s"', $accountTypeId, $accountType));
}
if (null !== $result) {
Log::debug(sprintf('Found account type based on %d and "%s": "%s"', $accountTypeId, $accountType, $result->type));
Log::warning(sprintf('Found NO account type based on %d and "%s"', $accountTypeId, $accountTypeName));
throw new FireflyException(sprintf('AccountFactory::create() was unable to find account type #%d ("%s").', $accountTypeId, $accountTypeName));
}
Log::debug(sprintf('Found account type based on %d and "%s": "%s"', $accountTypeId, $accountTypeName, $result->type));
return $result;
}
/**
@@ -225,11 +167,168 @@ class AccountFactory
return $this->user->accounts()->where('account_type_id', $type->id)->where('name', $accountName)->first();
}
/**
* @param array $data
*
* @return Account
*/
private function createAccount(AccountType $type, array $data): Account
{
$this->accountRepository->resetAccountOrder();
// create it:
$virtualBalance = array_key_exists('virtual_balance', $data) ? $data['virtual_balance'] : null;
$active = array_key_exists('active', $data) ? $data['active'] : true;
$databaseData = ['user_id' => $this->user->id,
'account_type_id' => $type->id,
'name' => $data['name'],
'order' => 25000,
'virtual_balance' => $virtualBalance,
'active' => $active,
'iban' => $data['iban'],
];
// fix virtual balance when it's empty
if ('' === (string)$databaseData['virtual_balance']) {
$databaseData['virtual_balance'] = null;
}
// remove virtual balance when not an asset account or a liability
if (!in_array($type->type, $this->canHaveVirtual, true)) {
$databaseData['virtual_balance'] = null;
}
// create account!
$account = Account::create($databaseData);
// update meta data:
$data = $this->cleanMetaDataArray($account, $data);
$this->storeMetaData($account, $data);
// create opening balance
$this->storeOpeningBalance($account, $data);
// create notes
$notes = array_key_exists('notes', $data) ? $data['notes'] : '';
$this->updateNote($account, $notes);
// create location
$this->storeNewLocation($account, $data);
// set order
$this->storeOrder($account, $data);
// refresh and return
$account->refresh();
return $account;
}
/**
* @param Account $account
* @param array $data
*
* @return array
*/
private function cleanMetaDataArray(Account $account, array $data): array
{
$currencyId = array_key_exists('currency_id', $data) ? (int)$data['currency_id'] : 0;
$currencyCode = array_key_exists('currency_code', $data) ? (string)$data['currency_code'] : '';
$accountRole = array_key_exists('account_role', $data) ? (string)$data['account_role'] : null;
$currency = $this->getCurrency($currencyId, $currencyCode);
// only asset account may have a role:
if ($account->accountType->type !== AccountType::ASSET) {
$accountRole = '';
}
$data['account_role'] = $accountRole;
$data['currency_id'] = $currency->id;
return $data;
}
/**
* @param Account $account
* @param array $data
*/
private function storeMetaData(Account $account, array $data): void
{
$fields = $this->validFields;
if ($account->accountType->type === AccountType::ASSET) {
$fields = $this->validAssetFields;
}
if ($account->accountType->type === AccountType::ASSET && 'ccAsset' === $data['account_role']) {
$fields = $this->validCCFields;
}
/** @var AccountMetaFactory $factory */
$factory = app(AccountMetaFactory::class);
foreach ($fields as $field) {
// if the field is set but NULL, skip it.
// if the field is set but "", update it.
if (array_key_exists($field, $data) && null !== $data[$field]) {
// convert boolean value:
if (is_bool($data[$field]) && false === $data[$field]) {
$data[$field] = 0;
}
if (is_bool($data[$field]) && true === $data[$field]) {
$data[$field] = 1;
}
$factory->crud($account, $field, (string)$data[$field]);
}
}
}
/**
* @param Account $account
* @param array $data
*/
private function storeOpeningBalance(Account $account, array $data)
{
$accountType = $account->accountType->type;
// if it can have a virtual balance, it can also have an opening balance.
if (in_array($accountType, $this->canHaveVirtual, true)) {
if ($this->validOBData($data)) {
$this->updateOBGroup($account, $data);
}
if (!$this->validOBData($data)) {
$this->deleteOBGroup($account);
}
}
}
/**
* @param Account $account
* @param array $data
*/
private function storeOrder(Account $account, array $data): void
{
$accountType = $account->accountType->type;
$maxOrder = $this->accountRepository->maxOrder($accountType);
$order = null;
if (!array_key_exists('order', $data)) {
$order = $maxOrder + 1;
}
if (array_key_exists('order', $data)) {
$order = (int)($data['order'] > $maxOrder ? $maxOrder + 1 : $data['order']);
$order = 0 === $order ? $maxOrder + 1 : $order;
}
$updateService = app(AccountUpdateService::class);
$updateService->setUser($account->user);
$updateService->update($account, ['order' => $order]);
}
/**
* @param User $user
*/
public function setUser(User $user): void
{
$this->user = $user;
$this->accountRepository->setUser($user);
}
}

View File

@@ -67,8 +67,8 @@ class AccountMetaFactory
if ('' === $value && null !== $entry) {
try {
$entry->delete();
} catch (Exception $e) { // @codeCoverageIgnore
Log::debug(sprintf('Could not delete entry: %s', $e->getMessage())); // @codeCoverageIgnore
} catch (Exception $e) { // @phpstan-ignore-line
Log::debug(sprintf('Could not delete entry: %s', $e->getMessage()));
}
return null;

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