Compare commits

..

35 Commits

Author SHA1 Message Date
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
github-actions
04d1e8fd59 Auto commit for release 'develop' on 2025-01-19 2025-01-19 11:46:08 +01:00
James Cole
9d2f57e40a Fix menu 2025-01-19 11:41:24 +01:00
James Cole
ae366341cc Rename default to native. 2025-01-19 11:40:07 +01:00
James Cole
3766128cb8 Add code for administrations. 2025-01-19 11:34:23 +01:00
James Cole
950c60d55c Fix https://github.com/firefly-iii/firefly-iii/issues/9667 2025-01-19 07:18:07 +01:00
James Cole
4b2807de48 rename admin to settings. 2025-01-18 17:26:31 +01:00
James Cole
649736cb31 Rename admin to settings. 2025-01-18 17:22:11 +01:00
James Cole
6a121a8a78 Merge branch 'develop' of github.com:firefly-iii/firefly-iii into develop
# Conflicts:
#	app/Transformers/AccountTransformer.php
2025-01-18 17:21:34 +01:00
James Cole
f69b9ac9da Commit updated transformers. 2025-01-18 17:20:39 +01:00
James Cole
23d70a2fac Rename to settings 2025-01-18 17:20:21 +01:00
James Cole
d178ff9de0 Rename admin routes to settings. 2025-01-18 17:20:06 +01:00
James Cole
3ecad3457f Rename "administration" to "settings" 2025-01-18 17:10:47 +01:00
github-actions
fa6c621968 Auto commit for release 'develop' on 2025-01-15 2025-01-15 20:30:00 +01:00
James Cole
df863b6cff Merge branch 'develop' of github.com:firefly-iii/firefly-iii into develop 2025-01-15 18:54:56 +01:00
James Cole
9316ff3e51 Fix account api for new features. 2025-01-15 18:54:49 +01:00
James Cole
bfd91f8ee6 Update default.twig
Signed-off-by: James Cole <james@firefly-iii.org>
2025-01-13 11:32:54 +01:00
github-actions
13e5d25cfe Auto commit for release 'develop' on 2025-01-13 2025-01-13 04:14:18 +01:00
James Cole
b13030420b Merge branch 'main' into develop 2025-01-11 10:07:21 +01:00
github-actions
44d1e8181c Auto commit for release 'develop' on 2025-01-11 2025-01-11 10:06:32 +01:00
James Cole
63b34c1853 Remove unused step. 2025-01-11 10:05:51 +01:00
github-actions
facd0144cb Auto commit for release 'develop' on 2025-01-10 2025-01-10 17:56:21 +01:00
James Cole
115e3435af Fix https://github.com/orgs/firefly-iii/discussions/9576 2025-01-10 06:26:28 +01:00
github-actions
d44cd50768 Auto commit for release 'develop' on 2025-01-06 2025-01-06 07:37:27 +01:00
James Cole
1afcaea4c6 Trim quotes 2025-01-06 06:55:34 +01:00
James Cole
2bd1b37717 Move class to separate file. 2025-01-06 06:19:09 +01:00
184 changed files with 5183 additions and 3766 deletions

View File

@@ -406,16 +406,16 @@
},
{
"name": "friendsofphp/php-cs-fixer",
"version": "v3.66.1",
"version": "v3.68.1",
"source": {
"type": "git",
"url": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer.git",
"reference": "cde186799d8e92960c5a00c96e6214bf7f5547a9"
"reference": "b9db2b2ea3cdba7201067acee46f984ef2397cff"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/cde186799d8e92960c5a00c96e6214bf7f5547a9",
"reference": "cde186799d8e92960c5a00c96e6214bf7f5547a9",
"url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/b9db2b2ea3cdba7201067acee46f984ef2397cff",
"reference": "b9db2b2ea3cdba7201067acee46f984ef2397cff",
"shasum": ""
},
"require": {
@@ -497,7 +497,7 @@
],
"support": {
"issues": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/issues",
"source": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/tree/v3.66.1"
"source": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/tree/v3.68.1"
},
"funding": [
{
@@ -505,7 +505,7 @@
"type": "github"
}
],
"time": "2025-01-05T14:43:25+00:00"
"time": "2025-01-17T09:20:36+00:00"
},
{
"name": "psr/container",

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

@@ -30,12 +30,19 @@ use FireflyIII\Models\Preference;
use FireflyIII\Models\TransactionCurrency;
use FireflyIII\Support\Facades\Amount;
use FireflyIII\Support\Facades\Steam;
use FireflyIII\Transformers\V2\AbstractTransformer;
use FireflyIII\User;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
use Illuminate\Foundation\Bus\DispatchesJobs;
use Illuminate\Foundation\Validation\ValidatesRequests;
use Illuminate\Pagination\LengthAwarePaginator;
use Illuminate\Routing\Controller as BaseController;
use Illuminate\Support\Collection;
use League\Fractal\Manager;
use League\Fractal\Pagination\IlluminatePaginatorAdapter;
use League\Fractal\Resource\Collection as FractalCollection;
use League\Fractal\Resource\Item;
use League\Fractal\Serializer\JsonApiSerializer;
use Symfony\Component\HttpFoundation\Exception\BadRequestException;
use Symfony\Component\HttpFoundation\ParameterBag;
@@ -73,7 +80,7 @@ abstract class Controller extends BaseController
if (auth()->check()) {
$language = Steam::getLanguage();
$this->convertToNative = Amount::convertToNative();
$this->defaultCurrency = Amount::getDefaultCurrency();
$this->defaultCurrency = Amount::getNativeCurrency();
app()->setLocale($language);
}
@@ -223,4 +230,45 @@ abstract class Controller extends BaseController
return $manager;
}
final protected function jsonApiList(string $key, LengthAwarePaginator $paginator, AbstractTransformer $transformer): array
{
$manager = new Manager();
$baseUrl = sprintf('%s/api/v1/', request()->getSchemeAndHttpHost());
// TODO add stuff to path?
$manager->setSerializer(new JsonApiSerializer($baseUrl));
$objects = $paginator->getCollection();
// the transformer, at this point, needs to collect information that ALL items in the collection
// require, like meta-data and stuff like that, and save it for later.
$objects = $transformer->collectMetaData($objects);
$paginator->setCollection($objects);
$resource = new FractalCollection($objects, $transformer, $key);
$resource->setPaginator(new IlluminatePaginatorAdapter($paginator));
return $manager->createData($resource)->toArray();
}
/**
* Returns a JSON API object and returns it.
*
* @param array<int, mixed>|Model $object
*/
final protected function jsonApiObject(string $key, array|Model $object, AbstractTransformer $transformer): array
{
// create some objects:
$manager = new Manager();
$baseUrl = sprintf('%s/api/v1', request()->getSchemeAndHttpHost());
$manager->setSerializer(new JsonApiSerializer($baseUrl));
$transformer->collectMetaData(new Collection([$object]));
$resource = new Item($object, $transformer, $key);
return $manager->createData($resource)->toArray();
}
}

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

@@ -0,0 +1,71 @@
<?php
/*
* IndexController.php
* Copyright (c) 2024 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\UserGroup;
use FireflyIII\Api\V1\Controllers\Controller;
use FireflyIII\Api\V1\Requests\Data\DateRequest;
use FireflyIII\Repositories\UserGroup\UserGroupRepositoryInterface;
use FireflyIII\Transformers\UserGroupTransformer;
use Illuminate\Http\JsonResponse;
use Illuminate\Pagination\LengthAwarePaginator;
class IndexController extends Controller
{
public const string RESOURCE_KEY = 'user_groups';
private UserGroupRepositoryInterface $repository;
/**
* AccountController constructor.
*/
public function __construct()
{
parent::__construct();
$this->middleware(
function ($request, $next) {
$this->repository = app(UserGroupRepositoryInterface::class);
return $next($request);
}
);
}
public function index(DateRequest $request): JsonResponse
{
$administrations = $this->repository->get();
$pageSize = $this->parameters->get('limit');
$count = $administrations->count();
$administrations = $administrations->slice(($this->parameters->get('page') - 1) * $pageSize, $pageSize);
$paginator = new LengthAwarePaginator($administrations, $count, $pageSize, $this->parameters->get('page'));
$transformer = new UserGroupTransformer();
$transformer->setParameters($this->parameters); // give params to transformer
return response()
->json($this->jsonApiList(self::RESOURCE_KEY, $paginator, $transformer))
->header('Content-Type', self::CONTENT_TYPE)
;
}
}

View File

@@ -0,0 +1,64 @@
<?php
/*
* ShowController.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\UserGroup;
use FireflyIII\Api\V1\Controllers\Controller;
use FireflyIII\Models\UserGroup;
use FireflyIII\Repositories\Webhook\WebhookRepositoryInterface;
use FireflyIII\Transformers\UserGroupTransformer;
use Illuminate\Http\JsonResponse;
/**
* Class ShowController
*/
class ShowController extends Controller
{
public const string RESOURCE_KEY = 'user_groups';
private WebhookRepositoryInterface $repository;
public function __construct()
{
parent::__construct();
$this->middleware(
function ($request, $next) {
$this->repository = app(WebhookRepositoryInterface::class);
$this->repository->setUser(auth()->user());
return $next($request);
}
);
}
public function show(UserGroup $userGroup): JsonResponse
{
$transformer = new UserGroupTransformer();
$transformer->setParameters($this->parameters);
return response()
->api($this->jsonApiObject(self::RESOURCE_KEY, $userGroup, $transformer))
->header('Content-Type', self::CONTENT_TYPE)
;
}
}

View File

@@ -0,0 +1,71 @@
<?php
/*
* UpdateController.php
* Copyright (c) 2025 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\UserGroup;
use FireflyIII\Api\V1\Controllers\Controller;
use FireflyIII\Api\V1\Requests\Models\UserGroup\UpdateRequest;
use FireflyIII\Models\UserGroup;
use FireflyIII\Repositories\UserGroup\UserGroupRepositoryInterface;
use FireflyIII\Transformers\UserGroupTransformer;
use Illuminate\Http\JsonResponse;
class UpdateController extends Controller
{
public const string RESOURCE_KEY = 'user_groups';
private UserGroupRepositoryInterface $repository;
/**
* AccountController constructor.
*/
public function __construct()
{
parent::__construct();
$this->middleware(
function ($request, $next) {
$this->repository = app(UserGroupRepositoryInterface::class);
return $next($request);
}
);
}
public function update(UpdateRequest $request, UserGroup $userGroup): JsonResponse
{
app('log')->debug(sprintf('Now in %s', __METHOD__));
$data = $request->getData();
$userGroup = $this->repository->update($userGroup, $data);
$userGroup->refresh();
app('preferences')->mark();
$transformer = new UserGroupTransformer();
$transformer->setParameters($this->parameters);
return response()
->api($this->jsonApiObject(self::RESOURCE_KEY, $userGroup, $transformer))
->header('Content-Type', self::CONTENT_TYPE)
;
}
}

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

@@ -55,6 +55,7 @@ class DateRequest extends FormRequest
return [
'start' => $start,
'end' => $end,
'date' => $this->getCarbonDate('date'),
];
}
@@ -64,8 +65,9 @@ class DateRequest extends FormRequest
public function rules(): array
{
return [
'start' => 'required|date',
'end' => 'required|date|after:start',
'date' => 'date|after:1900-01-01|before:2099-12-31',
'start' => 'date|after:1900-01-01|before:2099-12-31|before:end|required_with:end',
'end' => 'date|after:1900-01-01|before:2099-12-31|after:start|required_with:start',
];
}
}

View File

@@ -0,0 +1,65 @@
<?php
/*
* UpdateRequest.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\Requests\Models\UserGroup;
use FireflyIII\Models\UserGroup;
use FireflyIII\Support\Request\ChecksLogin;
use FireflyIII\Support\Request\ConvertsDataTypes;
use Illuminate\Foundation\Http\FormRequest;
/**
* Class UpdateRequest
*/
class UpdateRequest extends FormRequest
{
use ChecksLogin;
use ConvertsDataTypes;
public function getData(): array
{
$fields = [
'title' => ['title', 'convertString'],
'native_currency_id' => ['native_currency_id', 'convertInteger'],
'native_currency_code' => ['native_currency_code', 'convertString'],
];
return $this->getAllData($fields);
}
/**
* Rules for this request.
*/
public function rules(): array
{
/** @var UserGroup $userGroup */
$userGroup = $this->route()->parameter('userGroup');
return [
'title' => ['required', 'min:1', 'max:255'],
'native_currency_id' => 'exists:transaction_currencies,id',
'native_currency_code' => 'exists:transaction_currencies,code',
];
}
}

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

@@ -66,7 +66,7 @@ class ShowController extends Controller
$default = 1 === $group->pivot->group_default;
}
$currency->userGroupEnabled = $enabled;
$currency->userGroupDefault = $default;
$currency->userGroupNative = $default;
$transformer = new CurrencyTransformer();

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

@@ -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

@@ -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));

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

@@ -119,7 +119,7 @@ class EditController extends Controller
}
$request->session()->forget('accounts.edit.fromUpdate');
$openingBalanceAmount = (string) $repository->getOpeningBalanceAmount($account);
$openingBalanceAmount = (string) $repository->getOpeningBalanceAmount($account, false);
if ('0' === $openingBalanceAmount) {
$openingBalanceAmount = '';
}

View File

@@ -45,7 +45,7 @@ class ConfigurationController extends Controller
$this->middleware(
static function ($request, $next) {
app('view')->share('title', (string) trans('firefly.administration'));
app('view')->share('title', (string) trans('firefly.system_settings'));
app('view')->share('mainTitleIcon', 'fa-hand-spock-o');
return $next($request);
@@ -73,7 +73,7 @@ class ConfigurationController extends Controller
$siteOwner = config('firefly.site_owner');
return view(
'admin.configuration.index',
'settings.configuration.index',
compact('subTitle', 'subTitleIcon', 'singleUserMode', 'isDemoSite', 'siteOwner')
);
}
@@ -96,6 +96,6 @@ class ConfigurationController extends Controller
session()->flash('success', (string) trans('firefly.configuration_updated'));
app('preferences')->mark();
return redirect()->route('admin.configuration.index');
return redirect()->route('settings.configuration.index');
}
}

View File

@@ -51,7 +51,7 @@ class HomeController extends Controller
public function index()
{
Log::channel('audit')->info('User visits admin index.');
$title = (string) trans('firefly.administration');
$title = (string) trans('firefly.system_settings');
$mainTitleIcon = 'fa-hand-spock-o';
$email = auth()->user()->email;
$pref = app('preferences')->get('remote_guard_alt_email');
@@ -59,6 +59,6 @@ class HomeController extends Controller
$email = $pref->data;
}
return view('admin.index', compact('title', 'mainTitleIcon', 'email'));
return view('settings.index', compact('title', 'mainTitleIcon', 'email'));
}
}

View File

@@ -51,7 +51,7 @@ class LinkController extends Controller
$this->middleware(
function ($request, $next) {
app('view')->share('title', (string) trans('firefly.administration'));
app('view')->share('title', (string) trans('firefly.system_settings'));
app('view')->share('mainTitleIcon', 'fa-hand-spock-o');
$this->repository = app(LinkTypeRepositoryInterface::class);
@@ -78,7 +78,7 @@ class LinkController extends Controller
$this->rememberPreviousUrl('link-types.create.url');
}
return view('admin.link.create', compact('subTitle', 'subTitleIcon'));
return view('settings.link.create', compact('subTitle', 'subTitleIcon'));
}
/**
@@ -91,7 +91,7 @@ class LinkController extends Controller
if (false === $linkType->editable) {
$request->session()->flash('error', (string) trans('firefly.cannot_edit_link_type', ['name' => e($linkType->name)]));
return redirect(route('admin.links.index'));
return redirect(route('settings.links.index'));
}
Log::channel('audit')->info(sprintf('User wants to delete link type #%d', $linkType->id));
@@ -111,7 +111,7 @@ class LinkController extends Controller
// put previous url in session
$this->rememberPreviousUrl('link-types.delete.url');
return view('admin.link.delete', compact('linkType', 'subTitle', 'moveTo', 'count'));
return view('settings.link.delete', compact('linkType', 'subTitle', 'moveTo', 'count'));
}
/**
@@ -142,7 +142,7 @@ class LinkController extends Controller
if (false === $linkType->editable) {
$request->session()->flash('error', (string) trans('firefly.cannot_edit_link_type', ['name' => e($linkType->name)]));
return redirect(route('admin.links.index'));
return redirect(route('settings.links.index'));
}
$subTitle = (string) trans('firefly.edit_link_type', ['name' => $linkType->name]);
$subTitleIcon = 'fa-link';
@@ -155,7 +155,7 @@ class LinkController extends Controller
}
$request->session()->forget('link-types.edit.fromUpdate');
return view('admin.link.edit', compact('subTitle', 'subTitleIcon', 'linkType'));
return view('settings.link.edit', compact('subTitle', 'subTitleIcon', 'linkType'));
}
/**
@@ -176,7 +176,7 @@ class LinkController extends Controller
}
);
return view('admin.link.index', compact('subTitle', 'subTitleIcon', 'linkTypes'));
return view('settings.link.index', compact('subTitle', 'subTitleIcon', 'linkTypes'));
}
/**
@@ -192,7 +192,7 @@ class LinkController extends Controller
Log::channel('audit')->info(sprintf('User viewing link type #%d', $linkType->id));
return view('admin.link.show', compact('subTitle', 'subTitleIcon', 'linkType', 'links'));
return view('settings.link.show', compact('subTitle', 'subTitleIcon', 'linkType', 'links'));
}
/**
@@ -217,7 +217,7 @@ class LinkController extends Controller
// set value so create routine will not overwrite URL:
$request->session()->put('link-types.create.fromStore', true);
$redirect = redirect(route('admin.links.create'))->withInput();
$redirect = redirect(route('settings.links.create'))->withInput();
}
// redirect to previous URL.
@@ -234,7 +234,7 @@ class LinkController extends Controller
if (false === $linkType->editable) {
$request->session()->flash('error', (string) trans('firefly.cannot_edit_link_type', ['name' => e($linkType->name)]));
return redirect(route('admin.links.index'));
return redirect(route('settings.links.index'));
}
$data = [
@@ -253,7 +253,7 @@ class LinkController extends Controller
// set value so edit routine will not overwrite URL:
$request->session()->put('link-types.edit.fromUpdate', true);
$redirect = redirect(route('admin.links.edit', [$linkType->id]))->withInput(['return_to_edit' => 1]);
$redirect = redirect(route('settings.links.edit', [$linkType->id]))->withInput(['return_to_edit' => 1]);
}
// redirect to previous URL.

View File

@@ -38,7 +38,7 @@ class NotificationController extends Controller
public function index(): View
{
Log::channel('audit')->info('User visits notifications index.');
$title = (string) trans('firefly.administration');
$title = (string) trans('firefly.system_settings');
$mainTitleIcon = 'fa-hand-spock-o';
$subTitle = (string) trans('firefly.title_owner_notifications');
$subTitleIcon = 'envelope-o';
@@ -71,7 +71,7 @@ class NotificationController extends Controller
$forcedAvailability['pushover'] = '' !== $pushoverAppToken && '' !== $pushoverUserToken;
return view(
'admin.notifications.index',
'settings.notifications.index',
compact(
'title',
'subTitle',
@@ -115,7 +115,7 @@ class NotificationController extends Controller
session()->flash('success', (string) trans('firefly.notification_settings_saved'));
return redirect(route('admin.notification.index'));
return redirect(route('settings.notification.index'));
}
public function testNotification(Request $request): RedirectResponse
@@ -140,6 +140,6 @@ class NotificationController extends Controller
session()->flash('success', (string) trans('firefly.notification_test_executed', ['channel' => $channel]));
}
return redirect(route('admin.notification.index'));
return redirect(route('settings.notification.index'));
}
}

View File

@@ -47,7 +47,7 @@ class UpdateController extends Controller
parent::__construct();
$this->middleware(
static function ($request, $next) {
app('view')->share('title', (string) trans('firefly.administration'));
app('view')->share('title', (string) trans('firefly.system_settings'));
app('view')->share('mainTitleIcon', 'fa-hand-spock-o');
return $next($request);
@@ -81,7 +81,7 @@ class UpdateController extends Controller
'alpha' => (string) trans('firefly.update_channel_alpha'),
];
return view('admin.update.index', compact('subTitle', 'subTitleIcon', 'selected', 'options', 'channelSelected', 'channelOptions'));
return view('settings.update.index', compact('subTitle', 'subTitleIcon', 'selected', 'options', 'channelSelected', 'channelOptions'));
}
/**
@@ -100,7 +100,7 @@ class UpdateController extends Controller
app('fireflyconfig')->set('update_channel', $channel);
session()->flash('success', (string) trans('firefly.configuration_updated'));
return redirect(route('admin.update-check'));
return redirect(route('settings.update-check'));
}
/**
@@ -112,6 +112,6 @@ class UpdateController extends Controller
session()->flash($release['level'], $release['message']);
return redirect(route('admin.update-check'));
return redirect(route('settings.update-check'));
}
}

View File

@@ -55,7 +55,7 @@ class UserController extends Controller
$this->middleware(
function ($request, $next) {
app('view')->share('title', (string) trans('firefly.administration'));
app('view')->share('title', (string) trans('firefly.system_settings'));
app('view')->share('mainTitleIcon', 'fa-hand-spock-o');
$this->repository = app(UserRepositoryInterface::class);
@@ -74,12 +74,12 @@ class UserController extends Controller
if ($this->externalIdentity) {
request()->session()->flash('error', trans('firefly.external_user_mgt_disabled'));
return redirect(route('admin.users'));
return redirect(route('settings.users'));
}
$subTitle = (string) trans('firefly.delete_user', ['email' => $user->email]);
return view('admin.users.delete', compact('user', 'subTitle'));
return view('settings.users.delete', compact('user', 'subTitle'));
}
public function deleteInvite(InvitedUser $invitedUser): JsonResponse
@@ -108,12 +108,12 @@ class UserController extends Controller
if ($this->externalIdentity) {
request()->session()->flash('error', trans('firefly.external_user_mgt_disabled'));
return redirect(route('admin.users'));
return redirect(route('settings.users'));
}
$this->repository->destroy($user);
session()->flash('success', (string) trans('firefly.user_deleted'));
return redirect(route('admin.users'));
return redirect(route('settings.users'));
}
/**
@@ -144,7 +144,7 @@ class UserController extends Controller
'email_changed' => (string) trans('firefly.block_code_email_changed'),
];
return view('admin.users.edit', compact('user', 'canEditDetails', 'subTitle', 'subTitleIcon', 'codes', 'currentUser', 'isAdmin'));
return view('settings.users.edit', compact('user', 'canEditDetails', 'subTitle', 'subTitleIcon', 'codes', 'currentUser', 'isAdmin'));
}
/**
@@ -174,7 +174,7 @@ class UserController extends Controller
}
);
return view('admin.users.index', compact('subTitle', 'subTitleIcon', 'users', 'allowInvites', 'invitedUsers'));
return view('settings.users.index', compact('subTitle', 'subTitleIcon', 'users', 'allowInvites', 'invitedUsers'));
}
public function invite(InviteUserFormRequest $request): RedirectResponse
@@ -186,7 +186,7 @@ class UserController extends Controller
// event!
event(new InvitationCreated($invitee));
return redirect(route('admin.users'));
return redirect(route('settings.users'));
}
/**
@@ -196,14 +196,14 @@ class UserController extends Controller
*/
public function show(User $user)
{
$title = (string) trans('firefly.administration');
$title = (string) trans('firefly.system_settings');
$mainTitleIcon = 'fa-hand-spock-o';
$subTitle = (string) trans('firefly.single_user_administration', ['email' => $user->email]);
$subTitleIcon = 'fa-user';
$information = $this->repository->getUserData($user);
return view(
'admin.users.show',
'settings.users.show',
compact(
'title',
'mainTitleIcon',
@@ -248,7 +248,7 @@ class UserController extends Controller
if (1 === (int) $request->get('return_to_edit')) {
session()->put('users.edit.fromUpdate', true);
$redirect = redirect(route('admin.users.edit', [$user->id]))->withInput(['return_to_edit' => 1]);
$redirect = redirect(route('settings.users.edit', [$user->id]))->withInput(['return_to_edit' => 1]);
}
// redirect to previous URL.

View File

@@ -118,7 +118,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

@@ -74,10 +74,10 @@ class IndexController extends Controller
// order so default and enabled are on top:
$collection = $collection->sortBy(
static function (TransactionCurrency $currency) {
$default = true === $currency->userGroupDefault ? 0 : 1;
$native = true === $currency->userGroupNative ? 0 : 1;
$enabled = true === $currency->userGroupEnabled ? 0 : 1;
return sprintf('%s-%s-%s', $default, $enabled, $currency->code);
return sprintf('%s-%s-%s', $native, $enabled, $currency->code);
}
);
$total = $collection->count();

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

@@ -26,9 +26,11 @@ namespace FireflyIII\Http\Middleware;
use FireflyIII\Models\Account;
use FireflyIII\Models\Bill;
use FireflyIII\Models\GroupMembership;
use FireflyIII\Models\TransactionCurrency;
use FireflyIII\Models\TransactionGroup;
use FireflyIII\Models\TransactionJournal;
use FireflyIII\Models\UserGroup;
use FireflyIII\Models\Webhook;
use FireflyIII\User;
use Illuminate\Http\Request;
@@ -53,6 +55,10 @@ class InterestingMessage
app('preferences')->mark();
$this->handleGroupMessage($request);
}
if ($this->userGroupMessage($request)) {
app('preferences')->mark();
$this->handleUserGroupMessage($request);
}
if ($this->accountMessage($request)) {
app('preferences')->mark();
$this->handleAccountMessage($request);
@@ -88,6 +94,15 @@ class InterestingMessage
return null !== $transactionGroupId && null !== $message;
}
private function userGroupMessage(Request $request): bool
{
// get parameters from request.
$transactionGroupId = $request->get('user_group_id');
$message = $request->get('message');
return null !== $transactionGroupId && null !== $message;
}
private function handleGroupMessage(Request $request): void
{
// get parameters from request.
@@ -135,6 +150,44 @@ class InterestingMessage
return null !== $accountId && null !== $message;
}
private function handleUserGroupMessage(Request $request): void
{
// get parameters from request.
$userGroupId = $request->get('user_group_id');
$message = $request->get('message');
/** @var User $user */
$user = auth()->user();
/** @var null|UserGroup $userGroup */
$userGroup = UserGroup::find($userGroupId);
$valid = false;
$memberships = $user->groupMemberships()->get();
/** @var GroupMembership $membership */
foreach ($memberships as $membership) {
if ($membership->userGroup->id === $userGroup->id) {
$valid = true;
break;
}
}
if (false === $valid) {
return;
}
if ('deleted' === $message) {
session()->flash('success', (string) trans('firefly.flash_administration_deleted', ['title' => $userGroup->title]));
}
if ('created' === $message) {
session()->flash('success', (string) trans('firefly.flash_administration_created', ['title' => $userGroup->title]));
}
if ('updated' === $message) {
session()->flash('success', (string) trans('firefly.flash_administration_updated', ['title' => $userGroup->title]));
}
}
private function handleAccountMessage(Request $request): void
{
// get parameters from request.

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

@@ -37,7 +37,7 @@ class TransactionCurrency extends Model
use ReturnsIntegerIdTrait;
use SoftDeletes;
public ?bool $userGroupDefault = null;
public ?bool $userGroupNative = null;
public ?bool $userGroupEnabled = null;
protected $casts
= [
@@ -73,8 +73,8 @@ class TransactionCurrency extends Model
public function refreshForUser(User $user): void
{
$current = $user->userGroup->currencies()->where('transaction_currencies.id', $this->id)->first();
$default = app('amount')->getDefaultCurrencyByUserGroup($user->userGroup);
$this->userGroupDefault = $default->id === $this->id;
$native = app('amount')->getNativeCurrencyByUserGroup($user->userGroup);
$this->userGroupNative = $native->id === $this->id;
$this->userGroupEnabled = null !== $current;
}

View File

@@ -293,7 +293,7 @@ class AccountRepository implements AccountRepositoryInterface
/**
* Returns the amount of the opening balance for this account.
*/
public function getOpeningBalanceAmount(Account $account): ?string
public function getOpeningBalanceAmount(Account $account, bool $convertToNative): ?string
{
$journal = TransactionJournal::leftJoin('transactions', 'transactions.transaction_journal_id', '=', 'transaction_journals.id')
->where('transactions.account_id', $account->id)
@@ -307,6 +307,9 @@ class AccountRepository implements AccountRepositoryInterface
if (null === $transaction) {
return null;
}
if ($convertToNative) {
return $transaction->native_amount ?? '0';
}
return $transaction->amount;
}
@@ -352,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

@@ -106,7 +106,7 @@ interface AccountRepositoryInterface
/**
* Returns the amount of the opening balance for this account.
*/
public function getOpeningBalanceAmount(Account $account): ?string;
public function getOpeningBalanceAmount(Account $account, bool $convertToNative): ?string;
/**
* Return date of opening balance as string or null.

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) {

View File

@@ -279,7 +279,7 @@ class BudgetLimitRepository implements BudgetLimitRepositoryInterface
$factory = app(TransactionCurrencyFactory::class);
$currency = $factory->find($data['currency_id'] ?? null, $data['currency_code'] ?? null);
if (null === $currency) {
$currency = app('amount')->getDefaultCurrencyByUserGroup($this->user->userGroup);
$currency = app('amount')->getNativeCurrencyByUserGroup($this->user->userGroup);
}
$currency->enabled = true;
$currency->save();
@@ -377,7 +377,7 @@ class BudgetLimitRepository implements BudgetLimitRepositoryInterface
}
// catch unexpected null:
if (null === $currency) {
$currency = $budgetLimit->transactionCurrency ?? app('amount')->getDefaultCurrencyByUserGroup($this->user->userGroup);
$currency = $budgetLimit->transactionCurrency ?? app('amount')->getNativeCurrencyByUserGroup($this->user->userGroup);
}
$currency->enabled = true;
$currency->save();

View File

@@ -89,7 +89,7 @@ class BudgetRepository implements BudgetRepositoryInterface
$limitRepository = app(BudgetLimitRepository::class);
$limitRepository->setUser($this->user);
$budgets = $this->getActiveBudgets();
$defaultCurrency = app('amount')->getDefaultCurrency();
$defaultCurrency = app('amount')->getNativeCurrency();
$converter = new ExchangeRateConverter();
/** @var Budget $budget */
@@ -396,7 +396,7 @@ class BudgetRepository implements BudgetRepositoryInterface
$autoBudget = $this->getAutoBudget($budget);
// grab default currency:
$currency = app('amount')->getDefaultCurrencyByUserGroup($this->user->userGroup);
$currency = app('amount')->getNativeCurrencyByUserGroup($this->user->userGroup);
if (null === $autoBudget) {
// at this point it's a blind assumption auto_budget_type is 1 or 2.
@@ -782,7 +782,7 @@ class BudgetRepository implements BudgetRepositoryInterface
$currency = $repos->findByCode((string) $data['currency_code']);
}
if (null === $currency) {
$currency = app('amount')->getDefaultCurrencyByUserGroup($this->user->userGroup);
$currency = app('amount')->getNativeCurrencyByUserGroup($this->user->userGroup);
}
$autoBudget = new AutoBudget();

View File

@@ -364,7 +364,7 @@ class OperationsRepository implements OperationsRepositoryInterface
$collector->setCategories($categories);
$journals = $collector->getExtractedJournals();
$convertToNative = Amount::convertToNative($this->user);
$default = Amount::getDefaultCurrency();
$default = Amount::getNativeCurrency();
$array = [];
foreach ($journals as $journal) {

View File

@@ -68,7 +68,7 @@ trait ModifiesPiggyBanks
$pivot->native_current_amount = null;
// also update native_current_amount.
$userCurrency = app('amount')->getDefaultCurrencyByUserGroup($this->user->userGroup);
$userCurrency = app('amount')->getNativeCurrencyByUserGroup($this->user->userGroup);
if ($userCurrency->id !== $piggyBank->transaction_currency_id) {
$converter = new ExchangeRateConverter();
$converter->setIgnoreSettings(true);
@@ -91,7 +91,7 @@ trait ModifiesPiggyBanks
$pivot->native_current_amount = null;
// also update native_current_amount.
$userCurrency = app('amount')->getDefaultCurrencyByUserGroup($this->user->userGroup);
$userCurrency = app('amount')->getNativeCurrencyByUserGroup($this->user->userGroup);
if ($userCurrency->id !== $piggyBank->transaction_currency_id) {
$converter = new ExchangeRateConverter();
$converter->setIgnoreSettings(true);

View File

@@ -150,7 +150,7 @@ class PiggyBankRepository implements PiggyBankRepositoryInterface
$accountRepos = app(AccountRepositoryInterface::class);
$accountRepos->setUser($this->user);
$defaultCurrency = app('amount')->getDefaultCurrencyByUserGroup($this->user->userGroup);
$defaultCurrency = app('amount')->getNativeCurrencyByUserGroup($this->user->userGroup);
app('log')->debug(sprintf('Piggy bank #%d currency is %s', $piggyBank->id, $piggyBank->transactionCurrency->code));

View File

@@ -345,7 +345,7 @@ class TransactionGroupRepository implements TransactionGroupRepositoryInterface
{
$return = [];
$journals = $group->transactionJournals->pluck('id')->toArray();
$currency = app('amount')->getDefaultCurrencyByUserGroup($this->user->userGroup);
$currency = app('amount')->getNativeCurrencyByUserGroup($this->user->userGroup);
$data = PiggyBankEvent::whereIn('transaction_journal_id', $journals)
->with('piggyBank', 'piggyBank.account')
->get(['piggy_bank_events.*'])

View File

@@ -30,6 +30,7 @@ use FireflyIII\Factory\UserGroupFactory;
use FireflyIII\Models\GroupMembership;
use FireflyIII\Models\UserGroup;
use FireflyIII\Models\UserRole;
use FireflyIII\Repositories\UserGroups\Currency\CurrencyRepositoryInterface;
use FireflyIII\User;
use Illuminate\Contracts\Auth\Authenticatable;
use Illuminate\Support\Collection;
@@ -198,6 +199,24 @@ class UserGroupRepository implements UserGroupRepositoryInterface
{
$userGroup->title = $data['title'];
$userGroup->save();
$currency = null;
/** @var CurrencyRepositoryInterface $repository */
$repository = app(CurrencyRepositoryInterface::class);
if (array_key_exists('native_currency_code', $data)) {
$repository->setUser($this->user);
$currency = $repository->findByCode($data['native_currency_code']);
}
if (array_key_exists('native_currency_id', $data) && null === $currency) {
$repository->setUser($this->user);
$currency = $repository->find((int) $data['native_currency_id']);
}
if (null !== $currency) {
$repository->makeDefault($currency);
}
return $userGroup;
}

View File

@@ -69,7 +69,7 @@ class BillRepository implements BillRepositoryInterface
{
Log::debug(sprintf('Created new ExchangeRateConverter in %s', __METHOD__));
$bills = $this->getActiveBills();
$default = app('amount')->getDefaultCurrency();
$default = app('amount')->getNativeCurrency();
$return = [];
$converter = new ExchangeRateConverter();
@@ -139,7 +139,7 @@ class BillRepository implements BillRepositoryInterface
Log::debug(sprintf('Created new ExchangeRateConverter in %s', __METHOD__));
$bills = $this->getActiveBills();
$return = [];
$default = app('amount')->getDefaultCurrency();
$default = app('amount')->getNativeCurrency();
$converter = new ExchangeRateConverter();
/** @var Bill $bill */

View File

@@ -42,7 +42,7 @@ class AvailableBudgetRepository implements AvailableBudgetRepositoryInterface
Log::debug(sprintf('Created new ExchangeRateConverter in %s', __METHOD__));
$return = [];
$converter = new ExchangeRateConverter();
$default = app('amount')->getDefaultCurrency();
$default = app('amount')->getNativeCurrency();
$availableBudgets = $this->userGroup->availableBudgets()
->where('start_date', $start->format('Y-m-d'))
->where('end_date', $end->format('Y-m-d'))->get()

View File

@@ -180,11 +180,11 @@ class CurrencyRepository implements CurrencyRepositoryInterface
$hasId = $local->contains(static function (TransactionCurrency $entry) use ($current) {
return $entry->id === $current->id;
});
$isDefault = $local->contains(static function (TransactionCurrency $entry) use ($current) {
$isNative = $local->contains(static function (TransactionCurrency $entry) use ($current) {
return 1 === (int) $entry->pivot->group_default && $entry->id === $current->id;
});
$current->userGroupEnabled = $hasId;
$current->userGroupDefault = $isDefault;
$current->userGroupNative = $isNative;
return $current;
});
@@ -195,7 +195,7 @@ class CurrencyRepository implements CurrencyRepositoryInterface
$all = $this->userGroup->currencies()->orderBy('code', 'ASC')->withPivot(['group_default'])->get();
$all->map(static function (TransactionCurrency $current) { // @phpstan-ignore-line
$current->userGroupEnabled = true;
$current->userGroupDefault = 1 === (int) $current->pivot->group_default;
$current->userGroupNative = 1 === (int) $current->pivot->group_default;
return $current;
});
@@ -245,7 +245,7 @@ class CurrencyRepository implements CurrencyRepositoryInterface
app('log')->debug('Grabbing default currency for this user...');
/** @var null|TransactionCurrency $result */
$result = app('amount')->getDefaultCurrencyByUserGroup($this->user->userGroup);
$result = app('amount')->getNativeCurrencyByUserGroup($this->user->userGroup);
}
app('log')->debug(sprintf('Final result: %s', $result->code));
@@ -376,7 +376,7 @@ class CurrencyRepository implements CurrencyRepositoryInterface
public function makeDefault(TransactionCurrency $currency): void
{
$current = app('amount')->getDefaultCurrencyByUserGroup($this->userGroup);
$current = app('amount')->getNativeCurrencyByUserGroup($this->userGroup);
app('log')->debug(sprintf('Enabled + made default currency %s for user #%d', $currency->code, $this->userGroup->id));
$this->userGroup->currencies()->detach($currency->id);
foreach ($this->userGroup->currencies()->get() as $item) {

View File

@@ -233,7 +233,7 @@ trait AccountServiceTrait
// get or grab currency:
$currency = $this->accountRepository->getAccountCurrency($account);
if (null === $currency) {
$currency = app('amount')->getDefaultCurrencyByUserGroup($account->user->userGroup);
$currency = app('amount')->getNativeCurrencyByUserGroup($account->user->userGroup);
}
// submit to factory:
@@ -351,7 +351,7 @@ trait AccountServiceTrait
if (null === $currency) {
// use default currency:
$currency = app('amount')->getDefaultCurrencyByUserGroup($this->user->userGroup);
$currency = app('amount')->getNativeCurrencyByUserGroup($this->user->userGroup);
}
$currency->enabled = true;
$currency->save();
@@ -391,7 +391,7 @@ trait AccountServiceTrait
// if exists, update:
$currency = $this->accountRepository->getAccountCurrency($account);
if (null === $currency) {
$currency = app('amount')->getDefaultCurrencyByUserGroup($account->user->userGroup);
$currency = app('amount')->getNativeCurrencyByUserGroup($account->user->userGroup);
}
// simply grab the first journal and change it:
@@ -457,7 +457,7 @@ trait AccountServiceTrait
// get or grab currency:
$currency = $this->accountRepository->getAccountCurrency($account);
if (null === $currency) {
$currency = app('amount')->getDefaultCurrencyByUserGroup($account->user->userGroup);
$currency = app('amount')->getNativeCurrencyByUserGroup($account->user->userGroup);
}
// submit to factory:
@@ -573,7 +573,7 @@ trait AccountServiceTrait
// if exists, update:
$currency = $this->accountRepository->getAccountCurrency($account);
if (null === $currency) {
$currency = app('amount')->getDefaultCurrencyByUserGroup($account->user->userGroup);
$currency = app('amount')->getNativeCurrencyByUserGroup($account->user->userGroup);
}
// simply grab the first journal and change it:
@@ -654,7 +654,7 @@ trait AccountServiceTrait
// get or grab currency:
$currency = $this->accountRepository->getAccountCurrency($account);
if (null === $currency) {
$currency = app('amount')->getDefaultCurrencyByUserGroup($account->user->userGroup);
$currency = app('amount')->getNativeCurrencyByUserGroup($account->user->userGroup);
}
// submit to factory:

View File

@@ -170,7 +170,7 @@ class CreditRecalculateService
$this->validateOpeningBalance($account, $openingBalance);
}
}
$startOfDebt = $this->repository->getOpeningBalanceAmount($account) ?? '0';
$startOfDebt = $this->repository->getOpeningBalanceAmount($account, false) ?? '0';
$leftOfDebt = app('steam')->positive($startOfDebt);
// Log::debug(sprintf('Start of debt is "%s", so initial left of debt is "%s"', app('steam')->bcround($startOfDebt, 2), app('steam')->bcround($leftOfDebt, 2)));

View File

@@ -107,7 +107,7 @@ trait RecurringTransactionTrait
$currency = $factory->find($array['currency_id'] ?? null, $array['currency_code'] ?? null);
$foreignCurrency = $factory->find($array['foreign_currency_id'] ?? null, $array['foreign_currency_code'] ?? null);
if (null === $currency) {
$currency = app('amount')->getDefaultCurrencyByUserGroup($recurrence->user->userGroup);
$currency = app('amount')->getNativeCurrencyByUserGroup($recurrence->user->userGroup);
}
app('log')->debug(

View File

@@ -55,7 +55,7 @@ class BillUpdateService
if (array_key_exists('currency_id', $data) || array_key_exists('currency_code', $data)) {
$factory = app(TransactionCurrencyFactory::class);
$currency = $factory->find((int) ($data['currency_id'] ?? null), $data['currency_code'] ?? null) ??
app('amount')->getDefaultCurrencyByUserGroup($bill->user->userGroup);
app('amount')->getNativeCurrencyByUserGroup($bill->user->userGroup);
// enable the currency if it isn't.
$currency->enabled = true;

View File

@@ -51,7 +51,7 @@ class CurrencyUpdateService
$currency->decimal_places = $data['decimal_places'];
}
$currency->userGroupEnabled = null;
$currency->userGroupDefault = null;
$currency->userGroupNative = null;
$currency->save();
return $currency;

View File

@@ -55,7 +55,7 @@ class Amount
public function getAmountFromJournal(array $journal): string
{
$convertToNative = $this->convertToNative();
$currency = $this->getDefaultCurrency();
$currency = $this->getNativeCurrency();
$field = $convertToNative && $currency->id !== $journal['currency_id'] ? 'native_amount' : 'amount';
$amount = $journal[$field] ?? '0';
// Log::debug(sprintf('Field is %s, amount is %s', $field, $amount));
@@ -86,7 +86,7 @@ class Amount
public function getAmountFromJournalObject(TransactionJournal $journal): string
{
$convertToNative = $this->convertToNative();
$currency = $this->getDefaultCurrency();
$currency = $this->getNativeCurrency();
$field = $convertToNative && $currency->id !== $journal->transaction_currency_id ? 'native_amount' : 'amount';
/** @var null|Transaction $sourceTransaction */
@@ -155,38 +155,54 @@ class Amount
return $user->currencies()->orderBy('code', 'ASC')->get();
}
/**
* @deprecated
*/
public function getDefaultCurrency(): TransactionCurrency
{
return $this->getNativeCurrency();
}
public function getNativeCurrency(): TransactionCurrency
{
if (auth()->check()) {
/** @var User $user */
$user = auth()->user();
if (null !== $user->userGroup) {
return $this->getDefaultCurrencyByUserGroup($user->userGroup);
return $this->getNativeCurrencyByUserGroup($user->userGroup);
}
}
return $this->getSystemCurrency();
}
/**
* @deprecated
*/
public function getDefaultCurrencyByUserGroup(UserGroup $userGroup): TransactionCurrency
{
$cache = new CacheProperties();
$cache->addProperty('getDefaultCurrencyByGroup');
return $this->getNativeCurrencyByUserGroup($userGroup);
}
public function getNativeCurrencyByUserGroup(UserGroup $userGroup): TransactionCurrency
{
$cache = new CacheProperties();
$cache->addProperty('getNativeCurrencyByGroup');
$cache->addProperty($userGroup->id);
if ($cache->has()) {
return $cache->get();
}
/** @var null|TransactionCurrency $default */
$default = $userGroup->currencies()->where('group_default', true)->first();
if (null === $default) {
$default = $this->getSystemCurrency();
/** @var null|TransactionCurrency $native */
$native = $userGroup->currencies()->where('group_default', true)->first();
if (null === $native) {
$native = $this->getSystemCurrency();
// could be the user group has no default right now.
$userGroup->currencies()->sync([$default->id => ['group_default' => true]]);
$userGroup->currencies()->sync([$native->id => ['group_default' => true]]);
}
$cache->store($default);
$cache->store($native);
return $default;
return $native;
}
public function getSystemCurrency(): TransactionCurrency

View File

@@ -25,6 +25,8 @@ declare(strict_types=1);
namespace FireflyIII\Support\Export;
use Carbon\Carbon;
use FireflyIII\Enums\AccountTypeEnum;
use FireflyIII\Enums\TransactionTypeEnum;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Helpers\Collector\GroupCollectorInterface;
use FireflyIII\Models\Account;
@@ -50,6 +52,8 @@ use FireflyIII\Repositories\Recurring\RecurringRepositoryInterface;
use FireflyIII\Repositories\Rule\RuleRepositoryInterface;
use FireflyIII\Repositories\Tag\TagRepositoryInterface;
use FireflyIII\Repositories\TransactionGroup\TransactionGroupRepositoryInterface;
use FireflyIII\Support\Facades\Amount;
use FireflyIII\Support\Facades\Steam;
use FireflyIII\Support\Request\ConvertsDataTypes;
use FireflyIII\User;
use Illuminate\Support\Collection;
@@ -728,16 +732,15 @@ class ExportDataGenerator
private function exportTransactions(): string
{
// TODO better place for keys?
$header = ['user_id', 'group_id', 'journal_id', 'created_at', 'updated_at', 'group_title', 'type', 'amount', 'foreign_amount', 'currency_code', 'foreign_currency_code', 'description', 'date', 'source_name', 'source_iban', 'source_type', 'destination_name', 'destination_iban', 'destination_type', 'reconciled', 'category', 'budget', 'bill', 'tags', 'notes'];
$header = ['user_id', 'group_id', 'journal_id', 'created_at', 'updated_at', 'group_title', 'type', 'currency_code', 'amount', 'foreign_currency_code', 'foreign_amount', 'native_currency_code', 'native_amount', 'native_foreign_amount', 'description', 'date', 'source_name', 'source_iban', 'source_type', 'destination_name', 'destination_iban', 'destination_type', 'reconciled', 'category', 'budget', 'bill', 'tags', 'notes'];
$metaFields = config('firefly.journal_meta_fields');
$header = array_merge($header, $metaFields);
$default = Amount::getNativeCurrency();
$collector = app(GroupCollectorInterface::class);
$collector->setUser($this->user);
$collector->setRange($this->start, $this->end)->withAccountInformation()->withCategoryInformation()->withBillInformation()
->withBudgetInformation()->withTagInformation()->withNotes()
;
$collector->setRange($this->start, $this->end)->withAccountInformation()->withCategoryInformation()->withBillInformation()->withBudgetInformation()->withTagInformation()->withNotes();
if (0 !== $this->accounts->count()) {
$collector->setAccounts($this->accounts);
}
@@ -752,9 +755,34 @@ class ExportDataGenerator
/** @var array $journal */
foreach ($journals as $journal) {
$metaData = $repository->getMetaFields($journal['transaction_journal_id'], $metaFields);
$records[] = [
$journal['user_id'], $journal['transaction_group_id'], $journal['transaction_journal_id'], $journal['created_at']->toAtomString(), $journal['updated_at']->toAtomString(), $journal['transaction_group_title'], $journal['transaction_type_type'], $journal['amount'], $journal['foreign_amount'], $journal['currency_code'], $journal['foreign_currency_code'], $journal['description'], $journal['date']->toAtomString(), $journal['source_account_name'], $journal['source_account_iban'], $journal['source_account_type'], $journal['destination_account_name'], $journal['destination_account_iban'], $journal['destination_account_type'], $journal['reconciled'], $journal['category_name'], $journal['budget_name'], $journal['bill_name'],
$metaData = $repository->getMetaFields($journal['transaction_journal_id'], $metaFields);
$amount = Steam::bcround(Steam::negative($journal['amount']), $journal['currency_decimal_places']);
$foreignAmount = null === $journal['foreign_amount'] ? null : Steam::bcround(Steam::negative($journal['foreign_amount']), $journal['foreign_currency_decimal_places']);
$nativeAmount = null === $journal['native_amount'] ? null : Steam::bcround(Steam::negative($journal['native_amount']), $default->decimal_places);
$nativeForeignAmount = null === $journal['native_foreign_amount'] ? null : Steam::bcround(Steam::negative($journal['native_foreign_amount']), $default->decimal_places);
if (TransactionTypeEnum::WITHDRAWAL->value !== $journal['transaction_type_type']) {
$amount = Steam::bcround(Steam::positive($journal['amount']), $journal['currency_decimal_places']);
$foreignAmount = null === $journal['foreign_amount'] ? null : Steam::bcround(Steam::positive($journal['foreign_amount']), $journal['foreign_currency_decimal_places']);
$nativeAmount = null === $journal['native_amount'] ? null : Steam::bcround(Steam::positive($journal['native_amount']), $default->decimal_places);
$nativeForeignAmount = null === $journal['native_foreign_amount'] ? null : Steam::bcround(Steam::positive($journal['native_foreign_amount']), $default->decimal_places);
}
// opening balance depends on source account type.
if (TransactionTypeEnum::OPENING_BALANCE->value === $journal['transaction_type_type'] && AccountTypeEnum::ASSET->value === $journal['source_account_type']) {
$amount = Steam::bcround(Steam::negative($journal['amount']), $journal['currency_decimal_places']);
$foreignAmount = null === $journal['foreign_amount'] ? null : Steam::bcround(Steam::negative($journal['foreign_amount']), $journal['foreign_currency_decimal_places']);
$nativeAmount = null === $journal['native_amount'] ? null : Steam::bcround(Steam::negative($journal['native_amount']), $default->decimal_places);
$nativeForeignAmount = null === $journal['native_foreign_amount'] ? null : Steam::bcround(Steam::negative($journal['native_foreign_amount']), $default->decimal_places);
}
$records[] = [
$journal['user_id'], $journal['transaction_group_id'], $journal['transaction_journal_id'], $journal['created_at']->toAtomString(), $journal['updated_at']->toAtomString(), $journal['transaction_group_title'], $journal['transaction_type_type'],
// amounts and currencies
$journal['currency_code'], $amount, $journal['foreign_currency_code'], $foreignAmount, $default->code, $nativeAmount, $nativeForeignAmount,
// more fields
$journal['description'], $journal['date']->toAtomString(), $journal['source_account_name'], $journal['source_account_iban'], $journal['source_account_type'], $journal['destination_account_name'], $journal['destination_account_iban'], $journal['destination_account_type'], $journal['reconciled'], $journal['category_name'], $journal['budget_name'], $journal['bill_name'],
$this->mergeTags($journal['tags']),
$this->clearStringKeepNewlines($journal['notes']),

View File

@@ -60,7 +60,7 @@ class CurrencyForm
$classes = $this->getHolderClasses($name);
$value = $this->fillFieldValue($name, $value);
$options['step'] = 'any';
$defaultCurrency = $options['currency'] ?? app('amount')->getDefaultCurrency();
$defaultCurrency = $options['currency'] ?? app('amount')->getNativeCurrency();
/** @var Collection $currencies */
$currencies = app('amount')->getCurrencies();
@@ -128,7 +128,7 @@ class CurrencyForm
$classes = $this->getHolderClasses($name);
$value = $this->fillFieldValue($name, $value);
$options['step'] = 'any';
$defaultCurrency = $options['currency'] ?? app('amount')->getDefaultCurrency();
$defaultCurrency = $options['currency'] ?? app('amount')->getNativeCurrency();
/** @var Collection $currencies */
$currencies = app('amount')->getAllCurrencies();

View File

@@ -66,7 +66,7 @@ trait ChartGeneration
/** @var AccountRepositoryInterface $accountRepos */
$accountRepos = app(AccountRepositoryInterface::class);
$default = app('amount')->getDefaultCurrency();
$default = app('amount')->getNativeCurrency();
$chartData = [];
/** @var Account $account */

View File

@@ -82,7 +82,7 @@ class AccountEnrichment implements EnrichmentInterface
Log::debug(sprintf('Now doing account enrichment for %d account(s)', $collection->count()));
// prep local fields
$this->collection = $collection;
$this->default = app('amount')->getDefaultCurrency();
$this->default = app('amount')->getNativeCurrency();
$this->currencies = [];
$this->balances = [];
$this->objectGroups = [];

View File

@@ -347,6 +347,6 @@ class BudgetReportGenerator
$this->blRepository->setUser($user);
$this->opsRepository->setUser($user);
$this->nbRepository->setUser($user);
$this->currency = app('amount')->getDefaultCurrencyByUserGroup($user->userGroup);
$this->currency = app('amount')->getNativeCurrencyByUserGroup($user->userGroup);
}
}

View File

@@ -45,7 +45,7 @@ class TransactionSummarizer
public function setUser(User $user): void
{
$this->user = $user;
$this->default = Amount::getDefaultCurrencyByUserGroup($user->userGroup);
$this->default = Amount::getNativeCurrencyByUserGroup($user->userGroup);
$this->convertToNative = Amount::convertToNative($user);
}
@@ -117,7 +117,7 @@ class TransactionSummarizer
$idKey = sprintf('%s_account_id', $direction);
$nameKey = sprintf('%s_account_name', $direction);
$convertToNative = Amount::convertToNative($this->user);
$default = Amount::getDefaultCurrencyByUserGroup($this->user->userGroup);
$default = Amount::getNativeCurrencyByUserGroup($this->user->userGroup);

View File

@@ -0,0 +1,39 @@
<?php
/*
* NodeResult.php
* Copyright (c) 2025 https://github.com/Sobuno
*
* 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\Support\Search\QueryParser;
/**
* Represents a result from parsing a query node
*
* Contains the parsed node and a flag indicating if this is the end of the query.
* Used to handle subquery parsing and termination.
*/
class NodeResult
{
public function __construct(
public readonly ?Node $node,
public readonly bool $isSubqueryEnd
) {}
}

View File

@@ -27,21 +27,6 @@ namespace FireflyIII\Support\Search\QueryParser;
use Illuminate\Support\Facades\Log;
/**
* Represents a result from parsing a query node
*
* Contains the parsed node and a flag indicating if this is the end of the query.
* Used to handle subquery parsing and termination.
*/
class NodeResult
{
public function __construct(
public readonly ?Node $node,
public readonly bool $isSubqueryEnd
) {}
}
/**
* Single-pass parser that processes query strings into structured nodes.
* Scans each character once (O(n)) to build field searches, quoted strings,
@@ -108,7 +93,7 @@ class QueryParser implements QueryParserInterface
case '-':
if ('' === $tokenUnderConstruction) {
// A minus sign at the beginning of a token indicates prohibition
Log::debug('Indicate prohibition');
// Log::debug('Indicate prohibition');
$prohibited = true;
}
if ('' !== $tokenUnderConstruction) {
@@ -170,7 +155,7 @@ class QueryParser implements QueryParserInterface
$fieldName = $tokenUnderConstruction;
$tokenUnderConstruction = '';
}
if ('' === $tokenUnderConstruction) {
if ('' === $tokenUnderConstruction) { // @phpstan-ignore-line
// In any other location, it's just a normal character
$tokenUnderConstruction .= $char;
}
@@ -208,6 +193,8 @@ class QueryParser implements QueryParserInterface
{
if ('' !== $fieldName) {
Log::debug(sprintf('Create FieldNode %s:%s (%s)', $fieldName, $token, var_export($prohibited, true)));
$token = ltrim($token, ':"');
$token = rtrim($token, '"');
return new FieldNode(trim($fieldName), trim($token), $prohibited);
}

View File

@@ -75,7 +75,7 @@ class Steam
$balances = [];
$formatted = $start->format('Y-m-d');
$startBalance = $this->finalAccountBalance($account, $start);
$defaultCurrency = app('amount')->getDefaultCurrencyByUserGroup($account->user->userGroup);
$defaultCurrency = app('amount')->getNativeCurrencyByUserGroup($account->user->userGroup);
$accountCurrency = $this->getAccountCurrency($account);
$hasCurrency = null !== $accountCurrency;
$currency = $accountCurrency ?? $defaultCurrency;
@@ -305,7 +305,7 @@ class Steam
Log::debug(sprintf('Now in finalAccountBalance(#%d, "%s", "%s")', $account->id, $account->name, $date->format('Y-m-d H:i:s')));
$native = Amount::getDefaultCurrencyByUserGroup($account->user->userGroup);
$native = Amount::getNativeCurrencyByUserGroup($account->user->userGroup);
$convertToNative = Amount::convertToNative($account->user);
$accountCurrency = $this->getAccountCurrency($account);
$hasCurrency = null !== $accountCurrency;
@@ -407,7 +407,7 @@ class Steam
return [];
}
$defaultCurrency = app('amount')->getDefaultCurrency();
$defaultCurrency = app('amount')->getNativeCurrency();
if ($convertToNative) {
if ($defaultCurrency->id === $currency?->id) {
Log::debug(sprintf('Unset "native_balance" and "%s" for account #%d', $defaultCurrency->code, $account->id));

View File

@@ -48,7 +48,7 @@ class AmountFormat extends AbstractExtension
return new TwigFilter(
'formatAmount',
static function (string $string): string {
$currency = app('amount')->getDefaultCurrency();
$currency = app('amount')->getNativeCurrency();
return app('amount')->formatAnything($currency, $string, true);
},
@@ -61,7 +61,7 @@ class AmountFormat extends AbstractExtension
return new TwigFilter(
'formatAmountPlain',
static function (string $string): string {
$currency = app('amount')->getDefaultCurrency();
$currency = app('amount')->getNativeCurrency();
return app('amount')->formatAnything($currency, $string, false);
},
@@ -93,7 +93,7 @@ class AmountFormat extends AbstractExtension
/** @var AccountRepositoryInterface $accountRepos */
$accountRepos = app(AccountRepositoryInterface::class);
$currency = $accountRepos->getAccountCurrency($account) ?? app('amount')->getDefaultCurrency();
$currency = $accountRepos->getAccountCurrency($account) ?? app('amount')->getNativeCurrency();
return app('amount')->formatAnything($currency, $amount, $coloured);
},

View File

@@ -69,7 +69,7 @@ class General extends AbstractExtension
$date = session('end', today(config('app.timezone'))->endOfMonth());
$info = Steam::finalAccountBalance($account, $date);
$currency = Steam::getAccountCurrency($account);
$default = Amount::getDefaultCurrency();
$default = Amount::getNativeCurrency();
$convertToNative = Amount::convertToNative();
$useNative = $convertToNative && $default->id !== $currency->id;
$strings = [];

View File

@@ -27,7 +27,9 @@ namespace FireflyIII\Transformers;
use Carbon\Carbon;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Models\Account;
use FireflyIII\Models\TransactionCurrency;
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use FireflyIII\Support\Facades\Amount;
use FireflyIII\Support\Facades\Steam;
use Symfony\Component\HttpFoundation\ParameterBag;
@@ -37,14 +39,18 @@ use Symfony\Component\HttpFoundation\ParameterBag;
class AccountTransformer extends AbstractTransformer
{
protected AccountRepositoryInterface $repository;
protected bool $convertToNative;
protected TransactionCurrency $default;
/**
* AccountTransformer constructor.
*/
public function __construct()
{
$this->parameters = new ParameterBag();
$this->repository = app(AccountRepositoryInterface::class);
$this->parameters = new ParameterBag();
$this->repository = app(AccountRepositoryInterface::class);
$this->convertToNative = Amount::convertToNative();
$this->default = Amount::getNativeCurrency();
}
/**
@@ -57,22 +63,31 @@ class AccountTransformer extends AbstractTransformer
$this->repository->setUser($account->user);
// get account type:
$fullType = $account->accountType->type;
$accountType = (string) config(sprintf('firefly.shortNamesByFullName.%s', $fullType));
$liabilityType = (string) config(sprintf('firefly.shortLiabilityNameByFullName.%s', $fullType));
$liabilityType = '' === $liabilityType ? null : strtolower($liabilityType);
$liabilityDirection = $this->repository->getMetaValue($account, 'liability_direction');
$convertToNative = Amount::convertToNative();
// get account role (will only work if the type is asset.
// get account role (will only work if the type is asset).
$default = Amount::getNativeCurrency();
$accountRole = $this->getAccountRole($account, $accountType);
$date = $this->getDate();
$date->endOfDay();
[$currencyId, $currencyCode, $currencySymbol, $decimalPlaces] = $this->getCurrency($account);
[$creditCardType, $monthlyPaymentDate] = $this->getCCInfo($account, $accountRole, $accountType);
[$openingBalance, $openingBalanceDate] = $this->getOpeningBalance($account, $accountType);
[$openingBalance, $nativeOpeningBalance, $openingBalanceDate] = $this->getOpeningBalance($account, $accountType, $convertToNative);
[$interest, $interestPeriod] = $this->getInterest($account, $accountType);
$default = $this->default;
if (!$this->convertToNative) {
// reset default currency to NULL, not interesting.
$default = null;
}
$openingBalance = app('steam')->bcround($openingBalance, $decimalPlaces);
$includeNetWorth = '0' !== $this->repository->getMetaValue($account, 'include_net_worth');
$longitude = null;
@@ -90,41 +105,56 @@ class AccountTransformer extends AbstractTransformer
if (!in_array(strtolower($accountType), ['liability', 'liabilities', 'asset'], true)) {
$order = null;
}
// balance, native balance, virtual balance, native virtual balance?
$finalBalance = Steam::finalAccountBalance($account, $date);
if ($convertToNative) {
$finalBalance['balance'] = $finalBalance[$currencyCode] ?? '0';
}
$currentBalance = app('steam')->bcround($finalBalance['balance'] ?? '0', $decimalPlaces);
$nativeCurrentBalance = $convertToNative ? app('steam')->bcround($finalBalance['native_balance'] ?? '0', $default->decimal_places) : null;
return [
'id' => (string) $account->id,
'created_at' => $account->created_at->toAtomString(),
'updated_at' => $account->updated_at->toAtomString(),
'active' => $account->active,
'order' => $order,
'name' => $account->name,
'type' => strtolower($accountType),
'account_role' => $accountRole,
'currency_id' => $currencyId,
'currency_code' => $currencyCode,
'currency_symbol' => $currencySymbol,
'currency_decimal_places' => $decimalPlaces,
'current_balance' => app('steam')->bcround(Steam::finalAccountBalance($account, $date)['balance'] ?? '0', $decimalPlaces),
'current_balance_date' => $date->toAtomString(),
'notes' => $this->repository->getNoteText($account),
'monthly_payment_date' => $monthlyPaymentDate,
'credit_card_type' => $creditCardType,
'account_number' => $this->repository->getMetaValue($account, 'account_number'),
'iban' => '' === $account->iban ? null : $account->iban,
'bic' => $this->repository->getMetaValue($account, 'BIC'),
'virtual_balance' => app('steam')->bcround($account->virtual_balance, $decimalPlaces),
'opening_balance' => $openingBalance,
'opening_balance_date' => $openingBalanceDate,
'liability_type' => $liabilityType,
'liability_direction' => $liabilityDirection,
'interest' => $interest,
'interest_period' => $interestPeriod,
'current_debt' => $this->repository->getMetaValue($account, 'current_debt'),
'include_net_worth' => $includeNetWorth,
'longitude' => $longitude,
'latitude' => $latitude,
'zoom_level' => $zoomLevel,
'links' => [
'id' => (string) $account->id,
'created_at' => $account->created_at->toAtomString(),
'updated_at' => $account->updated_at->toAtomString(),
'active' => $account->active,
'order' => $order,
'name' => $account->name,
'type' => strtolower($accountType),
'account_role' => $accountRole,
'currency_id' => $currencyId,
'currency_code' => $currencyCode,
'currency_symbol' => $currencySymbol,
'currency_decimal_places' => $decimalPlaces,
'native_currency_id' => null === $default ? null : (string) $default->id,
'native_currency_code' => $default?->code,
'native_currency_symbol' => $default?->symbol,
'native_currency_decimal_places' => $default?->decimal_places,
'current_balance' => $currentBalance,
'native_current_balance' => $nativeCurrentBalance,
'current_balance_date' => $date->toAtomString(),
'notes' => $this->repository->getNoteText($account),
'monthly_payment_date' => $monthlyPaymentDate,
'credit_card_type' => $creditCardType,
'account_number' => $this->repository->getMetaValue($account, 'account_number'),
'iban' => '' === $account->iban ? null : $account->iban,
'bic' => $this->repository->getMetaValue($account, 'BIC'),
'virtual_balance' => app('steam')->bcround($account->virtual_balance, $decimalPlaces),
'native_virtual_balance' => $this->convertToNative ? app('steam')->bcround($account->native_virtual_balance, $default->decimal_places) : null,
'opening_balance' => $openingBalance,
'native_opening_balance' => $nativeOpeningBalance,
'opening_balance_date' => $openingBalanceDate,
'liability_type' => $liabilityType,
'liability_direction' => $liabilityDirection,
'interest' => $interest,
'interest_period' => $interestPeriod,
'current_debt' => $this->repository->getMetaValue($account, 'current_debt'),
'include_net_worth' => $includeNetWorth,
'longitude' => $longitude,
'latitude' => $latitude,
'zoom_level' => $zoomLevel,
'links' => [
[
'rel' => 'self',
'uri' => '/accounts/'.$account->id,
@@ -156,16 +186,13 @@ class AccountTransformer extends AbstractTransformer
return $date;
}
/**
* @throws FireflyException
*/
private function getCurrency(Account $account): array
{
$currency = $this->repository->getAccountCurrency($account);
// only grab default when result is null:
if (null === $currency) {
$currency = app('amount')->getDefaultCurrencyByUserGroup($account->user->userGroup);
$currency = $this->default;
}
$currencyId = (string) $currency->id;
$currencyCode = $currency->code;
@@ -203,14 +230,15 @@ class AccountTransformer extends AbstractTransformer
/**
* TODO refactor call to get~OpeningBalanceAmount / Date because it is a lot of queries
*/
private function getOpeningBalance(Account $account, string $accountType): array
private function getOpeningBalance(Account $account, string $accountType, bool $convertToNative): array
{
$openingBalance = null;
$openingBalanceDate = null;
$openingBalance = null;
$openingBalanceDate = null;
$nativeOpeningBalance = null;
if (in_array($accountType, ['asset', 'liabilities'], true)) {
$amount = $this->repository->getOpeningBalanceAmount($account);
$openingBalance = $amount;
$openingBalanceDate = $this->repository->getOpeningBalanceDate($account);
$openingBalance = $this->repository->getOpeningBalanceAmount($account, false);
$nativeOpeningBalance = $this->repository->getOpeningBalanceAmount($account, true);
$openingBalanceDate = $this->repository->getOpeningBalanceDate($account);
}
if (null !== $openingBalanceDate) {
$object = Carbon::createFromFormat('Y-m-d H:i:s', $openingBalanceDate, config('app.timezone'));
@@ -220,7 +248,7 @@ class AccountTransformer extends AbstractTransformer
$openingBalanceDate = $object->toAtomString();
}
return [$openingBalance, $openingBalanceDate];
return [$openingBalance, $nativeOpeningBalance, $openingBalanceDate];
}
private function getInterest(Account $account, string $accountType): array

View File

@@ -25,9 +25,11 @@ declare(strict_types=1);
namespace FireflyIII\Transformers;
use FireflyIII\Models\AvailableBudget;
use FireflyIII\Models\TransactionCurrency;
use FireflyIII\Repositories\Budget\BudgetRepositoryInterface;
use FireflyIII\Repositories\Budget\NoBudgetRepositoryInterface;
use FireflyIII\Repositories\Budget\OperationsRepositoryInterface;
use FireflyIII\Support\Facades\Amount;
/**
* Class AvailableBudgetTransformer
@@ -37,6 +39,8 @@ class AvailableBudgetTransformer extends AbstractTransformer
private NoBudgetRepositoryInterface $noBudgetRepository;
private OperationsRepositoryInterface $opsRepository;
private BudgetRepositoryInterface $repository;
private TransactionCurrency $default;
private bool $convertToNative;
/**
* CurrencyTransformer constructor.
@@ -46,6 +50,8 @@ class AvailableBudgetTransformer extends AbstractTransformer
$this->repository = app(BudgetRepositoryInterface::class);
$this->opsRepository = app(OperationsRepositoryInterface::class);
$this->noBudgetRepository = app(NoBudgetRepositoryInterface::class);
$this->default = Amount::getNativeCurrency();
$this->convertToNative = Amount::convertToNative();
}
/**
@@ -56,20 +62,29 @@ class AvailableBudgetTransformer extends AbstractTransformer
$this->repository->setUser($availableBudget->user);
$currency = $availableBudget->transactionCurrency;
$default = $this->default;
if (!$this->convertToNative) {
$default = null;
}
$data = [
'id' => (string) $availableBudget->id,
'created_at' => $availableBudget->created_at->toAtomString(),
'updated_at' => $availableBudget->updated_at->toAtomString(),
'currency_id' => (string) $currency->id,
'currency_code' => $currency->code,
'currency_symbol' => $currency->symbol,
'currency_decimal_places' => $currency->decimal_places,
'amount' => app('steam')->bcround($availableBudget->amount, $currency->decimal_places),
'start' => $availableBudget->start_date->toAtomString(),
'end' => $availableBudget->end_date->endOfDay()->toAtomString(),
'spent_in_budgets' => [],
'spent_no_budget' => [],
'links' => [
'id' => (string) $availableBudget->id,
'created_at' => $availableBudget->created_at->toAtomString(),
'updated_at' => $availableBudget->updated_at->toAtomString(),
'currency_id' => (string) $currency->id,
'currency_code' => $currency->code,
'currency_symbol' => $currency->symbol,
'currency_decimal_places' => $currency->decimal_places,
'native_currency_id' => null === $default ? null : (string) $default->id,
'native_currency_code' => $default?->code,
'native_currency_symbol' => $default?->symbol,
'native_currency_decimal_places' => $default?->decimal_places,
'amount' => app('steam')->bcround($availableBudget->amount, $currency->decimal_places),
'native_amount' => $this->convertToNative ? app('steam')->bcround($availableBudget->native_amount, $currency->decimal_places) : null,
'start' => $availableBudget->start_date->toAtomString(),
'end' => $availableBudget->end_date->endOfDay()->toAtomString(),
'spent_in_budgets' => [],
'spent_no_budget' => [],
'links' => [
[
'rel' => 'self',
'uri' => '/available_budgets/'.$availableBudget->id,

View File

@@ -28,8 +28,10 @@ use Carbon\Carbon;
use Carbon\CarbonInterface;
use FireflyIII\Models\Bill;
use FireflyIII\Models\ObjectGroup;
use FireflyIII\Models\TransactionCurrency;
use FireflyIII\Models\TransactionJournal;
use FireflyIII\Repositories\Bill\BillRepositoryInterface;
use FireflyIII\Support\Facades\Amount;
use FireflyIII\Support\Models\BillDateCalculator;
use Illuminate\Support\Collection;
@@ -40,14 +42,18 @@ class BillTransformer extends AbstractTransformer
{
private BillDateCalculator $calculator;
private BillRepositoryInterface $repository;
private TransactionCurrency $default;
private bool $convertToNative;
/**
* BillTransformer constructor.
*/
public function __construct()
{
$this->repository = app(BillRepositoryInterface::class);
$this->calculator = app(BillDateCalculator::class);
$this->repository = app(BillRepositoryInterface::class);
$this->calculator = app(BillDateCalculator::class);
$this->default = Amount::getNativeCurrency();
$this->convertToNative = Amount::convertToNative();
}
/**
@@ -58,7 +64,7 @@ class BillTransformer extends AbstractTransformer
*/
public function transform(Bill $bill): array
{
$defaultCurrency = $this->parameters->get('defaultCurrency') ?? app('amount')->getDefaultCurrency();
$default = $this->parameters->get('defaultCurrency') ?? $this->default;
$paidData = $this->paidData($bill);
$lastPaidDate = $this->getLastPaidDate($paidData);
@@ -141,36 +147,40 @@ class BillTransformer extends AbstractTransformer
}
return [
'id' => $bill->id,
'created_at' => $bill->created_at->toAtomString(),
'updated_at' => $bill->updated_at->toAtomString(),
'currency_id' => (string) $bill->transaction_currency_id,
'currency_code' => $currency->code,
'currency_symbol' => $currency->symbol,
'currency_decimal_places' => $currency->decimal_places,
'name' => $bill->name,
'amount_min' => app('steam')->bcround($bill->amount_min, $currency->decimal_places),
'amount_max' => app('steam')->bcround($bill->amount_max, $currency->decimal_places),
'native_amount_min' => app('steam')->bcround($bill->native_amount_min, $defaultCurrency->decimal_places),
'native_amount_max' => app('steam')->bcround($bill->native_amount_max, $defaultCurrency->decimal_places),
'date' => $bill->date->toAtomString(),
'end_date' => $bill->end_date?->toAtomString(),
'extension_date' => $bill->extension_date?->toAtomString(),
'repeat_freq' => $bill->repeat_freq,
'skip' => $bill->skip,
'active' => $bill->active,
'order' => $bill->order,
'notes' => $notes,
'object_group_id' => null !== $objectGroupId ? (string) $objectGroupId : null,
'object_group_order' => $objectGroupOrder,
'object_group_title' => $objectGroupTitle,
'id' => $bill->id,
'created_at' => $bill->created_at->toAtomString(),
'updated_at' => $bill->updated_at->toAtomString(),
'currency_id' => (string) $bill->transaction_currency_id,
'currency_code' => $currency->code,
'currency_symbol' => $currency->symbol,
'currency_decimal_places' => $currency->decimal_places,
'native_currency_id' => null === $default ? null : (string) $default->id,
'native_currency_code' => $default?->code,
'native_currency_symbol' => $default?->symbol,
'native_currency_decimal_places' => $default?->decimal_places,
'name' => $bill->name,
'amount_min' => app('steam')->bcround($bill->amount_min, $currency->decimal_places),
'amount_max' => app('steam')->bcround($bill->amount_max, $currency->decimal_places),
'native_amount_min' => $this->convertToNative ? app('steam')->bcround($bill->native_amount_min, $default->decimal_places) : null,
'native_amount_max' => $this->convertToNative ? app('steam')->bcround($bill->native_amount_max, $default->decimal_places) : null,
'date' => $bill->date->toAtomString(),
'end_date' => $bill->end_date?->toAtomString(),
'extension_date' => $bill->extension_date?->toAtomString(),
'repeat_freq' => $bill->repeat_freq,
'skip' => $bill->skip,
'active' => $bill->active,
'order' => $bill->order,
'notes' => $notes,
'object_group_id' => null !== $objectGroupId ? (string) $objectGroupId : null,
'object_group_order' => $objectGroupOrder,
'object_group_title' => $objectGroupTitle,
// these fields need work:
'next_expected_match' => $nem,
'next_expected_match_diff' => $nemDiff,
'pay_dates' => $payDatesFormatted,
'paid_dates' => $paidDataFormatted,
'links' => [
'next_expected_match' => $nem,
'next_expected_match_diff' => $nemDiff,
'pay_dates' => $payDatesFormatted,
'paid_dates' => $paidDataFormatted,
'links' => [
[
'rel' => 'self',
'uri' => '/bills/'.$bill->id,

View File

@@ -25,8 +25,10 @@ declare(strict_types=1);
namespace FireflyIII\Transformers;
use FireflyIII\Models\BudgetLimit;
use FireflyIII\Models\TransactionCurrency;
use FireflyIII\Repositories\Budget\BudgetLimitRepositoryInterface;
use FireflyIII\Repositories\Budget\OperationsRepository;
use FireflyIII\Support\Facades\Amount;
use Illuminate\Support\Collection;
use League\Fractal\Resource\Item;
@@ -40,6 +42,15 @@ class BudgetLimitTransformer extends AbstractTransformer
'budget',
];
protected TransactionCurrency $default;
protected bool $convertToNative;
public function __construct()
{
$this->default = Amount::getNativeCurrency();
$this->convertToNative = Amount::convertToNative();
}
/**
* Include Budget
*
@@ -83,24 +94,34 @@ class BudgetLimitTransformer extends AbstractTransformer
$currencyDecimalPlaces = $currency->decimal_places;
}
$amount = app('steam')->bcround($amount, $currencyDecimalPlaces);
$default = $this->default;
if (!$this->convertToNative) {
$default = null;
}
return [
'id' => (string) $budgetLimit->id,
'created_at' => $budgetLimit->created_at->toAtomString(),
'updated_at' => $budgetLimit->updated_at->toAtomString(),
'start' => $budgetLimit->start_date->toAtomString(),
'end' => $budgetLimit->end_date->endOfDay()->toAtomString(),
'budget_id' => (string) $budgetLimit->budget_id,
'currency_id' => (string) $currencyId,
'currency_code' => $currencyCode,
'currency_name' => $currencyName,
'currency_decimal_places' => $currencyDecimalPlaces,
'currency_symbol' => $currencySymbol,
'amount' => $amount,
'period' => $budgetLimit->period,
'spent' => $expenses[$currencyId]['sum'] ?? '0',
'notes' => '' === $notes ? null : $notes,
'links' => [
'id' => (string) $budgetLimit->id,
'created_at' => $budgetLimit->created_at->toAtomString(),
'updated_at' => $budgetLimit->updated_at->toAtomString(),
'start' => $budgetLimit->start_date->toAtomString(),
'end' => $budgetLimit->end_date->endOfDay()->toAtomString(),
'budget_id' => (string) $budgetLimit->budget_id,
'currency_id' => (string) $currencyId,
'currency_code' => $currencyCode,
'currency_name' => $currencyName,
'currency_decimal_places' => $currencyDecimalPlaces,
'currency_symbol' => $currencySymbol,
'native_currency_id' => null === $default ? null : (string) $default->id,
'native_currency_code' => $default?->code,
'native_currency_symbol' => $default?->symbol,
'native_currency_decimal_places' => $default?->decimal_places,
'amount' => $amount,
'native_amount' => $this->convertToNative ? app('steam')->bcround($budgetLimit->native_amount, $default->decimal_places) : null,
'period' => $budgetLimit->period,
'spent' => $expenses[$currencyId]['sum'] ?? '0', // will be in native if convertToNative.
'notes' => '' === $notes ? null : $notes,
'links' => [
[
'rel' => 'self',
'uri' => '/budgets/limits/'.$budgetLimit->id,

View File

@@ -26,8 +26,10 @@ namespace FireflyIII\Transformers;
use FireflyIII\Enums\AutoBudgetType;
use FireflyIII\Models\Budget;
use FireflyIII\Models\TransactionCurrency;
use FireflyIII\Repositories\Budget\BudgetRepositoryInterface;
use FireflyIII\Repositories\Budget\OperationsRepositoryInterface;
use FireflyIII\Support\Facades\Amount;
use Illuminate\Support\Collection;
use Symfony\Component\HttpFoundation\ParameterBag;
@@ -38,15 +40,19 @@ class BudgetTransformer extends AbstractTransformer
{
private OperationsRepositoryInterface $opsRepository;
private BudgetRepositoryInterface $repository;
private bool $convertToNative;
private TransactionCurrency $default;
/**
* BudgetTransformer constructor.
*/
public function __construct()
{
$this->opsRepository = app(OperationsRepositoryInterface::class);
$this->repository = app(BudgetRepositoryInterface::class);
$this->parameters = new ParameterBag();
$this->opsRepository = app(OperationsRepositoryInterface::class);
$this->repository = app(BudgetRepositoryInterface::class);
$this->parameters = new ParameterBag();
$this->default = Amount::getNativeCurrency();
$this->convertToNative = Amount::convertToNative();
}
/**
@@ -55,50 +61,68 @@ class BudgetTransformer extends AbstractTransformer
public function transform(Budget $budget): array
{
$this->opsRepository->setUser($budget->user);
$start = $this->parameters->get('start');
$end = $this->parameters->get('end');
$autoBudget = $this->repository->getAutoBudget($budget);
$spent = [];
$start = $this->parameters->get('start');
$end = $this->parameters->get('end');
$autoBudget = $this->repository->getAutoBudget($budget);
$spent = [];
if (null !== $start && null !== $end) {
$spent = $this->beautify($this->opsRepository->sumExpenses($start, $end, null, new Collection([$budget])));
}
$abCurrencyId = null;
$abCurrencyCode = null;
$abType = null;
$abAmount = null;
$abPeriod = null;
$notes = $this->repository->getNoteText($budget);
// info for auto budget.
$abType = null;
$abAmount = null;
$abNative = null;
$abPeriod = null;
$notes = $this->repository->getNoteText($budget);
$types = [
$types = [
AutoBudgetType::AUTO_BUDGET_RESET->value => 'reset',
AutoBudgetType::AUTO_BUDGET_ROLLOVER->value => 'rollover',
AutoBudgetType::AUTO_BUDGET_ADJUSTED->value => 'adjusted',
];
$currency = $autoBudget?->transactionCurrency;
$default = $this->default;
if (!$this->convertToNative) {
$default = null;
}
if (null === $autoBudget) {
$currency = $default;
}
if (null !== $autoBudget) {
$abCurrencyId = (string) $autoBudget->transactionCurrency->id;
$abCurrencyCode = $autoBudget->transactionCurrency->code;
$abType = $types[$autoBudget->auto_budget_type];
$abAmount = app('steam')->bcround($autoBudget->amount, $autoBudget->transactionCurrency->decimal_places);
$abPeriod = $autoBudget->period;
$abType = $types[$autoBudget->auto_budget_type];
$abAmount = app('steam')->bcround($autoBudget->amount, $currency->decimal_places);
$abNative = $this->convertToNative ? app('steam')->bcround($autoBudget->native_amount, $default->decimal_places) : null;
$abPeriod = $autoBudget->period;
}
return [
'id' => (string) $budget->id,
'created_at' => $budget->created_at->toAtomString(),
'updated_at' => $budget->updated_at->toAtomString(),
'active' => $budget->active,
'name' => $budget->name,
'order' => $budget->order,
'notes' => $notes,
'auto_budget_type' => $abType,
'auto_budget_period' => $abPeriod,
'auto_budget_currency_id' => $abCurrencyId,
'auto_budget_currency_code' => $abCurrencyCode,
'auto_budget_amount' => $abAmount,
'spent' => $spent,
'links' => [
'id' => (string) $budget->id,
'created_at' => $budget->created_at->toAtomString(),
'updated_at' => $budget->updated_at->toAtomString(),
'active' => $budget->active,
'name' => $budget->name,
'order' => $budget->order,
'notes' => $notes,
'auto_budget_type' => $abType,
'auto_budget_period' => $abPeriod,
'currency_id' => null === $autoBudget ? null : (string) $autoBudget->transactionCurrency->id,
'currency_code' => $autoBudget?->transactionCurrency->code,
'currency_name' => $autoBudget?->transactionCurrency->name,
'currency_decimal_places' => $autoBudget?->transactionCurrency->decimal_places,
'currency_symbol' => $autoBudget?->transactionCurrency->symbol,
'native_currency_id' => null === $default ? null : (string) $default->id,
'native_currency_code' => $default?->code,
'native_currency_symbol' => $default?->symbol,
'native_currency_decimal_places' => $default?->decimal_places,
// amount and native amount if present.
'auto_budget_amount' => $abAmount,
'native_auto_budget_amount' => $abNative,
'spent' => $spent, // always in native.
'links' => [
[
'rel' => 'self',
'uri' => '/budgets/'.$budget->id,

View File

@@ -25,8 +25,10 @@ declare(strict_types=1);
namespace FireflyIII\Transformers;
use FireflyIII\Models\Category;
use FireflyIII\Models\TransactionCurrency;
use FireflyIII\Repositories\Category\CategoryRepositoryInterface;
use FireflyIII\Repositories\Category\OperationsRepositoryInterface;
use FireflyIII\Support\Facades\Amount;
use Illuminate\Support\Collection;
/**
@@ -36,14 +38,18 @@ class CategoryTransformer extends AbstractTransformer
{
private OperationsRepositoryInterface $opsRepository;
private CategoryRepositoryInterface $repository;
private TransactionCurrency $default;
private bool $convertToNative;
/**
* CategoryTransformer constructor.
*/
public function __construct()
{
$this->opsRepository = app(OperationsRepositoryInterface::class);
$this->repository = app(CategoryRepositoryInterface::class);
$this->opsRepository = app(OperationsRepositoryInterface::class);
$this->repository = app(CategoryRepositoryInterface::class);
$this->default = Amount::getNativeCurrency();
$this->convertToNative = Amount::convertToNative();
}
/**
@@ -54,25 +60,33 @@ class CategoryTransformer extends AbstractTransformer
$this->opsRepository->setUser($category->user);
$this->repository->setUser($category->user);
$spent = [];
$earned = [];
$start = $this->parameters->get('start');
$end = $this->parameters->get('end');
$spent = [];
$earned = [];
$start = $this->parameters->get('start');
$end = $this->parameters->get('end');
if (null !== $start && null !== $end) {
$earned = $this->beautify($this->opsRepository->sumIncome($start, $end, null, new Collection([$category])));
$spent = $this->beautify($this->opsRepository->sumExpenses($start, $end, null, new Collection([$category])));
}
$notes = $this->repository->getNoteText($category);
$default = $this->default;
if (!$this->convertToNative) {
$default = null;
}
$notes = $this->repository->getNoteText($category);
return [
'id' => $category->id,
'created_at' => $category->created_at->toAtomString(),
'updated_at' => $category->updated_at->toAtomString(),
'name' => $category->name,
'notes' => $notes,
'spent' => $spent,
'earned' => $earned,
'links' => [
'id' => $category->id,
'created_at' => $category->created_at->toAtomString(),
'updated_at' => $category->updated_at->toAtomString(),
'name' => $category->name,
'notes' => $notes,
'native_currency_id' => null === $default ? null : (string) $default->id,
'native_currency_code' => $default?->code,
'native_currency_symbol' => $default?->symbol,
'native_currency_decimal_places' => $default?->decimal_places,
'spent' => $spent,
'earned' => $earned,
'links' => [
[
'rel' => 'self',
'uri' => '/categories/'.$category->id,

View File

@@ -40,7 +40,8 @@ class CurrencyTransformer extends AbstractTransformer
'id' => $currency->id,
'created_at' => $currency->created_at->toAtomString(),
'updated_at' => $currency->updated_at->toAtomString(),
'default' => $currency->userGroupDefault,
'native' => $currency->userGroupNative,
'default' => $currency->userGroupNative,
'enabled' => $currency->userGroupEnabled,
'name' => $currency->name,
'code' => $currency->code,

View File

@@ -61,7 +61,7 @@ class PiggyBankEventTransformer extends AbstractTransformer
$this->piggyRepos->setUser($account->user);
// get associated currency or fall back to the default:
$currency = $this->repository->getAccountCurrency($account) ?? app('amount')->getDefaultCurrencyByUserGroup($account->user->userGroup);
$currency = $this->repository->getAccountCurrency($account) ?? app('amount')->getNativeCurrencyByUserGroup($account->user->userGroup);
// get associated journal and transaction, if any:
$journalId = $event->transaction_journal_id;

View File

@@ -0,0 +1,127 @@
<?php
/*
* UserGroupTransformer.php
* Copyright (c) 2023 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\Transformers;
use FireflyIII\Enums\UserRoleEnum;
use FireflyIII\Models\GroupMembership;
use FireflyIII\Models\UserGroup;
use FireflyIII\Support\Facades\Amount;
use FireflyIII\Transformers\V2\AbstractTransformer;
use FireflyIII\User;
use Illuminate\Support\Collection;
/**
* Class UserGroupTransformer
*/
class UserGroupTransformer extends AbstractTransformer
{
private array $inUse;
private array $memberships;
private array $membershipsVisible;
public function __construct()
{
$this->memberships = [];
$this->membershipsVisible = [];
$this->inUse = [];
}
public function collectMetaData(Collection $objects): Collection
{
if (auth()->check()) {
// collect memberships so they can be listed in the group.
/** @var User $user */
$user = auth()->user();
/** @var UserGroup $userGroup */
foreach ($objects as $userGroup) {
$userGroupId = $userGroup->id;
$this->inUse[$userGroupId] = $user->user_group_id === $userGroupId;
$access = $user->hasRoleInGroupOrOwner($userGroup, UserRoleEnum::VIEW_MEMBERSHIPS) || $user->hasRole('owner');
$this->membershipsVisible[$userGroupId] = $access;
if ($access) {
$groupMemberships = $userGroup->groupMemberships()->get();
/** @var GroupMembership $groupMembership */
foreach ($groupMemberships as $groupMembership) {
$this->memberships[$userGroupId][] = [
'user_id' => (string) $groupMembership->user_id,
'user_email' => $groupMembership->user->email,
'role' => $groupMembership->userRole->title,
'you' => $groupMembership->user_id === $user->id,
];
}
}
}
$this->mergeMemberships();
}
return $objects;
}
private function mergeMemberships(): void
{
$new = [];
foreach ($this->memberships as $groupId => $members) {
$new[$groupId] ??= [];
foreach ($members as $member) {
$mail = $member['user_email'];
$new[$groupId][$mail] ??= [
'user_id' => $member['user_id'],
'user_email' => $member['user_email'],
'you' => $member['you'],
'roles' => [],
];
$new[$groupId][$mail]['roles'][] = $member['role'];
}
}
$this->memberships = $new;
}
/**
* Transform the user group.
*/
public function transform(UserGroup $userGroup): array
{
$currency = Amount::getNativeCurrencyByUserGroup($userGroup);
return [
'id' => $userGroup->id,
'created_at' => $userGroup->created_at->toAtomString(),
'updated_at' => $userGroup->updated_at->toAtomString(),
'in_use' => $this->inUse[$userGroup->id] ?? false,
'title' => $userGroup->title,
'can_see_members' => $this->membershipsVisible[$userGroup->id] ?? false,
'members' => array_values($this->memberships[$userGroup->id] ?? []),
'native_currency_id' => (string) $currency->id,
'native_currency_name' => $currency->name,
'native_currency_code' => $currency->code,
'native_currency_symbol' => $currency->symbol,
'native_currency_decimal_places' => $currency->decimal_places,
];
// if the user has a specific role in this group, then collect the memberships.
}
}

View File

@@ -135,7 +135,7 @@ class AccountTransformer extends AbstractTransformer
private function getDefaultCurrency(): void
{
$this->default = app('amount')->getDefaultCurrency();
$this->default = app('amount')->getNativeCurrency();
}
private function collectAccountMetaData(Collection $accounts): void

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