Compare commits

..

31 Commits

Author SHA1 Message Date
github-actions
5e15747a5b Auto commit for release 'develop' on 2025-01-26 2025-01-26 14:33:19 +01:00
James Cole
8a6eaad2bb Fix vite 2025-01-26 14:29:11 +01:00
James Cole
5ab52d9f66 Fix vite 2025-01-26 14:26:17 +01:00
James Cole
21a327bf08 Merge branch 'main' into develop 2025-01-26 14:10:30 +01:00
James Cole
15dd175394 Add date [skip ci] 2025-01-26 14:10:09 +01:00
James Cole
3f35305beb Update changelog. 2025-01-26 14:09:49 +01:00
James Cole
768d8b1515 Fix currency exchange rates 2025-01-26 10:09:09 +01:00
James Cole
1c19428a12 Catch API endpoint errors. 2025-01-26 07:44:41 +01:00
James Cole
c204533195 Fix various API 500 errors. 2025-01-26 06:30:38 +01:00
James Cole
6d89485792 Fix endpoints, validate dates. 2025-01-25 09:17:21 +01:00
James Cole
949d818bad Cleanup code. 2025-01-25 04:51:09 +01:00
James Cole
a12e200a0a Put query count in debug header 2025-01-25 04:50:36 +01:00
James Cole
b4039b1f13 Report if the version is a dev version 2025-01-25 04:50:26 +01:00
James Cole
32921e15b1 Remove errors from handler 2025-01-25 04:50:15 +01:00
James Cole
4f7cc7d53b More strict date validation 2025-01-25 04:49:28 +01:00
James Cole
0986bfbc34 Rename warnings to notifications 2025-01-25 04:49:08 +01:00
James Cole
663202bfc6 Return correct headers 2025-01-25 04:48:51 +01:00
James Cole
6f63ddf5b0 [chore] Fix https://github.com/firefly-iii/firefly-iii/issues/9683 and rename default to native. 2025-01-22 05:24:12 +01:00
James Cole
a9805b144a Merge pull request #9684 from firefly-iii/dependabot/npm_and_yarn/npm_and_yarn-545022be4d 2025-01-22 04:37:48 +01:00
dependabot[bot]
e1b8b9b3ae Bump vite in the npm_and_yarn group across 1 directory
Bumps the npm_and_yarn group with 1 update in the / directory: [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite).


Updates `vite` from 6.0.7 to 6.0.9
- [Release notes](https://github.com/vitejs/vite/releases)
- [Changelog](https://github.com/vitejs/vite/blob/main/packages/vite/CHANGELOG.md)
- [Commits](https://github.com/vitejs/vite/commits/v6.0.9/packages/vite)

---
updated-dependencies:
- dependency-name: vite
  dependency-type: direct:development
  dependency-group: npm_and_yarn
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-01-21 21:02:17 +00:00
James Cole
d57327fd11 [chore] various code cleanup. 2025-01-21 06:34:39 +01:00
github-actions
15ac69bfad Auto commit for release 'develop' on 2025-01-20 2025-01-20 04:08:13 +01:00
github-actions
a5bd28f8d4 Auto commit for release 'develop' on 2025-01-19 2025-01-19 19:26:58 +01:00
github-actions
b2516ca1b4 Auto commit for release 'v6.2.0-alpha.2' on 2025-01-19 2025-01-19 19:12:01 +01:00
James Cole
053b46ae63 [chore] fix phpstan errors. 2025-01-19 19:07:19 +01:00
James Cole
6e836aceec Expand changelog. 2025-01-19 18:55:03 +01:00
James Cole
0e8bcd2e79 [chore] cod cleanup 2025-01-19 18:53:32 +01:00
James Cole
bd1f8b2497 [chore] Move to native from default. [skip ci] 2025-01-19 11:54:40 +01:00
James Cole
19dfcf7139 Merge branch 'develop' of github.com:firefly-iii/firefly-iii into develop
# Conflicts:
#	app/Transformers/CurrencyTransformer.php
#	app/Transformers/V2/CurrencyTransformer.php
2025-01-19 11:48:18 +01:00
James Cole
ef7a3287bb Add info to changelog 2025-01-19 11:47:49 +01:00
James Cole
2900049498 Add default 2025-01-19 11:47:41 +01:00
162 changed files with 1204 additions and 1003 deletions

View File

@@ -16,6 +16,9 @@ parameters:
- '#Dynamic call to static method#' # all the Laravel ORM things depend on this.
- identifier: varTag.nativeType
- identifier: varTag.type
-
identifier: larastan.noEnvCallsOutsideOfConfig
path: ../app/Console/Commands/System/CreatesDatabase.php
- identifier: missingType.iterableValue # not interesting enough to fix.
- identifier: missingType.generics # not interesting enough to fix.
- "#Parameter \\#[1-2] \\$num[1-2] of function bc[a-z]+ expects numeric-string, [a-z\\-|&]+ given#"
@@ -28,49 +31,6 @@ parameters:
- '#Call to an undefined method Illuminate\\Database\\Eloquent\\Relations\\HasMany::withTrashed#'
- '#Call to an undefined method Illuminate\\Database\\Eloquent\\Relations\\HasMany::accountTypeIn#'
- '#Call to an undefined method Illuminate\\Database\\Eloquent\\Relations\\BelongsTo::withTrashed#'
# - '#Control structures using switch should not be used.#' # switch is fine in some cases.
# - '#with no value type specified in iterable type array#' # remove this rule when all other issues are solved.
# - '#has no value type specified in iterable type array#' # remove this rule when all other issues are solved.
# - '#is not allowed to extend#'
# - '#does not specify its types#'
# - '#switch is forbidden to use#'
# - '#is neither abstract nor final#'
# - '#on left side of \?\?\= always exists and is not nullable#'
# - '#has a nullable return type declaration#' # perhaps throw errors instead?
# - '#with a nullable type declaration#' # decide what action should be if param is null.
# - '#with null as default value#'
# -
# message: '#Constructor in [a-zA-Z0-9\\_]+ has parameter \$[a-zA-Z0-9\\_]+ with default value#'
# paths:
# - ../app/Exceptions/IntervalException.php
# - ../app/Support/Navigation.php
# -
# message: '#but containers should not be injected#'
# paths:
# - ../app/Support/Authentication/RemoteUserGuard.php
# -
# message: '#Function compact\(\) should not be used#' # too useful in template rendering.
# paths:
# - ../app/Generator/Report/Account/MonthReportGenerator.php
# - ../app/Generator/Report/Audit/MonthReportGenerator.php
# - ../app/Generator/Report/Budget/MonthReportGenerator.php
# - ../app/Generator/Report/Category/MonthReportGenerator.php
# - ../app/Generator/Report/Standard/MonthReportGenerator.php
# - ../app/Generator/Report/Standard/MultiYearReportGenerator.php
# - ../app/Generator/Report/Standard/YearReportGenerator.php
# - ../app/Generator/Report/Tag/MonthReportGenerator.php
# - ../app/Http/Controllers/Account/*.php
# - ../app/Http/Controllers/Admin/*.php
# - ../app/Http/Controllers/*.php
# - ../app/Support/ExpandedForm.php
# - ../app/Support/Form/AccountForm.php
# - ../app/Support/Form/CurrencyForm.php
# - ../app/Support/Form/FormSupport.php
# -
# message: '#Either catch a more specific exception#'
# paths:
# - ../app/Support/Form/FormSupport.php
# The level 8 is the highest level. original was 5
# 7 is more than enough, higher just leaves NULL things.

View File

@@ -41,6 +41,7 @@ use Illuminate\Http\JsonResponse;
class AccountController extends Controller
{
use AccountFilter;
protected array $accepts = ['application/json'];
/** @var array<int, string> */
private array $balanceTypes;
@@ -84,12 +85,12 @@ class AccountController extends Controller
/** @var Account $account */
foreach ($result as $account) {
$nameWithBalance = $account->name;
$currency = $this->repository->getAccountCurrency($account) ?? $this->defaultCurrency;
$currency = $this->repository->getAccountCurrency($account) ?? $this->nativeCurrency;
$useCurrency = $currency;
if (in_array($account->accountType->type, $this->balanceTypes, true)) {
$balance = Steam::finalAccountBalance($account, $date);
$key = $this->convertToNative && $currency->id !== $this->defaultCurrency->id ? 'native_balance' : 'balance';
$useCurrency = $this->convertToNative && $currency->id !== $this->defaultCurrency->id ? $this->defaultCurrency : $currency;
$key = $this->convertToNative && $currency->id !== $this->nativeCurrency->id ? 'native_balance' : 'balance';
$useCurrency = $this->convertToNative && $currency->id !== $this->nativeCurrency->id ? $this->nativeCurrency : $currency;
$amount = $balance[$key] ?? '0';
$nameWithBalance = sprintf(
'%s (%s)',
@@ -123,6 +124,6 @@ class AccountController extends Controller
}
);
return response()->json($return);
return response()->api($return);
}
}

View File

@@ -74,6 +74,6 @@ class BillController extends Controller
}
);
return response()->json($filtered->toArray());
return response()->api($filtered->toArray());
}
}

View File

@@ -73,6 +73,6 @@ class BudgetController extends Controller
}
);
return response()->json($filtered);
return response()->api($filtered->toArray());
}
}

View File

@@ -73,6 +73,6 @@ class CategoryController extends Controller
}
);
return response()->json($filtered);
return response()->api($filtered->toArray());
}
}

View File

@@ -77,7 +77,7 @@ class CurrencyController extends Controller
];
}
return response()->json($result);
return response()->api($result);
}
/**
@@ -103,6 +103,6 @@ class CurrencyController extends Controller
];
}
return response()->json($result);
return response()->api($result);
}
}

View File

@@ -75,6 +75,6 @@ class ObjectGroupController extends Controller
];
}
return response()->json($return);
return response()->api($return);
}
}

View File

@@ -87,7 +87,7 @@ class PiggyBankController extends Controller
];
}
return response()->json($response);
return response()->api($response);
}
/**
@@ -124,6 +124,6 @@ class PiggyBankController extends Controller
];
}
return response()->json($response);
return response()->api($response);
}
}

View File

@@ -73,6 +73,6 @@ class RecurrenceController extends Controller
];
}
return response()->json($response);
return response()->api($response);
}
}

View File

@@ -72,6 +72,6 @@ class RuleController extends Controller
];
}
return response()->json($response);
return response()->api($response);
}
}

View File

@@ -72,6 +72,6 @@ class RuleGroupController extends Controller
];
}
return response()->json($response);
return response()->api($response);
}
}

View File

@@ -75,6 +75,6 @@ class TagController extends Controller
];
}
return response()->json($array);
return response()->api($array);
}
}

View File

@@ -84,7 +84,7 @@ class TransactionController extends Controller
];
}
return response()->json($array);
return response()->api($array);
}
/**
@@ -122,6 +122,6 @@ class TransactionController extends Controller
];
}
return response()->json($array);
return response()->api($array);
}
}

View File

@@ -72,6 +72,6 @@ class TransactionTypeController extends Controller
];
}
return response()->json($array);
return response()->api($array);
}
}

View File

@@ -97,8 +97,8 @@ class AccountController extends Controller
/** @var Account $account */
foreach ($accounts as $account) {
$currency = $this->repository->getAccountCurrency($account) ?? $this->defaultCurrency;
$field = $this->convertToNative && $currency->id !== $this->defaultCurrency->id ? 'native_balance' : 'balance';
$currency = $this->repository->getAccountCurrency($account) ?? $this->nativeCurrency;
$field = $this->convertToNative && $currency->id !== $this->nativeCurrency->id ? 'native_balance' : 'balance';
$currentSet = [
'label' => $account->name,
'currency_id' => (string) $currency->id,

View File

@@ -26,6 +26,7 @@ namespace FireflyIII\Api\V1\Controllers;
use Carbon\Carbon;
use Carbon\Exceptions\InvalidFormatException;
use FireflyIII\Exceptions\BadHttpHeaderException;
use FireflyIII\Models\Preference;
use FireflyIII\Models\TransactionCurrency;
use FireflyIII\Support\Facades\Amount;
@@ -59,13 +60,15 @@ abstract class Controller extends BaseController
use DispatchesJobs;
use ValidatesRequests;
protected const string CONTENT_TYPE = 'application/vnd.api+json';
protected const string CONTENT_TYPE = 'application/vnd.api+json';
protected const string JSON_CONTENT_TYPE = 'application/json';
/** @var array<int, string> */
protected array $allowedSort;
protected ParameterBag $parameters;
protected bool $convertToNative = false;
protected TransactionCurrency $defaultCurrency;
protected bool $convertToNative = false;
protected array $accepts = ['application/json'];
protected TransactionCurrency $nativeCurrency;
/**
* Controller constructor.
@@ -80,11 +83,17 @@ abstract class Controller extends BaseController
if (auth()->check()) {
$language = Steam::getLanguage();
$this->convertToNative = Amount::convertToNative();
$this->defaultCurrency = Amount::getDefaultCurrency();
$this->nativeCurrency = Amount::getNativeCurrency();
app()->setLocale($language);
}
// filter down what this endpoint accepts.
if (!$request->accepts($this->accepts)) {
throw new BadHttpHeaderException(sprintf('Sorry, Accept header "%s" is not something this endpoint can provide.', $request->header('Accept')));
}
return $next($request);
}
);
@@ -148,7 +157,15 @@ abstract class Controller extends BaseController
$value = null;
}
if (null !== $value) {
$bag->set($integer, (int) $value);
$value = (int) $value;
if ($value < 1) {
$value = 1;
}
if ($value > 2 ** 16) {
$value = 2 ** 16;
}
$bag->set($integer, $value);
}
if (null === $value
&& 'limit' === $integer // @phpstan-ignore-line

View File

@@ -70,7 +70,7 @@ class BillController extends Controller
$start = $request->getStart();
$end = $request->getEnd();
$convertToNative = Amount::convertToNative();
$default = Amount::getDefaultCurrency();
$default = Amount::getNativeCurrency();
$response = [];
// get all bills:
@@ -133,7 +133,7 @@ class BillController extends Controller
$start = $request->getStart();
$end = $request->getEnd();
$convertToNative = Amount::convertToNative();
$default = Amount::getDefaultCurrency();
$default = Amount::getNativeCurrency();
$response = [];
// collect all expenses in this period (regardless of type) by the given bills and accounts.

View File

@@ -48,7 +48,7 @@ class PeriodController extends Controller
$end = $request->getEnd();
$response = [];
$convertToNative = Amount::convertToNative();
$default = Amount::getDefaultCurrency();
$default = Amount::getNativeCurrency();
// collect all expenses in this period (regardless of type)
$collector = app(GroupCollectorInterface::class);

View File

@@ -69,7 +69,7 @@ class TagController extends Controller
$end = $request->getEnd();
$response = [];
$convertToNative = Amount::convertToNative();
$default = Amount::getDefaultCurrency();
$default = Amount::getNativeCurrency();
// collect all expenses in this period (regardless of type) by the given bills and accounts.
$collector = app(GroupCollectorInterface::class);

View File

@@ -47,7 +47,7 @@ class PeriodController extends Controller
$end = $request->getEnd();
$response = [];
$convertToNative = Amount::convertToNative();
$default = Amount::getDefaultCurrency();
$default = Amount::getNativeCurrency();
// collect all expenses in this period (regardless of type)
$collector = app(GroupCollectorInterface::class);

View File

@@ -69,7 +69,7 @@ class TagController extends Controller
$end = $request->getEnd();
$response = [];
$convertToNative = Amount::convertToNative();
$default = Amount::getDefaultCurrency();
$default = Amount::getNativeCurrency();
// collect all expenses in this period (regardless of type) by the given bills and accounts.
$collector = app(GroupCollectorInterface::class);

View File

@@ -47,7 +47,7 @@ class PeriodController extends Controller
$end = $request->getEnd();
$response = [];
$convertToNative = Amount::convertToNative();
$default = Amount::getDefaultCurrency();
$default = Amount::getNativeCurrency();
// collect all expenses in this period (regardless of type)
$collector = app(GroupCollectorInterface::class);

View File

@@ -67,7 +67,7 @@ class TagController extends Controller
$end = $request->getEnd();
$response = [];
$convertToNative = Amount::convertToNative();
$default = Amount::getDefaultCurrency();
$default = Amount::getNativeCurrency();
// collect all expenses in this period (regardless of type) by the given bills and accounts.

View File

@@ -25,6 +25,7 @@ declare(strict_types=1);
namespace FireflyIII\Api\V1\Controllers\Models\Budget;
use FireflyIII\Api\V1\Controllers\Controller;
use FireflyIII\Enums\TransactionTypeEnum;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Helpers\Collector\GroupCollectorInterface;
use FireflyIII\Models\Budget;
@@ -208,6 +209,8 @@ class ListController extends Controller
$collector = app(GroupCollectorInterface::class);
$collector
->setUser($admin)
// withdrawals only
->setTypes([TransactionTypeEnum::WITHDRAWAL->value])
// filter on budget.
->withoutBudget()
// all info needed for the API:

View File

@@ -2,7 +2,7 @@
/*
* DestroyController.php
* Copyright (c) 2024 james@firefly-iii.org.
* Copyright (c) 2025 james@firefly-iii.org.
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
@@ -22,10 +22,13 @@
declare(strict_types=1);
namespace FireflyIII\Api\V2\Controllers\Model\ExchangeRate;
namespace FireflyIII\Api\V1\Controllers\Models\CurrencyExchangeRate;
use FireflyIII\Api\V2\Controllers\Controller;
use FireflyIII\Api\V2\Request\Model\ExchangeRate\DestroyRequest;
use FireflyIII\Api\V1\Controllers\Controller;
use FireflyIII\Api\V1\Requests\Models\CurrencyExchangeRate\DestroyRequest;
use FireflyIII\Enums\UserRoleEnum;
use FireflyIII\Exceptions\ValidationException;
use FireflyIII\Models\CurrencyExchangeRate;
use FireflyIII\Models\TransactionCurrency;
use FireflyIII\Repositories\UserGroups\ExchangeRate\ExchangeRateRepositoryInterface;
use FireflyIII\Support\Http\Api\ValidatesUserGroupTrait;
@@ -36,6 +39,8 @@ class DestroyController extends Controller
{
use ValidatesUserGroupTrait;
protected array $acceptedRoles = [UserRoleEnum::OWNER];
public const string RESOURCE_KEY = 'exchange-rates';
private ExchangeRateRepositoryInterface $repository;
@@ -56,6 +61,9 @@ class DestroyController extends Controller
public function destroy(DestroyRequest $request, TransactionCurrency $from, TransactionCurrency $to): JsonResponse
{
$date = $request->getDate();
if (null === $date) {
throw new ValidationException('Date is required');
}
$rate = $this->repository->getSpecificRateOnDate($from, $to, $date);
if (null === $rate) {
throw new NotFoundHttpException();
@@ -64,4 +72,11 @@ class DestroyController extends Controller
return response()->json([], 204);
}
public function destroySingle(CurrencyExchangeRate $exchangeRate): JsonResponse
{
$this->repository->deleteRate($exchangeRate);
return response()->json([], 204);
}
}

View File

@@ -1,8 +1,8 @@
<?php
/*
* ShowController.php
* Copyright (c) 2023 james@firefly-iii.org
* IndexController.php
* Copyright (c) 2025 james@firefly-iii.org.
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
@@ -17,12 +17,12 @@
* 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/>.
* along with this program. If not, see https://www.gnu.org/licenses/.
*/
declare(strict_types=1);
namespace FireflyIII\Api\V2\Controllers\Model\ExchangeRate;
namespace FireflyIII\Api\V1\Controllers\Models\CurrencyExchangeRate;
use FireflyIII\Api\V2\Controllers\Controller;
use FireflyIII\Repositories\UserGroups\ExchangeRate\ExchangeRateRepositoryInterface;
@@ -38,7 +38,7 @@ class IndexController extends Controller
{
use ValidatesUserGroupTrait;
public const string RESOURCE_KEY = 'exchange-rates';
public const string RESOURCE_KEY = 'currency_exchange_rates';
private ExchangeRateRepositoryInterface $repository;
@@ -62,9 +62,6 @@ class IndexController extends Controller
$count = $piggies->count();
$piggies = $piggies->slice(($this->parameters->get('page') - 1) * $pageSize, $pageSize);
$paginator = new LengthAwarePaginator($piggies, $count, $pageSize, $this->parameters->get('page'));
var_dump('here we are');
$transformer = new ExchangeRateTransformer();
$transformer->setParameters($this->parameters); // give params to transformer

View File

@@ -2,7 +2,7 @@
/*
* ShowController.php
* Copyright (c) 2023 james@firefly-iii.org
* Copyright (c) 2025 james@firefly-iii.org.
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
@@ -17,14 +17,15 @@
* 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/>.
* along with this program. If not, see https://www.gnu.org/licenses/.
*/
declare(strict_types=1);
namespace FireflyIII\Api\V2\Controllers\Model\ExchangeRate;
namespace FireflyIII\Api\V1\Controllers\Models\CurrencyExchangeRate;
use FireflyIII\Api\V2\Controllers\Controller;
use FireflyIII\Models\CurrencyExchangeRate;
use FireflyIII\Models\TransactionCurrency;
use FireflyIII\Repositories\UserGroups\ExchangeRate\ExchangeRateRepositoryInterface;
use FireflyIII\Support\Http\Api\ValidatesUserGroupTrait;
@@ -73,4 +74,15 @@ class ShowController extends Controller
->header('Content-Type', self::CONTENT_TYPE)
;
}
public function showSingle(CurrencyExchangeRate $exchangeRate): JsonResponse
{
$transformer = new ExchangeRateTransformer();
$transformer->setParameters($this->parameters);
return response()
->api($this->jsonApiObject(self::RESOURCE_KEY, $exchangeRate, $transformer))
->header('Content-Type', self::CONTENT_TYPE)
;
}
}

View File

@@ -1,8 +1,8 @@
<?php
/*
* DestroyController.php
* Copyright (c) 2024 james@firefly-iii.org.
* StoreController.php
* Copyright (c) 2025 james@firefly-iii.org.
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
@@ -22,10 +22,10 @@
declare(strict_types=1);
namespace FireflyIII\Api\V2\Controllers\Model\ExchangeRate;
namespace FireflyIII\Api\V1\Controllers\Models\CurrencyExchangeRate;
use FireflyIII\Api\V1\Requests\Models\CurrencyExchangeRate\StoreRequest;
use FireflyIII\Api\V2\Controllers\Controller;
use FireflyIII\Api\V2\Request\Model\ExchangeRate\StoreRequest;
use FireflyIII\Repositories\UserGroups\ExchangeRate\ExchangeRateRepositoryInterface;
use FireflyIII\Support\Http\Api\ValidatesUserGroupTrait;
use FireflyIII\Transformers\V2\ExchangeRateTransformer;

View File

@@ -1,8 +1,8 @@
<?php
/*
* DestroyController.php
* Copyright (c) 2024 james@firefly-iii.org.
* UpdateController.php
* Copyright (c) 2025 james@firefly-iii.org.
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
@@ -22,10 +22,10 @@
declare(strict_types=1);
namespace FireflyIII\Api\V2\Controllers\Model\ExchangeRate;
namespace FireflyIII\Api\V1\Controllers\Models\CurrencyExchangeRate;
use FireflyIII\Api\V1\Requests\Models\CurrencyExchangeRate\UpdateRequest;
use FireflyIII\Api\V2\Controllers\Controller;
use FireflyIII\Api\V2\Request\Model\ExchangeRate\UpdateRequest;
use FireflyIII\Models\CurrencyExchangeRate;
use FireflyIII\Repositories\UserGroups\ExchangeRate\ExchangeRateRepositoryInterface;
use FireflyIII\Support\Http\Api\ValidatesUserGroupTrait;

View File

@@ -107,7 +107,7 @@ class ShowController extends Controller
/** @var User $user */
$user = auth()->user();
$manager = $this->getManager();
$this->parameters->set('defaultCurrency', $this->defaultCurrency);
$this->parameters->set('nativeCurrency', $this->nativeCurrency);
// update fields with user info.
$currency->refreshForUser($user);
@@ -123,7 +123,7 @@ class ShowController extends Controller
/**
* This endpoint is documented at:
* https://api-docs.firefly-iii.org/?urls.primaryName=2.0.0%20(v1)#/currencies/getDefaultCurrency
* https://api-docs.firefly-iii.org/?urls.primaryName=2.0.0%20(v1)#/currencies/getNativeCurrency
*
* Show a currency.
*
@@ -134,7 +134,7 @@ class ShowController extends Controller
/** @var User $user */
$user = auth()->user();
$manager = $this->getManager();
$currency = $this->defaultCurrency;
$currency = $this->nativeCurrency;
// update fields with user info.
$currency->refreshForUser($user);

View File

@@ -100,7 +100,7 @@ class UpdateController extends Controller
/**
* This endpoint is documented at:
* https://api-docs.firefly-iii.org/?urls.primaryName=2.0.0%20(v1)#/currencies/defaultCurrency
* https://api-docs.firefly-iii.org/?urls.primaryName=2.0.0%20(v1)#/currencies/nativeCurrency
*
* Make the currency a default currency.
*

View File

@@ -124,7 +124,7 @@ class BasicController extends Controller
{
// some config settings
$convertToNative = Amount::convertToNative();
$default = Amount::getDefaultCurrency();
$default = Amount::getNativeCurrency();
// prep some arrays:
$incomes = [];
$expenses = [];

View File

@@ -58,7 +58,7 @@ class AboutController extends Controller
'driver' => $currentDriver,
];
return response()->api(['data' => $data])->header('Content-Type', self::CONTENT_TYPE);
return response()->api(['data' => $data])->header('Content-Type', self::JSON_CONTENT_TYPE);
}
/**

View File

@@ -86,7 +86,7 @@ class ConfigurationController extends Controller
];
}
return response()->json($return);
return response()->api($return);
}
/**
@@ -142,7 +142,7 @@ class ConfigurationController extends Controller
];
}
return response()->json(['data' => $data])->header('Content-Type', self::CONTENT_TYPE);
return response()->api(['data' => $data])->header('Content-Type', self::JSON_CONTENT_TYPE);
}
/**
@@ -173,6 +173,6 @@ class ConfigurationController extends Controller
'editable' => true,
];
return response()->json(['data' => $data])->header('Content-Type', self::CONTENT_TYPE);
return response()->api(['data' => $data])->header('Content-Type', self::CONTENT_TYPE);
}
}

View File

@@ -52,8 +52,8 @@ class CronController extends Controller
if (true === config('cer.download_enabled')) {
$return['exchange_rates'] = $this->exchangeRatesCronJob($config['force'], $config['date']);
}
$return['bill_warnings'] = $this->billWarningCronJob($config['force'], $config['date']);
$return['bill_notifications'] = $this->billWarningCronJob($config['force'], $config['date']);
return response()->json($return);
return response()->api($return);
}
}

View File

@@ -32,7 +32,6 @@ use FireflyIII\Models\Preference;
use FireflyIII\Transformers\PreferenceTransformer;
use Illuminate\Http\JsonResponse;
use Illuminate\Pagination\LengthAwarePaginator;
use Illuminate\Support\Collection;
use League\Fractal\Pagination\IlluminatePaginatorAdapter;
use League\Fractal\Resource\Collection as FractalCollection;
use League\Fractal\Resource\Item;
@@ -86,7 +85,7 @@ class PreferencesController extends Controller
$manager = $this->getManager();
if ('currencyPreference' === $preference->name) {
throw new FireflyException('Please use api/v1/currencies/default instead.');
throw new FireflyException('Please use api/v1/currencies/native instead.');
}
/** @var PreferenceTransformer $transformer */
@@ -98,34 +97,6 @@ class PreferencesController extends Controller
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', self::CONTENT_TYPE);
}
/**
* TODO This endpoint is not documented.
*
* Return a single preference by name.
*
* @param Collection<int, Preference> $collection
*/
public function showList(Collection $collection): JsonResponse
{
$manager = $this->getManager();
$count = $collection->count();
$pageSize = $this->parameters->get('limit');
$preferences = $collection->slice(($this->parameters->get('page') - 1) * $pageSize, $pageSize);
// make paginator:
$paginator = new LengthAwarePaginator($preferences, $count, $pageSize, $this->parameters->get('page'));
$paginator->setPath(route('api.v1.preferences.show-list').$this->buildParams());
/** @var PreferenceTransformer $transformer */
$transformer = app(PreferenceTransformer::class);
$transformer->setParameters($this->parameters);
$resource = new FractalCollection($preferences, $transformer, self::RESOURCE_KEY);
$resource->setPaginator(new IlluminatePaginatorAdapter($paginator));
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', self::CONTENT_TYPE);
}
/**
* This endpoint is documented at:
* https://api-docs.firefly-iii.org/?urls.primaryName=2.0.0%20(v1)#/preferences/storePreference
@@ -161,7 +132,7 @@ class PreferencesController extends Controller
public function update(PreferenceUpdateRequest $request, Preference $preference): JsonResponse
{
if ('currencyPreference' === $preference->name) {
throw new FireflyException('Please use api/v1/currencies/default instead.');
throw new FireflyException('Please use api/v1/currencies/native instead.');
}
$manager = $this->getManager();

View File

@@ -58,6 +58,7 @@ class AutocompleteRequest extends FormRequest
public function rules(): array
{
return [
'date' => 'date|after:1900-01-01|before:2099-12-31',
];
}
}

View File

@@ -24,7 +24,7 @@ declare(strict_types=1);
namespace FireflyIII\Api\V1\Requests\Data;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Exceptions\ValidationException;
use FireflyIII\Support\Request\ChecksLogin;
use FireflyIII\Support\Request\ConvertsDataTypes;
use Illuminate\Foundation\Http\FormRequest;
@@ -49,7 +49,7 @@ class DateRequest extends FormRequest
$start->startOfDay();
$end->endOfDay();
if ($start->diffInYears($end, true) > 5) {
throw new FireflyException('Date range out of range.');
throw new ValidationException('Date range out of range.');
}
return [

View File

@@ -26,6 +26,7 @@ namespace FireflyIII\Api\V1\Requests\Models\Account;
use FireflyIII\Models\Account;
use FireflyIII\Models\Location;
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use FireflyIII\Rules\IsBoolean;
use FireflyIII\Rules\UniqueAccountNumber;
use FireflyIII\Rules\UniqueIban;
@@ -33,6 +34,8 @@ use FireflyIII\Support\Request\AppendsLocationData;
use FireflyIII\Support\Request\ChecksLogin;
use FireflyIII\Support\Request\ConvertsDataTypes;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Support\Facades\Log;
use Illuminate\Validation\Validator;
/**
* Class UpdateRequest
@@ -112,4 +115,36 @@ class UpdateRequest extends FormRequest
return Location::requestRules($rules);
}
/**
* Configure the validator instance with special rules for after the basic validation rules.
*/
public function withValidator(Validator $validator): void
{
$validator->after(
function (Validator $validator): void {
// validate start before end only if both are there.
$data = $validator->getData();
/** @var Account $account */
$account = $this->route()->parameter('account');
/** @var AccountRepositoryInterface $repository */
$repository = app(AccountRepositoryInterface::class);
$currency = $repository->getAccountCurrency($account);
// how many piggies are attached?
$piggyBanks = $account->piggyBanks()->count();
if ($piggyBanks > 0 && array_key_exists('currency_code', $data) && $data['currency_code'] !== $currency->code) {
$validator->errors()->add('currency_code', (string) trans('validation.piggy_no_change_currency'));
}
if ($piggyBanks > 0 && array_key_exists('currency_id', $data) && (int) $data['currency_id'] !== $currency->id) {
$validator->errors()->add('currency_id', (string) trans('validation.piggy_no_change_currency'));
}
}
);
if ($validator->fails()) {
Log::channel('audit')->error(sprintf('Validation errors in %s', __CLASS__), $validator->errors()->toArray());
}
}
}

View File

@@ -66,8 +66,8 @@ class Request extends FormRequest
'currency_id' => 'numeric|exists:transaction_currencies,id',
'currency_code' => 'min:3|max:51|exists:transaction_currencies,code',
'amount' => ['nullable', new IsValidPositiveAmount()],
'start' => 'date',
'end' => 'date',
'start' => 'date|after:1900-01-01|before:2099-12-31',
'end' => 'date|after:1900-01-01|before:2099-12-31',
];
}

View File

@@ -78,9 +78,9 @@ class StoreRequest extends FormRequest
'amount_max' => ['required', new IsValidPositiveAmount()],
'currency_id' => 'numeric|exists:transaction_currencies,id',
'currency_code' => 'min:3|max:51|exists:transaction_currencies,code',
'date' => 'date|required',
'end_date' => 'nullable|date|after:date',
'extension_date' => 'nullable|date|after:date',
'date' => 'date|required|after:1900-01-01|before:2099-12-31',
'end_date' => 'nullable|date|after:date|after:1900-01-01|before:2099-12-31',
'extension_date' => 'nullable|date|after:date|after:1900-01-01|before:2099-12-31',
'repeat_freq' => 'in:weekly,monthly,quarterly,half-year,yearly|required',
'skip' => 'min:0|max:31|numeric',
'active' => [new IsBoolean()],
@@ -95,16 +95,40 @@ class StoreRequest extends FormRequest
{
$validator->after(
static function (Validator $validator): void {
$data = $validator->getData();
$min = (string) ($data['amount_min'] ?? '0');
$max = (string) ($data['amount_max'] ?? '0');
$data = $validator->getData();
$min = $data['amount_min'] ?? '0';
$max = $data['amount_max'] ?? '0';
if (1 === bccomp($min, $max)) {
if (is_array($min) || is_array($max)) {
$validator->errors()->add('amount_min', (string) trans('validation.generic_invalid'));
$validator->errors()->add('amount_max', (string) trans('validation.generic_invalid'));
$min = '0';
$max = '0';
}
$result = false;
try {
$result = bccomp($min, $max);
} catch (\ValueError $e) {
Log::error($e->getMessage());
$validator->errors()->add('amount_min', (string) trans('validation.generic_invalid'));
$validator->errors()->add('amount_max', (string) trans('validation.generic_invalid'));
}
if (1 === $result) {
$validator->errors()->add('amount_min', (string) trans('validation.amount_min_over_max'));
}
}
);
if ($validator->fails()) {
$failed = false;
try {
$failed = $validator->fails();
} catch (\TypeError $e) {
Log::error($e->getMessage());
$failed = false;
}
if ($failed) {
Log::channel('audit')->error(sprintf('Validation errors in %s', __CLASS__), $validator->errors()->toArray());
}
}

View File

@@ -81,9 +81,9 @@ class UpdateRequest extends FormRequest
'amount_max' => ['nullable', new IsValidPositiveAmount()],
'currency_id' => 'numeric|exists:transaction_currencies,id',
'currency_code' => 'min:3|max:51|exists:transaction_currencies,code',
'date' => 'date',
'end_date' => 'date|after:date',
'extension_date' => 'date|after:date',
'date' => 'date|after:1900-01-01|before:2099-12-31',
'end_date' => 'date|after:date|after:1900-01-01|before:2099-12-31',
'extension_date' => 'date|after:date|after:1900-01-01|before:2099-12-31',
'repeat_freq' => 'in:weekly,monthly,quarterly,half-year,yearly',
'skip' => 'min:0|max:31|numeric',
'active' => [new IsBoolean()],

View File

@@ -67,8 +67,8 @@ class UpdateRequest extends FormRequest
public function rules(): array
{
return [
'start' => 'date',
'end' => 'date',
'start' => 'date|after:1900-01-01|before:2099-12-31',
'end' => 'date|after:1900-01-01|before:2099-12-31',
'amount' => ['nullable', new IsValidPositiveAmount()],
'currency_id' => 'numeric|exists:transaction_currencies,id',
'currency_code' => 'min:3|max:51|exists:transaction_currencies,code',

View File

@@ -2,7 +2,7 @@
/*
* DestroyRequest.php
* Copyright (c) 2024 james@firefly-iii.org.
* Copyright (c) 2025 james@firefly-iii.org.
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
@@ -22,7 +22,7 @@
declare(strict_types=1);
namespace FireflyIII\Api\V2\Request\Model\ExchangeRate;
namespace FireflyIII\Api\V1\Requests\Models\CurrencyExchangeRate;
use Carbon\Carbon;
use FireflyIII\Support\Request\ChecksLogin;
@@ -34,7 +34,7 @@ class DestroyRequest extends FormRequest
use ChecksLogin;
use ConvertsDataTypes;
public function getDate(): Carbon
public function getDate(): ?Carbon
{
return $this->getCarbonDate('date');
}

View File

@@ -1,8 +1,8 @@
<?php
/*
* DestroyRequest.php
* Copyright (c) 2024 james@firefly-iii.org.
* StoreRequest.php
* Copyright (c) 2025 james@firefly-iii.org.
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
@@ -22,7 +22,7 @@
declare(strict_types=1);
namespace FireflyIII\Api\V2\Request\Model\ExchangeRate;
namespace FireflyIII\Api\V1\Requests\Models\CurrencyExchangeRate;
use Carbon\Carbon;
use FireflyIII\Models\TransactionCurrency;

View File

@@ -1,8 +1,8 @@
<?php
/*
* DestroyRequest.php
* Copyright (c) 2024 james@firefly-iii.org.
* UpdateRequest.php
* Copyright (c) 2025 james@firefly-iii.org.
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
@@ -22,7 +22,7 @@
declare(strict_types=1);
namespace FireflyIII\Api\V2\Request\Model\ExchangeRate;
namespace FireflyIII\Api\V1\Requests\Models\CurrencyExchangeRate;
use Carbon\Carbon;
use FireflyIII\Support\Request\ChecksLogin;

View File

@@ -154,7 +154,7 @@ class UpdateRequest extends FormRequest
return [
'title' => sprintf('min:1|max:255|uniqueObjectForUser:recurrences,title,%d', $recurrence->id),
'description' => 'min:1|max:32768',
'first_date' => 'date',
'first_date' => 'date|after:1900-01-01|before:2099-12-31',
'apply_rules' => [new IsBoolean()],
'active' => [new IsBoolean()],
'repeat_until' => 'nullable|date',

View File

@@ -71,8 +71,8 @@ class TestRequest extends FormRequest
public function rules(): array
{
return [
'start' => 'date',
'end' => 'date|after_or_equal:start',
'start' => 'date|after:1900-01-01|before:2099-12-31',
'end' => 'date|after_or_equal:start|after:1900-01-01|before:2099-12-31',
'accounts' => '',
'accounts.*' => 'required|exists:accounts,id|belongsToUser:accounts',
];

View File

@@ -65,8 +65,8 @@ class TriggerRequest extends FormRequest
public function rules(): array
{
return [
'start' => 'date',
'end' => 'date|after_or_equal:start',
'start' => 'date|after:1900-01-01|before:2099-12-31',
'end' => 'date|after_or_equal:start|after:1900-01-01|before:2099-12-31',
'accounts' => '',
'accounts.*' => 'exists:accounts,id|belongsToUser:accounts',
];

View File

@@ -65,8 +65,8 @@ class TestRequest extends FormRequest
public function rules(): array
{
return [
'start' => 'date',
'end' => 'date|after_or_equal:start',
'start' => 'date|after:1900-01-01|before:2099-12-31',
'end' => 'date|after_or_equal:start|after:1900-01-01|before:2099-12-31',
'accounts' => '',
'accounts.*' => 'exists:accounts,id|belongsToUser:accounts',
];

View File

@@ -69,8 +69,8 @@ class TriggerRequest extends FormRequest
public function rules(): array
{
return [
'start' => 'date',
'end' => 'date|after_or_equal:start',
'start' => 'date|after:1900-01-01|before:2099-12-31',
'end' => 'date|after_or_equal:start|after:1900-01-01|before:2099-12-31',
];
}
}

View File

@@ -62,7 +62,7 @@ class StoreRequest extends FormRequest
$rules = [
'tag' => 'required|min:1|uniqueObjectForUser:tags,tag|max:1024',
'description' => 'min:1|nullable|max:32768',
'date' => 'date|nullable',
'date' => 'date|nullable|after:1900-01-01|before:2099-12-31',
];
return Location::requestRules($rules);

View File

@@ -63,11 +63,10 @@ class UpdateRequest extends FormRequest
{
/** @var Tag $tag */
$tag = $this->route()->parameter('tagOrId');
// TODO check if uniqueObjectForUser is obsolete
$rules = [
'tag' => 'min:1|max:1024|uniqueObjectForUser:tags,tag,'.$tag->id,
'description' => 'min:1|nullable|max:32768',
'date' => 'date|nullable',
'date' => 'date|nullable|after:1900-01-01|before:2099-12-31',
];
return Location::requestRules($rules);

View File

@@ -24,6 +24,7 @@ declare(strict_types=1);
namespace FireflyIII\Api\V1\Requests\Models\Transaction;
use FireflyIII\Models\Location;
use FireflyIII\Rules\BelongsUser;
use FireflyIII\Rules\IsBoolean;
use FireflyIII\Rules\IsDateOrTime;
@@ -82,82 +83,87 @@ class StoreRequest extends FormRequest
foreach ($this->get('transactions') as $transaction) {
$object = new NullArrayObject($transaction);
$return[] = [
'type' => $this->clearString($object['type']),
'date' => $this->dateFromValue($object['date']),
'order' => $this->integerFromValue((string) $object['order']),
'type' => $this->clearString($object['type']),
'date' => $this->dateFromValue($object['date']),
'order' => $this->integerFromValue((string) $object['order']),
'currency_id' => $this->integerFromValue((string) $object['currency_id']),
'currency_code' => $this->clearString((string) $object['currency_code']),
'currency_id' => $this->integerFromValue((string) $object['currency_id']),
'currency_code' => $this->clearString((string) $object['currency_code']),
// location
'latitude' => $this->floatFromValue((string) $object['latitude']),
'longitude' => $this->floatFromValue((string) $object['longitude']),
'zoom_level' => $this->integerFromValue((string) $object['zoom_level']),
// foreign currency info:
'foreign_currency_id' => $this->integerFromValue((string) $object['foreign_currency_id']),
'foreign_currency_code' => $this->clearString((string) $object['foreign_currency_code']),
'foreign_currency_id' => $this->integerFromValue((string) $object['foreign_currency_id']),
'foreign_currency_code' => $this->clearString((string) $object['foreign_currency_code']),
// amount and foreign amount. Cannot be 0.
'amount' => $this->clearString((string) $object['amount']),
'foreign_amount' => $this->clearString((string) $object['foreign_amount']),
'amount' => $this->clearString((string) $object['amount']),
'foreign_amount' => $this->clearString((string) $object['foreign_amount']),
// description.
'description' => $this->clearString($object['description']),
'description' => $this->clearString($object['description']),
// source of transaction. If everything is null, assume cash account.
'source_id' => $this->integerFromValue((string) $object['source_id']),
'source_name' => $this->clearString((string) $object['source_name']),
'source_iban' => $this->clearIban((string) $object['source_iban']),
'source_number' => $this->clearString((string) $object['source_number']),
'source_bic' => $this->clearString((string) $object['source_bic']),
'source_id' => $this->integerFromValue((string) $object['source_id']),
'source_name' => $this->clearString((string) $object['source_name']),
'source_iban' => $this->clearIban((string) $object['source_iban']),
'source_number' => $this->clearString((string) $object['source_number']),
'source_bic' => $this->clearString((string) $object['source_bic']),
// destination of transaction. If everything is null, assume cash account.
'destination_id' => $this->integerFromValue((string) $object['destination_id']),
'destination_name' => $this->clearString((string) $object['destination_name']),
'destination_iban' => $this->clearIban((string) $object['destination_iban']),
'destination_number' => $this->clearString((string) $object['destination_number']),
'destination_bic' => $this->clearString((string) $object['destination_bic']),
'destination_id' => $this->integerFromValue((string) $object['destination_id']),
'destination_name' => $this->clearString((string) $object['destination_name']),
'destination_iban' => $this->clearIban((string) $object['destination_iban']),
'destination_number' => $this->clearString((string) $object['destination_number']),
'destination_bic' => $this->clearString((string) $object['destination_bic']),
// budget info
'budget_id' => $this->integerFromValue((string) $object['budget_id']),
'budget_name' => $this->clearString((string) $object['budget_name']),
'budget_id' => $this->integerFromValue((string) $object['budget_id']),
'budget_name' => $this->clearString((string) $object['budget_name']),
// category info
'category_id' => $this->integerFromValue((string) $object['category_id']),
'category_name' => $this->clearString((string) $object['category_name']),
'category_id' => $this->integerFromValue((string) $object['category_id']),
'category_name' => $this->clearString((string) $object['category_name']),
// journal bill reference. Optional. Will only work for withdrawals
'bill_id' => $this->integerFromValue((string) $object['bill_id']),
'bill_name' => $this->clearString((string) $object['bill_name']),
'bill_id' => $this->integerFromValue((string) $object['bill_id']),
'bill_name' => $this->clearString((string) $object['bill_name']),
// piggy bank reference. Optional. Will only work for transfers
'piggy_bank_id' => $this->integerFromValue((string) $object['piggy_bank_id']),
'piggy_bank_name' => $this->clearString((string) $object['piggy_bank_name']),
'piggy_bank_id' => $this->integerFromValue((string) $object['piggy_bank_id']),
'piggy_bank_name' => $this->clearString((string) $object['piggy_bank_name']),
// some other interesting properties
'reconciled' => $this->convertBoolean((string) $object['reconciled']),
'notes' => $this->clearStringKeepNewlines((string) $object['notes']),
'tags' => $this->arrayFromValue($object['tags']),
'reconciled' => $this->convertBoolean((string) $object['reconciled']),
'notes' => $this->clearStringKeepNewlines((string) $object['notes']),
'tags' => $this->arrayFromValue($object['tags']),
// all custom fields:
'internal_reference' => $this->clearString((string) $object['internal_reference']),
'external_id' => $this->clearString((string) $object['external_id']),
'original_source' => sprintf('ff3-v%s', config('firefly.version')),
'recurrence_id' => $this->integerFromValue($object['recurrence_id']),
'bunq_payment_id' => $this->clearString((string) $object['bunq_payment_id']),
'external_url' => $this->clearString((string) $object['external_url']),
'internal_reference' => $this->clearString((string) $object['internal_reference']),
'external_id' => $this->clearString((string) $object['external_id']),
'original_source' => sprintf('ff3-v%s', config('firefly.version')),
'recurrence_id' => $this->integerFromValue($object['recurrence_id']),
'bunq_payment_id' => $this->clearString((string) $object['bunq_payment_id']),
'external_url' => $this->clearString((string) $object['external_url']),
'sepa_cc' => $this->clearString((string) $object['sepa_cc']),
'sepa_ct_op' => $this->clearString((string) $object['sepa_ct_op']),
'sepa_ct_id' => $this->clearString((string) $object['sepa_ct_id']),
'sepa_db' => $this->clearString((string) $object['sepa_db']),
'sepa_country' => $this->clearString((string) $object['sepa_country']),
'sepa_ep' => $this->clearString((string) $object['sepa_ep']),
'sepa_ci' => $this->clearString((string) $object['sepa_ci']),
'sepa_batch_id' => $this->clearString((string) $object['sepa_batch_id']),
'sepa_cc' => $this->clearString((string) $object['sepa_cc']),
'sepa_ct_op' => $this->clearString((string) $object['sepa_ct_op']),
'sepa_ct_id' => $this->clearString((string) $object['sepa_ct_id']),
'sepa_db' => $this->clearString((string) $object['sepa_db']),
'sepa_country' => $this->clearString((string) $object['sepa_country']),
'sepa_ep' => $this->clearString((string) $object['sepa_ep']),
'sepa_ci' => $this->clearString((string) $object['sepa_ci']),
'sepa_batch_id' => $this->clearString((string) $object['sepa_batch_id']),
// custom date fields. Must be Carbon objects. Presence is optional.
'interest_date' => $this->dateFromValue($object['interest_date']),
'book_date' => $this->dateFromValue($object['book_date']),
'process_date' => $this->dateFromValue($object['process_date']),
'due_date' => $this->dateFromValue($object['due_date']),
'payment_date' => $this->dateFromValue($object['payment_date']),
'invoice_date' => $this->dateFromValue($object['invoice_date']),
'interest_date' => $this->dateFromValue($object['interest_date']),
'book_date' => $this->dateFromValue($object['book_date']),
'process_date' => $this->dateFromValue($object['process_date']),
'due_date' => $this->dateFromValue($object['due_date']),
'payment_date' => $this->dateFromValue($object['payment_date']),
'invoice_date' => $this->dateFromValue($object['invoice_date']),
];
}
@@ -171,6 +177,7 @@ class StoreRequest extends FormRequest
{
app('log')->debug('Collect rules of TransactionStoreRequest');
$validProtocols = config('firefly.valid_url_protocols');
$locationRules = Location::requestRules([]);
return [
// basic fields for group:
@@ -178,6 +185,11 @@ class StoreRequest extends FormRequest
'error_if_duplicate_hash' => [new IsBoolean()],
'apply_rules' => [new IsBoolean()],
// location rules
'transactions.*.latitude' => $locationRules['latitude'],
'transactions.*.longitude' => $locationRules['longitude'],
'transactions.*.zoom_level' => $locationRules['zoom_level'],
// transaction rules (in array for splits):
'transactions.*.type' => 'required|in:withdrawal,deposit,transfer,opening-balance,reconciliation',
'transactions.*.date' => ['required', new IsDateOrTime()],

View File

@@ -57,6 +57,10 @@ class CronRequest extends FormRequest
if ($this->has('date')) {
$data['date'] = $this->getCarbonDate('date');
}
// catch NULL.
if (null === $data['date']) {
$data['date'] = today(config('app.timezone'));
}
return $data;
}
@@ -68,7 +72,7 @@ class CronRequest extends FormRequest
{
return [
'force' => 'in:true,false',
'date' => 'date',
'date' => 'nullable|date|after:1900-01-01|before:2099-12-31',
];
}
}

View File

@@ -55,7 +55,7 @@ class AccountController extends Controller
$userGroup = $this->validateUserGroup($request);
$this->repository = app(AccountRepositoryInterface::class);
$this->repository->setUserGroup($userGroup);
$this->default = app('amount')->getDefaultCurrency();
$this->default = app('amount')->getNativeCurrency();
$this->converter = app(ExchangeRateConverter::class);
return $next($request);

View File

@@ -57,7 +57,7 @@ class AccountController extends Controller
$this->repository = app(AccountRepositoryInterface::class);
$this->repository->setUserGroup($this->validateUserGroup($request));
$this->chartData = new ChartData();
$this->default = app('amount')->getDefaultCurrency();
$this->default = app('amount')->getNativeCurrency();
return $next($request);
}

View File

@@ -62,7 +62,7 @@ class BalanceController extends Controller
$this->repository->setUserGroup($userGroup);
$this->collector->setUserGroup($userGroup);
$this->chartData = new ChartData();
// $this->default = app('amount')->getDefaultCurrency();
// $this->default = app('amount')->getNativeCurrency();
return $next($request);
}
@@ -87,7 +87,7 @@ class BalanceController extends Controller
// prepare for currency conversion and data collection:
/** @var TransactionCurrency $default */
$default = app('amount')->getDefaultCurrency();
$default = app('amount')->getNativeCurrency();
// get journals for entire period:

View File

@@ -63,7 +63,7 @@ class BudgetController extends Controller
$this->repository = app(BudgetRepositoryInterface::class);
$this->blRepository = app(BudgetLimitRepositoryInterface::class);
$this->opsRepository = app(OperationsRepositoryInterface::class);
$this->currency = app('amount')->getDefaultCurrency();
$this->currency = app('amount')->getNativeCurrency();
$userGroup = $this->validateUserGroup($request);
$this->repository->setUserGroup($userGroup);
$this->opsRepository->setUserGroup($userGroup);

View File

@@ -82,7 +82,7 @@ class CategoryController extends Controller
/** @var Carbon $end */
$end = $this->parameters->get('end');
$accounts = $this->accountRepos->getAccountsByType([AccountTypeEnum::DEBT->value, AccountTypeEnum::LOAN->value, AccountTypeEnum::MORTGAGE->value, AccountTypeEnum::ASSET->value, AccountTypeEnum::DEFAULT->value]);
$default = app('amount')->getDefaultCurrency();
$default = app('amount')->getNativeCurrency();
$converter = new ExchangeRateConverter();
$currencies = [];
$return = [];

View File

@@ -118,7 +118,7 @@ class BasicController extends Controller
private function getBalanceInformation(Carbon $start, Carbon $end): array
{
$object = new SummaryBalanceGrouped();
$default = app('amount')->getDefaultCurrency();
$default = app('amount')->getNativeCurrency();
$object->setDefault($default);
@@ -233,7 +233,7 @@ class BasicController extends Controller
$available = $this->abRepository->getAvailableBudgetWithCurrency($start, $end);
$budgets = $this->budgetRepository->getActiveBudgets();
$spent = $this->opsRepository->listExpenses($start, $end, null, $budgets);
$default = app('amount')->getDefaultCurrency();
$default = app('amount')->getNativeCurrency();
$currencies = [];
$converter = new ExchangeRateConverter();

View File

@@ -109,8 +109,8 @@ class InfiniteListRequest extends FormRequest
public function rules(): array
{
return [
'start' => 'date',
'end' => 'date|after:start',
'start' => 'date|after:1900-01-01|before:2099-12-31',
'end' => 'date|after:start|after:1900-01-01|before:2099-12-31',
'start_row' => 'integer|min:0|max:4294967296',
'end_row' => 'integer|min:0|max:4294967296|gt:start_row',
];

View File

@@ -84,8 +84,8 @@ class ListRequest extends FormRequest
public function rules(): array
{
return [
'start' => 'date',
'end' => 'date|after:start',
'start' => 'date|after:1900-01-01|before:2099-12-31',
'end' => 'date|after:start|after:1900-01-01|before:2099-12-31',
];
}
}

View File

@@ -63,7 +63,7 @@ class CorrectsCurrencies extends Command
$repos = app(CurrencyRepositoryInterface::class);
// first check if the user has any default currency (not necessarily the case, so can be forced).
$defaultCurrency = app('amount')->getDefaultCurrencyByUserGroup($userGroup);
$defaultCurrency = app('amount')->getNativeCurrencyByUserGroup($userGroup);
Log::debug(sprintf('Now correcting currencies for user group #%d', $userGroup->id));
$found = [$defaultCurrency->id];

View File

@@ -88,7 +88,7 @@ class CorrectsNativeAmounts extends Command
// do a check with the group's currency so we can skip some stuff.
Preferences::mark();
$currency = app('amount')->getDefaultCurrencyByUserGroup($userGroup);
$currency = app('amount')->getNativeCurrencyByUserGroup($userGroup);
$this->recalculatePiggyBanks($userGroup, $currency);
$this->recalculateBudgets($userGroup, $currency);

View File

@@ -132,6 +132,6 @@ class CorrectsOpeningBalanceCurrencies extends Command
$repos = app(AccountRepositoryInterface::class);
$repos->setUser($account->user);
return $repos->getAccountCurrency($account) ?? app('amount')->getDefaultCurrencyByUserGroup($account->userGroup);
return $repos->getAccountCurrency($account) ?? app('amount')->getNativeCurrencyByUserGroup($account->userGroup);
}
}

View File

@@ -38,7 +38,7 @@ class CreatesDatabase extends Command
public function handle(): int
{
if ('mysql' !== env('DB_CONNECTION')) {
if ('mysql' !== env('DB_CONNECTION')) { // @phpstan-ignore larastan.noEnvCallsOutsideOfConfig */
$this->friendlyInfo(sprintf('CreateDB does not apply to "%s", skipped.', env('DB_CONNECTION')));
return 0;
@@ -60,7 +60,7 @@ class CreatesDatabase extends Command
// when it fails, display error
try {
$pdo = new \PDO($dsn, env('DB_USERNAME'), env('DB_PASSWORD'), $options);
$pdo = new \PDO($dsn, (string) env('DB_USERNAME'), (string) env('DB_PASSWORD'), $options);
} catch (\PDOException $e) {
$this->friendlyError(sprintf('Error when connecting to DB: %s', $e->getMessage()));

View File

@@ -107,7 +107,7 @@ class UpgradesAccountCurrencies extends Command
$accounts = $this->accountRepos->getAccountsByType([AccountTypeEnum::DEFAULT->value, AccountTypeEnum::ASSET->value]);
// get user's currency preference:
$defaultCurrency = app('amount')->getDefaultCurrencyByUserGroup($user->userGroup);
$defaultCurrency = app('amount')->getNativeCurrencyByUserGroup($user->userGroup);
/** @var Account $account */
foreach ($accounts as $account) {

View File

@@ -66,7 +66,7 @@ class UpgradesBudgetLimits extends Command
/** @var null|User $user */
$user = $budget->user;
if (null !== $user) {
$currency = app('amount')->getDefaultCurrencyByUserGroup($user->userGroup);
$currency = app('amount')->getNativeCurrencyByUserGroup($user->userGroup);
$budgetLimit->transaction_currency_id = $currency->id;
$budgetLimit->save();
$this->friendlyInfo(

View File

@@ -90,7 +90,7 @@ class UpgradesMultiPiggyBanks extends Command
$this->repository->setUser($piggyBank->account->user);
$this->accountRepository->setUser($piggyBank->account->user);
$repetition = $this->repository->getRepetition($piggyBank, true);
$currency = $this->accountRepository->getAccountCurrency($piggyBank->account) ?? app('amount')->getDefaultCurrencyByUserGroup($piggyBank->account->user->userGroup);
$currency = $this->accountRepository->getAccountCurrency($piggyBank->account) ?? app('amount')->getNativeCurrencyByUserGroup($piggyBank->account->user->userGroup);
// update piggy bank to have a currency.
$piggyBank->transaction_currency_id = $currency->id;

View File

@@ -24,6 +24,7 @@ declare(strict_types=1);
namespace FireflyIII\Exceptions;
use Brick\Math\Exception\NumberFormatException;
use FireflyIII\Jobs\MailError;
use Illuminate\Auth\Access\AuthorizationException;
use Illuminate\Auth\AuthenticationException;
@@ -124,7 +125,7 @@ class Handler extends ExceptionHandler
if ($e instanceof BadRequestHttpException) {
app('log')->debug('Return JSON BadRequestHttpException.');
return response()->json(['message' => $e->getMessage(), 'exception' => 'BadRequestHttpException'], 400);
return response()->json(['message' => $e->getMessage(), 'exception' => 'HttpException'], 400);
}
if ($e instanceof BadHttpHeaderException) {
@@ -133,6 +134,14 @@ class Handler extends ExceptionHandler
return response()->json(['message' => $e->getMessage(), 'exception' => 'BadHttpHeaderException'], $e->statusCode);
}
if (($e instanceof ValidationException || $e instanceof NumberFormatException) && $expectsJson) {
$errorCode = 422;
return response()->json(
['message' => sprintf('Validation exception: %s', $e->getMessage()), 'errors' => ['field' => 'Field is invalid']],
$errorCode
);
}
if ($expectsJson) {
$errorCode = 500;
@@ -156,7 +165,7 @@ class Handler extends ExceptionHandler
app('log')->debug(sprintf('Return JSON %s.', get_class($e)));
return response()->json(
['message' => sprintf('Internal Firefly III Exception: %s', $e->getMessage()), 'exception' => get_class($e)],
['message' => sprintf('Internal Firefly III Exception: %s', $e->getMessage()), 'exception' => 'UndisclosedException'],
$errorCode
);
}

View File

@@ -49,7 +49,7 @@ class BillFactory
app('log')->debug(sprintf('Now in %s', __METHOD__), $data);
$factory = app(TransactionCurrencyFactory::class);
$currency = $factory->find((int) ($data['currency_id'] ?? null), (string) ($data['currency_code'] ?? null)) ??
app('amount')->getDefaultCurrencyByUserGroup($this->user->userGroup);
app('amount')->getNativeCurrencyByUserGroup($this->user->userGroup);
try {
$skip = array_key_exists('skip', $data) ? $data['skip'] : 0;

View File

@@ -121,7 +121,7 @@ class PiggyBankFactory
private function getCurrency(array $data): TransactionCurrency
{
// currency:
$defaultCurrency = app('amount')->getDefaultCurrency();
$defaultCurrency = app('amount')->getNativeCurrency();
$currency = null;
if (array_key_exists('transaction_currency_code', $data)) {
$currency = $this->currencyRepository->findByCode((string) ($data['transaction_currency_code'] ?? ''));

View File

@@ -466,7 +466,7 @@ class TransactionJournalFactory
$preference = $this->accountRepository->getAccountCurrency($account);
if (null === $preference && null === $currency) {
// return user's default:
return app('amount')->getDefaultCurrencyByUserGroup($this->user->userGroup);
return app('amount')->getNativeCurrencyByUserGroup($this->user->userGroup);
}
$result = $preference ?? $currency;
app('log')->debug(sprintf('Currency is now #%d (%s) because of account #%d (%s)', $result->id, $result->code, $account->id, $account->name));
@@ -576,7 +576,7 @@ class TransactionJournalFactory
private function storeLocation(TransactionJournal $journal, NullArrayObject $data): void
{
if (true === $data['store_location']) {
if (null !== $data['longitude'] && null !== $data['latitude'] && null !== $data['zoom_level']) {
$location = new Location();
$location->longitude = $data['longitude'];
$location->latitude = $data['latitude'];

View File

@@ -135,7 +135,7 @@ class MonthReportGenerator implements ReportGeneratorInterface
$journals = array_reverse($journals, true);
$dayBeforeBalance = Steam::finalAccountBalance($account, $date);
$startBalance = $dayBeforeBalance['balance'];
$defaultCurrency = app('amount')->getDefaultCurrencyByUserGroup($account->user->userGroup);
$defaultCurrency = app('amount')->getNativeCurrencyByUserGroup($account->user->userGroup);
$currency = $accountRepository->getAccountCurrency($account) ?? $defaultCurrency;
foreach ($journals as $index => $journal) {

View File

@@ -47,7 +47,7 @@ class AccountObserver
if (!Amount::convertToNative($account->user)) {
return;
}
$userCurrency = app('amount')->getDefaultCurrencyByUserGroup($account->user->userGroup);
$userCurrency = app('amount')->getNativeCurrencyByUserGroup($account->user->userGroup);
$repository = app(AccountRepositoryInterface::class);
$currency = $repository->getAccountCurrency($account);
if (null !== $currency && $currency->id !== $userCurrency->id && '' !== (string) $account->virtual_balance && 0 !== bccomp($account->virtual_balance, '0')) {

View File

@@ -48,7 +48,7 @@ class AutoBudgetObserver
if (!Amount::convertToNative($autoBudget->budget->user)) {
return;
}
$userCurrency = app('amount')->getDefaultCurrencyByUserGroup($autoBudget->budget->user->userGroup);
$userCurrency = app('amount')->getNativeCurrencyByUserGroup($autoBudget->budget->user->userGroup);
$autoBudget->native_amount = null;
if ($autoBudget->transactionCurrency->id !== $userCurrency->id) {
$converter = new ExchangeRateConverter();

View File

@@ -50,7 +50,7 @@ class AvailableBudgetObserver
return;
}
$userCurrency = app('amount')->getDefaultCurrencyByUserGroup($availableBudget->user->userGroup);
$userCurrency = app('amount')->getNativeCurrencyByUserGroup($availableBudget->user->userGroup);
$availableBudget->native_amount = null;
if ($availableBudget->transactionCurrency->id !== $userCurrency->id) {
$converter = new ExchangeRateConverter();

View File

@@ -59,7 +59,7 @@ class BillObserver
if (!Amount::convertToNative($bill->user)) {
return;
}
$userCurrency = app('amount')->getDefaultCurrencyByUserGroup($bill->user->userGroup);
$userCurrency = app('amount')->getNativeCurrencyByUserGroup($bill->user->userGroup);
$bill->native_amount_min = null;
$bill->native_amount_max = null;
if ($bill->transactionCurrency->id !== $userCurrency->id) {

View File

@@ -50,7 +50,7 @@ class BudgetLimitObserver
return;
}
$userCurrency = app('amount')->getDefaultCurrencyByUserGroup($budgetLimit->budget->user->userGroup);
$userCurrency = app('amount')->getNativeCurrencyByUserGroup($budgetLimit->budget->user->userGroup);
$budgetLimit->native_amount = null;
if ($budgetLimit->transactionCurrency->id !== $userCurrency->id) {
$converter = new ExchangeRateConverter();

View File

@@ -48,7 +48,7 @@ class PiggyBankEventObserver
if (!Amount::convertToNative($event->piggyBank->accounts()->first()->user)) {
return;
}
$userCurrency = app('amount')->getDefaultCurrencyByUserGroup($event->piggyBank->accounts()->first()->user->userGroup);
$userCurrency = app('amount')->getNativeCurrencyByUserGroup($event->piggyBank->accounts()->first()->user->userGroup);
$event->native_amount = null;
if ($event->piggyBank->transactionCurrency->id !== $userCurrency->id) {
$converter = new ExchangeRateConverter();

View File

@@ -70,7 +70,7 @@ class PiggyBankObserver
return;
}
$userCurrency = app('amount')->getDefaultCurrencyByUserGroup($group);
$userCurrency = app('amount')->getNativeCurrencyByUserGroup($group);
$piggyBank->native_target_amount = null;
if ($piggyBank->transactionCurrency->id !== $userCurrency->id) {
$converter = new ExchangeRateConverter();

View File

@@ -71,7 +71,7 @@ class TransactionObserver
if (!Amount::convertToNative($transaction->transactionJournal->user)) {
return;
}
$userCurrency = app('amount')->getDefaultCurrencyByUserGroup($transaction->transactionJournal->user->userGroup);
$userCurrency = app('amount')->getNativeCurrencyByUserGroup($transaction->transactionJournal->user->userGroup);
$transaction->native_amount = null;
$transaction->native_foreign_amount = null;
// first normal amount

View File

@@ -77,7 +77,7 @@ class NetWorth implements NetWorthInterface
return $cache->get();
}
Log::debug(sprintf('Now in byAccounts("%s", "%s")', $ids, $date->format('Y-m-d H:i:s')));
$default = Amount::getDefaultCurrency();
$default = Amount::getNativeCurrency();
$netWorth = [];
$balances = Steam::finalAccountsBalance($accounts, $date);

View File

@@ -106,6 +106,7 @@ class IndexController extends Controller
$account->interestPeriod = (string) trans(sprintf('firefly.interest_calc_%s', $this->repository->getMetaValue($account, 'interest_period')));
$account->accountTypeString = (string) trans(sprintf('firefly.account_type_%s', $account->accountType->type));
$account->current_debt = '0';
$account->currency = $currency ?? $this->defaultCurrency;
$account->iban = implode(' ', str_split((string) $account->iban, 4));
}
);

View File

@@ -95,17 +95,22 @@ abstract class Controller extends BaseController
// share is alpha, is beta
$isAlpha = false;
$isBeta = false;
$isDevelop = false;
if (str_contains(config('firefly.version'), 'alpha')) {
$isAlpha = true;
}
if (str_contains(config('firefly.version'), 'develop') || str_contains(config('firefly.version'), 'branch')) {
$isDevelop = true;
}
$isBeta = false;
if (str_contains(config('firefly.version'), 'beta')) {
$isBeta = true;
}
View::share('FF_IS_ALPHA', $isAlpha);
View::share('FF_IS_BETA', $isBeta);
View::share('FF_IS_DEVELOP', $isDevelop);
$this->middleware(
function ($request, $next): mixed {
@@ -118,7 +123,7 @@ abstract class Controller extends BaseController
$this->defaultCurrency =null;
// get shown-intro-preference:
if (auth()->check()) {
$this->defaultCurrency = Amount::getDefaultCurrency();
$this->defaultCurrency = Amount::getNativeCurrency();
$language = Steam::getLanguage();
$locale = Steam::getLocale();
$darkMode = app('preferences')->get('darkMode', 'browser')->data;

View File

@@ -31,6 +31,9 @@ use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Http\Middleware\IsDemoUser;
use FireflyIII\Models\TransactionType;
use FireflyIII\Repositories\PiggyBank\PiggyBankRepositoryInterface;
use FireflyIII\Support\Facades\Amount;
use FireflyIII\Support\Facades\Preferences;
use FireflyIII\Support\Facades\Steam;
use FireflyIII\Support\Http\Controllers\GetConfigurationData;
use FireflyIII\Support\Models\AccountBalanceCalculator;
use FireflyIII\User;
@@ -61,7 +64,7 @@ class DebugController extends Controller
$this->middleware(IsDemoUser::class)->except(['displayError']);
}
public function routes(): never
public function routes(Request $request): never
{
if (!auth()->user()->hasRole('owner')) {
throw new NotFoundHttpException();
@@ -69,6 +72,46 @@ class DebugController extends Controller
/** @var iterable $routes */
$routes = Route::getRoutes();
if ('true' === $request->get('api')) {
$collection = [];
$i = 0;
echo 'PATHS="';
/** @var \Illuminate\Routing\Route $route */
foreach ($routes as $route) {
++$i;
// skip API and other routes.
if (!str_starts_with($route->uri(), 'api/v1')
) {
continue;
}
// skip non GET routes
if (!in_array('GET', $route->methods(), true)) {
continue;
}
// no name route:
if (null === $route->getName()) {
var_dump($route);
exit;
}
echo substr($route->uri(), 3);
if (0 === $i % 5) {
echo '"<br>PATHS="${PATHS},';
}
if (0 !== $i % 5) {
echo ',';
}
}
exit;
}
$return = [];
/** @var \Illuminate\Routing\Route $route */
@@ -153,7 +196,7 @@ class DebugController extends Controller
*/
public function flush(Request $request)
{
app('preferences')->mark();
Preferences::mark();
$request->session()->forget(['start', 'end', '_previous', 'viewRange', 'range', 'is_custom_range', 'temp-mfa-secret', 'temp-mfa-codes']);
Artisan::call('cache:clear');
@@ -223,8 +266,8 @@ class DebugController extends Controller
private function getSystemInformation(): array
{
$maxFileSize = app('steam')->phpBytes((string) ini_get('upload_max_filesize'));
$maxPostSize = app('steam')->phpBytes((string) ini_get('post_max_size'));
$maxFileSize = Steam::phpBytes((string) ini_get('upload_max_filesize'));
$maxPostSize = Steam::phpBytes((string) ini_get('post_max_size'));
$drivers = \DB::availableDrivers();
$currentDriver = \DB::getDriverName();
@@ -314,7 +357,7 @@ class DebugController extends Controller
];
}
private function getuserInfo(): array
private function getUserInfo(): array
{
$userFlags = $this->getUserFlags();
@@ -324,7 +367,7 @@ class DebugController extends Controller
// set languages, see what happens:
$original = setlocale(LC_ALL, '0');
$localeAttempts = [];
$parts = app('steam')->getLocaleArray(app('steam')->getLocale());
$parts = Steam::getLocaleArray(Steam::getLocale());
foreach ($parts as $code) {
$code = trim($code);
app('log')->debug(sprintf('Trying to set %s', $code));
@@ -334,14 +377,15 @@ class DebugController extends Controller
setlocale(LC_ALL, (string) $original);
return [
'user_id' => auth()->user()->id,
'user_count' => User::count(),
'user_flags' => $userFlags,
'user_agent' => $userAgent,
'locale_attempts' => $localeAttempts,
'locale' => app('steam')->getLocale(),
'language' => app('steam')->getLanguage(),
'view_range' => app('preferences')->get('viewRange', '1M')->data,
'user_id' => auth()->user()->id,
'user_count' => User::count(),
'user_flags' => $userFlags,
'user_agent' => $userAgent,
'convert_to_native' => Amount::convertToNative(),
'locale_attempts' => $localeAttempts,
'locale' => Steam::getLocale(),
'language' => Steam::getLanguage(),
'view_range' => Preferences::get('viewRange', '1M')->data,
];
}

View File

@@ -31,6 +31,7 @@ use FireflyIII\Http\Requests\PreferencesRequest;
use FireflyIII\Models\Account;
use FireflyIII\Models\Preference;
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use FireflyIII\Support\Facades\Preferences;
use FireflyIII\User;
use Illuminate\Contracts\View\Factory;
use Illuminate\Http\RedirectResponse;
@@ -93,35 +94,35 @@ class PreferencesController extends Controller
/** @var array<int, int> $accountIds */
$accountIds = $accounts->pluck('id')->toArray();
$viewRange = app('navigation')->getViewRange(false);
$frontpageAccountsPref = app('preferences')->get('frontpageAccounts', $accountIds);
$frontpageAccountsPref = Preferences::get('frontpageAccounts', $accountIds);
$frontpageAccounts = $frontpageAccountsPref->data;
if (!is_array($frontpageAccounts)) {
$frontpageAccounts = $accountIds;
}
$language = app('steam')->getLanguage();
$languages = config('firefly.languages');
$locale = app('preferences')->get('locale', config('firefly.default_locale', 'equal'))->data;
$listPageSize = app('preferences')->get('listPageSize', 50)->data;
$darkMode = app('preferences')->get('darkMode', 'browser')->data;
$customFiscalYear = app('preferences')->get('customFiscalYear', 0)->data;
$fiscalYearStartStr = app('preferences')->get('fiscalYearStart', '01-01')->data;
$locale = Preferences::get('locale', config('firefly.default_locale', 'equal'))->data;
$listPageSize = Preferences::get('listPageSize', 50)->data;
$darkMode = Preferences::get('darkMode', 'browser')->data;
$customFiscalYear = Preferences::get('customFiscalYear', 0)->data;
$fiscalYearStartStr = Preferences::get('fiscalYearStart', '01-01')->data;
$convertToNative = $this->convertToNative;
if (is_array($fiscalYearStartStr)) {
$fiscalYearStartStr = '01-01';
}
$fiscalYearStart = sprintf('%s-%s', date('Y'), (string) $fiscalYearStartStr);
$tjOptionalFields = app('preferences')->get('transaction_journal_optional_fields', [])->data;
$tjOptionalFields = Preferences::get('transaction_journal_optional_fields', [])->data;
$availableDarkModes = config('firefly.available_dark_modes');
// notifications settings
$slackUrl = app('preferences')->getEncrypted('slack_webhook_url', '')->data;
$pushoverAppToken = (string) app('preferences')->getEncrypted('pushover_app_token', '')->data;
$pushoverUserToken = (string) app('preferences')->getEncrypted('pushover_user_token', '')->data;
$ntfyServer = app('preferences')->getEncrypted('ntfy_server', 'https://ntfy.sh')->data;
$ntfyTopic = (string) app('preferences')->getEncrypted('ntfy_topic', '')->data;
$ntfyAuth = app('preferences')->get('ntfy_auth', false)->data;
$ntfyUser = app('preferences')->getEncrypted('ntfy_user', '')->data;
$ntfyPass = (string) app('preferences')->getEncrypted('ntfy_pass', '')->data;
$slackUrl = Preferences::getEncrypted('slack_webhook_url', '')->data;
$pushoverAppToken = (string) Preferences::getEncrypted('pushover_app_token', '')->data;
$pushoverUserToken = (string) Preferences::getEncrypted('pushover_user_token', '')->data;
$ntfyServer = Preferences::getEncrypted('ntfy_server', 'https://ntfy.sh')->data;
$ntfyTopic = (string) Preferences::getEncrypted('ntfy_topic', '')->data;
$ntfyAuth = Preferences::get('ntfy_auth', false)->data;
$ntfyUser = Preferences::getEncrypted('ntfy_user', '')->data;
$ntfyPass = (string) Preferences::getEncrypted('ntfy_pass', '')->data;
$channels = config('notifications.channels');
$forcedAvailability = [];
@@ -131,7 +132,7 @@ class PreferencesController extends Controller
if (true === $info['enabled']) {
$notifications[$key]
= [
'enabled' => true === app('preferences')->get(sprintf('notification_%s', $key), true)->data,
'enabled' => true === Preferences::get(sprintf('notification_%s', $key), true)->data,
'configurable' => $info['configurable'],
];
}
@@ -221,7 +222,7 @@ class PreferencesController extends Controller
foreach ($request->get('frontpageAccounts') as $id) {
$frontpageAccounts[] = (int) $id;
}
app('preferences')->set('frontpageAccounts', $frontpageAccounts);
Preferences::set('frontpageAccounts', $frontpageAccounts);
}
// extract notifications:
@@ -229,15 +230,15 @@ class PreferencesController extends Controller
foreach (config('notifications.notifications.user') as $key => $info) {
$key = sprintf('notification_%s', $key);
if (array_key_exists($key, $all)) {
app('preferences')->set($key, true);
Preferences::set($key, true);
}
if (!array_key_exists($key, $all)) {
app('preferences')->set($key, false);
Preferences::set($key, false);
}
}
// view range:
app('preferences')->set('viewRange', $request->get('viewRange'));
Preferences::set('viewRange', $request->get('viewRange'));
// forget session values:
session()->forget('start');
session()->forget('end');
@@ -249,13 +250,13 @@ class PreferencesController extends Controller
$variables = ['slack_webhook_url', 'pushover_app_token', 'pushover_user_token', 'ntfy_server', 'ntfy_topic', 'ntfy_user', 'ntfy_pass'];
foreach ($variables as $variable) {
if ('' === $all[$variable]) {
app('preferences')->delete($variable);
Preferences::delete($variable);
}
if ('' !== $all[$variable]) {
app('preferences')->setEncrypted($variable, $all[$variable]);
Preferences::setEncrypted($variable, $all[$variable]);
}
}
app('preferences')->set('ntfy_auth', $all['ntfy_auth'] ?? false);
Preferences::set('ntfy_auth', $all['ntfy_auth'] ?? false);
}
// convert native
@@ -265,30 +266,30 @@ class PreferencesController extends Controller
Log::debug('User sets convertToNative to true.');
event(new UserGroupChangedDefaultCurrency(auth()->user()->userGroup));
}
app('preferences')->set('convert_to_native', $convertToNative);
Preferences::set('convert_to_native', $convertToNative);
// custom fiscal year
$customFiscalYear = 1 === (int) $request->get('customFiscalYear');
$string = strtotime((string) $request->get('fiscalYearStart'));
if (false !== $string) {
$fiscalYearStart = date('m-d', $string);
app('preferences')->set('customFiscalYear', $customFiscalYear);
app('preferences')->set('fiscalYearStart', $fiscalYearStart);
Preferences::set('customFiscalYear', $customFiscalYear);
Preferences::set('fiscalYearStart', $fiscalYearStart);
}
// save page size:
app('preferences')->set('listPageSize', 50);
Preferences::set('listPageSize', 50);
$listPageSize = (int) $request->get('listPageSize');
if ($listPageSize > 0 && $listPageSize < 1337) {
app('preferences')->set('listPageSize', $listPageSize);
Preferences::set('listPageSize', $listPageSize);
}
// language:
/** @var Preference $currentLang */
$currentLang = app('preferences')->get('language', 'en_US');
$currentLang = Preferences::get('language', 'en_US');
$lang = $request->get('language');
if (array_key_exists($lang, config('firefly.languages'))) {
app('preferences')->set('language', $lang);
Preferences::set('language', $lang);
}
if ($currentLang->data !== $lang) {
// this string is untranslated on purpose.
@@ -299,7 +300,7 @@ class PreferencesController extends Controller
if (!auth()->user()->hasRole('demo')) {
$locale = (string) $request->get('locale');
$locale = '' === $locale ? null : $locale;
app('preferences')->set('locale', $locale);
Preferences::set('locale', $locale);
}
// optional fields for transactions:
@@ -318,16 +319,16 @@ class PreferencesController extends Controller
'location' => array_key_exists('location', $setOptions),
'links' => array_key_exists('links', $setOptions),
];
app('preferences')->set('transaction_journal_optional_fields', $optionalTj);
Preferences::set('transaction_journal_optional_fields', $optionalTj);
// dark mode
$darkMode = $request->get('darkMode') ?? 'browser';
if (in_array($darkMode, config('firefly.available_dark_modes'), true)) {
app('preferences')->set('darkMode', $darkMode);
Preferences::set('darkMode', $darkMode);
}
session()->flash('success', (string) trans('firefly.saved_preferences'));
app('preferences')->mark();
Preferences::mark();
return redirect(route('preferences.index'));
}

View File

@@ -42,8 +42,6 @@ class EditController extends Controller
$mainTitleIcon = 'fa-book';
app('log')->debug(sprintf('Now at %s', __METHOD__));
return view('administrations.edit') // @phpstan-ignore-line
->with(compact('title', 'subTitle', 'mainTitleIcon'))
;
return view('administrations.edit')->with(compact('title', 'subTitle', 'mainTitleIcon'));
}
}

View File

@@ -159,6 +159,7 @@ class InterestingMessage
/** @var User $user */
$user = auth()->user();
/** @var null|UserGroup $userGroup */
$userGroup = UserGroup::find($userGroupId);
$valid = false;
$memberships = $user->groupMemberships()->get();

View File

@@ -118,7 +118,7 @@ class Range
// save some formats:
$monthAndDayFormat = (string) trans('config.month_and_day_js', [], $locale);
$dateTimeFormat = (string) trans('config.date_time_js', [], $locale);
$defaultCurrency = Amount::getDefaultCurrency();
$defaultCurrency = Amount::getNativeCurrency();
// also format for moment JS:
$madMomentJS = (string) trans('config.month_and_day_moment_js', [], $locale);

View File

@@ -126,7 +126,7 @@ class PiggyBankStoreRequest extends FormRequest
$currencyId = (int) ($data['transaction_currency_id'] ?? 0);
$currency = TransactionCurrency::find($currencyId);
if (null === $currency) {
return Amount::getDefaultCurrency();
return Amount::getNativeCurrency();
}
return $currency;

View File

@@ -129,7 +129,7 @@ class PiggyBankUpdateRequest extends FormRequest
$currencyId = (int) ($data['transaction_currency_id'] ?? 0);
$currency = TransactionCurrency::find($currencyId);
if (null === $currency) {
return Amount::getDefaultCurrency();
return Amount::getNativeCurrency();
}
return $currency;

View File

@@ -419,7 +419,9 @@ class CreateRecurringTransactions implements ShouldQueue
/** @var RecurrenceTransaction $transaction */
foreach ($transactions as $index => $transaction) {
$single = [
'type' => null === $transaction->transactionType->type ? strtolower($recurrence->transactionType->type) : strtolower($transaction->transactionType->type),
'type' => null === $transaction?->transactionType?->type ?
strtolower($recurrence->transactionType->type) :
strtolower($transaction->transactionType->type),
'date' => $date,
'user' => $recurrence->user_id,
'currency_id' => $transaction->transaction_currency_id,

View File

@@ -73,7 +73,7 @@ class TransactionCurrency extends Model
public function refreshForUser(User $user): void
{
$current = $user->userGroup->currencies()->where('transaction_currencies.id', $this->id)->first();
$native = app('amount')->getDefaultCurrencyByUserGroup($user->userGroup);
$native = app('amount')->getNativeCurrencyByUserGroup($user->userGroup);
$this->userGroupNative = $native->id === $this->id;
$this->userGroupEnabled = null !== $current;
}

View File

@@ -23,6 +23,9 @@ declare(strict_types=1);
namespace FireflyIII\Providers;
use Barryvdh\Debugbar\DataCollector\QueryCollector;
use Barryvdh\Debugbar\Facades\Debugbar;
use DebugBar\DebugBarException;
use Illuminate\Support\Facades\Blade;
use Illuminate\Support\Facades\Response;
use Illuminate\Support\Facades\Route;
@@ -50,6 +53,17 @@ class AppServiceProvider extends ServiceProvider
$headers['X-Trace-Id'] = $uuid;
}
if (config('app.debug')) {
try {
/** @var QueryCollector $collector */
$collector = Debugbar::getCollector('queries');
$info = $collector->collect();
$headers['X-Debug-QueryCount'] = $info['nb_statements'] ?? 0;
} catch (DebugBarException $e) {
// ignore error.
}
}
return response()
->json($value)
->withHeaders($headers)

View File

@@ -355,7 +355,7 @@ class AccountRepository implements AccountRepositoryInterface
if (AccountTypeEnum::ASSET->value !== $account->accountType->type) {
throw new FireflyException(sprintf('%s is not an asset account.', $account->name));
}
$currency = $this->getAccountCurrency($account) ?? app('amount')->getDefaultCurrency();
$currency = $this->getAccountCurrency($account) ?? app('amount')->getNativeCurrency();
$name = trans('firefly.reconciliation_account_name', ['name' => $account->name, 'currency' => $currency->code]);
/** @var AccountType $type */

View File

@@ -53,7 +53,7 @@ class AccountTasker implements AccountTaskerInterface
/** @var AccountRepositoryInterface $repository */
$repository = app(AccountRepositoryInterface::class);
$defaultCurrency = app('amount')->getDefaultCurrencyByUserGroup($this->user->userGroup);
$defaultCurrency = app('amount')->getNativeCurrencyByUserGroup($this->user->userGroup);
$return = [
'accounts' => [],
@@ -143,7 +143,7 @@ class AccountTasker implements AccountTaskerInterface
*/
private function groupExpenseByDestination(array $array): array
{
$defaultCurrency = app('amount')->getDefaultCurrencyByUserGroup($this->user->userGroup);
$defaultCurrency = app('amount')->getNativeCurrencyByUserGroup($this->user->userGroup);
/** @var CurrencyRepositoryInterface $currencyRepos */
$currencyRepos = app(CurrencyRepositoryInterface::class);
@@ -231,7 +231,7 @@ class AccountTasker implements AccountTaskerInterface
*/
private function groupIncomeBySource(array $array): array
{
$defaultCurrency = app('amount')->getDefaultCurrencyByUserGroup($this->user->userGroup);
$defaultCurrency = app('amount')->getNativeCurrencyByUserGroup($this->user->userGroup);
/** @var CurrencyRepositoryInterface $currencyRepos */
$currencyRepos = app(CurrencyRepositoryInterface::class);

View File

@@ -275,7 +275,7 @@ class BillRepository implements BillRepositoryInterface
];
$result[$currencyId]['sum'] = bcadd($result[$currencyId]['sum'], $transaction->amount);
$result[$currencyId]['native_sum'] = bcadd($result[$currencyId]['native_sum'], $transaction->native_amount ?? '0');
if ($journal->foreign_currency_id === Amount::getDefaultCurrency()->id) {
if ($journal->foreign_currency_id === Amount::getNativeCurrency()->id) {
$result[$currencyId]['native_sum'] = bcadd($result[$currencyId]['native_sum'], $transaction->amount);
}
++$result[$currencyId]['count'];
@@ -406,7 +406,7 @@ class BillRepository implements BillRepositoryInterface
];
$result[$currencyId]['sum'] = bcadd($result[$currencyId]['sum'], $transaction->amount);
$result[$currencyId]['native_sum'] = bcadd($result[$currencyId]['native_sum'], $transaction->native_amount ?? '0');
if ($journal->foreign_currency_id === Amount::getDefaultCurrency()->id) {
if ($journal->foreign_currency_id === Amount::getNativeCurrency()->id) {
$result[$currencyId]['native_sum'] = bcadd($result[$currencyId]['native_sum'], $transaction->amount);
}
++$result[$currencyId]['count'];
@@ -530,7 +530,7 @@ class BillRepository implements BillRepositoryInterface
$bills = $this->getActiveBills();
$return = [];
$convertToNative = Amount::convertToNative($this->user);
$default = app('amount')->getDefaultCurrency();
$default = app('amount')->getNativeCurrency();
/** @var Bill $bill */
foreach ($bills as $bill) {
@@ -575,7 +575,7 @@ class BillRepository implements BillRepositoryInterface
$bills = $this->getActiveBills();
$return = [];
$convertToNative = Amount::convertToNative($this->user);
$default = app('amount')->getDefaultCurrency();
$default = app('amount')->getNativeCurrency();
/** @var Bill $bill */
foreach ($bills as $bill) {

View File

@@ -142,7 +142,7 @@ class AvailableBudgetRepository implements AvailableBudgetRepositoryInterface
// use native amount if necessary?
$convertToNative = Amount::convertToNative($this->user);
$default = Amount::getDefaultCurrency();
$default = Amount::getNativeCurrency();
/** @var AvailableBudget $availableBudget */
foreach ($availableBudgets as $availableBudget) {

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