Compare commits

..

44 Commits

Author SHA1 Message Date
github-actions
e0709f2975 Auto commit for release 'develop' on 2025-02-19 2025-02-19 09:14:18 +01:00
James Cole
30007b05cb Fix #9861 2025-02-19 06:37:40 +01:00
James Cole
13fc7f0d8d Fix #9862 2025-02-19 06:21:27 +01:00
github-actions
7c85138115 Auto commit for release 'v6.2.7' on 2025-02-18 2025-02-18 19:52:25 +01:00
James Cole
2c25f65f7f Expand changelog. 2025-02-18 19:46:01 +01:00
github-actions
7eaba962e8 Auto commit for release 'develop' on 2025-02-18 2025-02-18 15:17:06 +01:00
Sander Dorigo
7c38393cde merge 2025-02-18 15:12:42 +01:00
Sander Dorigo
153fd2ae74 fix missing var 2025-02-18 15:06:51 +01:00
github-actions
c0204c810c Auto commit for release 'develop' on 2025-02-18 2025-02-18 10:31:05 +01:00
Sander Dorigo
944c107e26 Add enrichment 2025-02-18 10:26:36 +01:00
Sander Dorigo
18e05c06fd Catch nullpointer 2025-02-18 10:24:23 +01:00
Sander Dorigo
fb79dbf17c Merge branch 'develop' of https://github.com/firefly-iii/firefly-iii into develop 2025-02-18 10:22:42 +01:00
github-actions
31a8163c61 Auto commit for release 'develop' on 2025-02-17 2025-02-17 16:52:58 +01:00
Sander Dorigo
8bcd729250 remove unused script 2025-02-17 16:49:00 +01:00
Sander Dorigo
80c4e69528 Fix #9848 2025-02-17 13:43:43 +01:00
github-actions
7f6d8fdb87 Auto commit for release 'develop' on 2025-02-17 2025-02-17 13:37:44 +01:00
Sander Dorigo
c8e301326e Fix #9855 2025-02-17 13:32:07 +01:00
github-actions
4820ef6580 Auto commit for release 'develop' on 2025-02-17 2025-02-17 04:11:50 +01:00
James Cole
4cb775cf4b Various code cleanup. 2025-02-16 19:45:31 +01:00
James Cole
c371662c51 Fix missing method. 2025-02-16 19:38:07 +01:00
James Cole
ffaa164aa5 Replace facade 2025-02-16 19:32:50 +01:00
James Cole
344bfbe059 Various includes fixed, optimize account deletion. 2025-02-16 19:30:40 +01:00
James Cole
6c38b87ec5 Fix #9842 2025-02-16 07:23:03 +01:00
James Cole
dfcd5d79be Fix preferences. 2025-02-16 06:33:53 +01:00
James Cole
07631eea28 Add some debug logging. 2025-02-15 20:51:43 +01:00
James Cole
26c4fe36cc Fix #9803 2025-02-15 19:19:23 +01:00
James Cole
90fc4b44f2 A lot less queries for the account transformer. 2025-02-15 16:51:13 +01:00
James Cole
f755dd2d48 Fix nullpointer 2025-02-15 16:46:25 +01:00
James Cole
d2647f96e7 Fix type error. 2025-02-15 15:44:21 +01:00
James Cole
9f94ec067a Greatly reduce number of queries in transaction transformer. 2025-02-15 14:10:54 +01:00
James Cole
a795755618 Fix #9835 2025-02-15 07:24:31 +01:00
James Cole
8457a1c881 Add cron routine for update. 2025-02-15 06:12:02 +01:00
James Cole
fc9429bf3e Fix #9835 2025-02-15 05:39:21 +01:00
James Cole
b6e8b66035 Make sure user_group_id is rendered as int where relevant. 2025-02-15 05:38:40 +01:00
github-actions
7504b21c3e Auto commit for release 'develop' on 2025-02-12 2025-02-12 20:11:21 +01:00
github-actions
b7dad8166d Auto commit for release 'v6.2.6' on 2025-02-12 2025-02-12 20:06:45 +01:00
James Cole
2da1b43c37 Expand changelog. 2025-02-12 20:01:45 +01:00
James Cole
a606315884 Fix balance display #9826 2025-02-12 11:53:51 +01:00
github-actions
295feedd77 Auto commit for release 'develop' on 2025-02-12 2025-02-12 10:50:48 +01:00
James Cole
d3b2748c8f Ok this fix for #9797 goes out to @nebster9k who is delightfully stubborn and absolutely correct. 2025-02-12 06:38:21 +01:00
James Cole
1b4655fd70 Fix #9821 2025-02-12 06:06:28 +01:00
Sander Dorigo
05f67ef584 Fix #9810 2025-02-11 16:27:18 +01:00
Sander Dorigo
04ab7ba07d qMerge branch 'develop' of https://github.com/firefly-iii/firefly-iii into develop 2025-02-11 16:10:48 +01:00
Sander Dorigo
5806323970 Add some notes 2025-02-11 16:10:16 +01:00
105 changed files with 1922 additions and 1198 deletions

View File

@@ -406,16 +406,16 @@
}, },
{ {
"name": "friendsofphp/php-cs-fixer", "name": "friendsofphp/php-cs-fixer",
"version": "v3.68.5", "version": "v3.69.1",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer.git", "url": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer.git",
"reference": "7bedb718b633355272428c60736dc97fb96daf27" "reference": "13b0c0eede38c11cd674b080f2b485d0f14ffa9f"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/7bedb718b633355272428c60736dc97fb96daf27", "url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/13b0c0eede38c11cd674b080f2b485d0f14ffa9f",
"reference": "7bedb718b633355272428c60736dc97fb96daf27", "reference": "13b0c0eede38c11cd674b080f2b485d0f14ffa9f",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -432,7 +432,7 @@
"react/promise": "^2.0 || ^3.0", "react/promise": "^2.0 || ^3.0",
"react/socket": "^1.0", "react/socket": "^1.0",
"react/stream": "^1.0", "react/stream": "^1.0",
"sebastian/diff": "^4.0 || ^5.1 || ^6.0", "sebastian/diff": "^4.0 || ^5.1 || ^6.0 || ^7.0",
"symfony/console": "^5.4 || ^6.4 || ^7.0", "symfony/console": "^5.4 || ^6.4 || ^7.0",
"symfony/event-dispatcher": "^5.4 || ^6.4 || ^7.0", "symfony/event-dispatcher": "^5.4 || ^6.4 || ^7.0",
"symfony/filesystem": "^5.4 || ^6.4 || ^7.0", "symfony/filesystem": "^5.4 || ^6.4 || ^7.0",
@@ -445,18 +445,18 @@
"symfony/stopwatch": "^5.4 || ^6.4 || ^7.0" "symfony/stopwatch": "^5.4 || ^6.4 || ^7.0"
}, },
"require-dev": { "require-dev": {
"facile-it/paraunit": "^1.3.1 || ^2.4", "facile-it/paraunit": "^1.3.1 || ^2.5",
"infection/infection": "^0.29.8", "infection/infection": "^0.29.10",
"justinrainbow/json-schema": "^5.3 || ^6.0", "justinrainbow/json-schema": "^5.3 || ^6.0",
"keradus/cli-executor": "^2.1", "keradus/cli-executor": "^2.1",
"mikey179/vfsstream": "^1.6.12", "mikey179/vfsstream": "^1.6.12",
"php-coveralls/php-coveralls": "^2.7", "php-coveralls/php-coveralls": "^2.7",
"php-cs-fixer/accessible-object": "^1.1", "php-cs-fixer/accessible-object": "^1.1",
"php-cs-fixer/phpunit-constraint-isidenticalstring": "^1.5", "php-cs-fixer/phpunit-constraint-isidenticalstring": "^1.6",
"php-cs-fixer/phpunit-constraint-xmlmatchesxsd": "^1.5", "php-cs-fixer/phpunit-constraint-xmlmatchesxsd": "^1.6",
"phpunit/phpunit": "^9.6.22 || ^10.5.40 || ^11.5.2", "phpunit/phpunit": "^9.6.22 || ^10.5.45 || ^11.5.7",
"symfony/var-dumper": "^5.4.48 || ^6.4.15 || ^7.2.0", "symfony/var-dumper": "^5.4.48 || ^6.4.18 || ^7.2.0",
"symfony/yaml": "^5.4.45 || ^6.4.13 || ^7.2.0" "symfony/yaml": "^5.4.45 || ^6.4.18 || ^7.2.0"
}, },
"suggest": { "suggest": {
"ext-dom": "For handling output formats in XML", "ext-dom": "For handling output formats in XML",
@@ -497,7 +497,7 @@
], ],
"support": { "support": {
"issues": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/issues", "issues": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/issues",
"source": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/tree/v3.68.5" "source": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/tree/v3.69.1"
}, },
"funding": [ "funding": [
{ {
@@ -505,7 +505,7 @@
"type": "github" "type": "github"
} }
], ],
"time": "2025-01-30T17:00:50+00:00" "time": "2025-02-18T23:57:43+00:00"
}, },
{ {
"name": "psr/container", "name": "psr/container",
@@ -1188,29 +1188,29 @@
}, },
{ {
"name": "sebastian/diff", "name": "sebastian/diff",
"version": "6.0.2", "version": "7.0.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/sebastianbergmann/diff.git", "url": "https://github.com/sebastianbergmann/diff.git",
"reference": "b4ccd857127db5d41a5b676f24b51371d76d8544" "reference": "7ab1ea946c012266ca32390913653d844ecd085f"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/b4ccd857127db5d41a5b676f24b51371d76d8544", "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/7ab1ea946c012266ca32390913653d844ecd085f",
"reference": "b4ccd857127db5d41a5b676f24b51371d76d8544", "reference": "7ab1ea946c012266ca32390913653d844ecd085f",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"php": ">=8.2" "php": ">=8.3"
}, },
"require-dev": { "require-dev": {
"phpunit/phpunit": "^11.0", "phpunit/phpunit": "^12.0",
"symfony/process": "^4.2 || ^5" "symfony/process": "^7.2"
}, },
"type": "library", "type": "library",
"extra": { "extra": {
"branch-alias": { "branch-alias": {
"dev-main": "6.0-dev" "dev-main": "7.0-dev"
} }
}, },
"autoload": { "autoload": {
@@ -1243,7 +1243,7 @@
"support": { "support": {
"issues": "https://github.com/sebastianbergmann/diff/issues", "issues": "https://github.com/sebastianbergmann/diff/issues",
"security": "https://github.com/sebastianbergmann/diff/security/policy", "security": "https://github.com/sebastianbergmann/diff/security/policy",
"source": "https://github.com/sebastianbergmann/diff/tree/6.0.2" "source": "https://github.com/sebastianbergmann/diff/tree/7.0.0"
}, },
"funding": [ "funding": [
{ {
@@ -1251,7 +1251,7 @@
"type": "github" "type": "github"
} }
], ],
"time": "2024-07-03T04:53:05+00:00" "time": "2025-02-07T04:55:46+00:00"
}, },
{ {
"name": "symfony/console", "name": "symfony/console",

9
.gitignore vendored
View File

@@ -14,7 +14,16 @@ public/build
# ignore v1 build files # ignore v1 build files
resources/assets/v1/node_modules resources/assets/v1/node_modules
resources/assets/v1/build resources/assets/v1/build
public/v1/js/app.js*
public/v1/js/app_vue.js*
public/v1/js/create*
public/v1/js/edit*
public/v1/js/profile*
public/v1/js/administrations
public/v1/js/exchange-rates
public/v1/js/webhooks
# ignore v2 build files # ignore v2 build files
resources/assets/v2/node_modules resources/assets/v2/node_modules
resources/assets/v2/build resources/assets/v2/build
public/v2/i18n

View File

@@ -93,6 +93,7 @@ class AccountController extends Controller
$currency = $this->repository->getAccountCurrency($account) ?? $this->nativeCurrency; $currency = $this->repository->getAccountCurrency($account) ?? $this->nativeCurrency;
$useCurrency = $currency; $useCurrency = $currency;
if (in_array($account->accountType->type, $this->balanceTypes, true)) { if (in_array($account->accountType->type, $this->balanceTypes, true)) {
// this one is correct.
Log::debug(sprintf('accounts: Call finalAccountBalance with date/time "%s"', $date->toIso8601String())); Log::debug(sprintf('accounts: Call finalAccountBalance with date/time "%s"', $date->toIso8601String()));
$balance = Steam::finalAccountBalance($account, $date); $balance = Steam::finalAccountBalance($account, $date);
$key = $this->convertToNative && $currency->id !== $this->nativeCurrency->id ? 'native_balance' : 'balance'; $key = $this->convertToNative && $currency->id !== $this->nativeCurrency->id ? 'native_balance' : 'balance';

View File

@@ -30,6 +30,7 @@ use FireflyIII\Helpers\Collector\GroupCollectorInterface;
use FireflyIII\Models\Account; use FireflyIII\Models\Account;
use FireflyIII\Repositories\Account\AccountRepositoryInterface; use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use FireflyIII\Support\Http\Api\TransactionFilter; use FireflyIII\Support\Http\Api\TransactionFilter;
use FireflyIII\Support\JsonApi\Enrichments\TransactionGroupEnrichment;
use FireflyIII\Transformers\AttachmentTransformer; use FireflyIII\Transformers\AttachmentTransformer;
use FireflyIII\Transformers\PiggyBankTransformer; use FireflyIII\Transformers\PiggyBankTransformer;
use FireflyIII\Transformers\TransactionGroupTransformer; use FireflyIII\Transformers\TransactionGroupTransformer;
@@ -140,18 +141,18 @@ class ListController extends Controller
*/ */
public function transactions(Request $request, Account $account): JsonResponse public function transactions(Request $request, Account $account): JsonResponse
{ {
$pageSize = $this->parameters->get('limit'); $pageSize = $this->parameters->get('limit');
$type = $request->get('type') ?? 'default'; $type = $request->get('type') ?? 'default';
$this->parameters->set('type', $type); $this->parameters->set('type', $type);
$types = $this->mapTransactionTypes($this->parameters->get('type')); $types = $this->mapTransactionTypes($this->parameters->get('type'));
$manager = $this->getManager(); $manager = $this->getManager();
/** @var User $admin */ /** @var User $admin */
$admin = auth()->user(); $admin = auth()->user();
// use new group collector: // use new group collector:
/** @var GroupCollectorInterface $collector */ /** @var GroupCollectorInterface $collector */
$collector = app(GroupCollectorInterface::class); $collector = app(GroupCollectorInterface::class);
$collector->setUser($admin)->setAccounts(new Collection([$account])) $collector->setUser($admin)->setAccounts(new Collection([$account]))
->withAPIInformation()->setLimit($pageSize)->setPage($this->parameters->get('page'))->setTypes($types) ->withAPIInformation()->setLimit($pageSize)->setPage($this->parameters->get('page'))->setTypes($types)
; ;
@@ -163,15 +164,19 @@ class ListController extends Controller
$collector->setEnd($this->parameters->get('end')); $collector->setEnd($this->parameters->get('end'));
} }
$paginator = $collector->getPaginatedGroups(); $paginator = $collector->getPaginatedGroups();
$paginator->setPath(route('api.v1.accounts.transactions', [$account->id]).$this->buildParams()); $paginator->setPath(route('api.v1.accounts.transactions', [$account->id]).$this->buildParams());
$groups = $paginator->getCollection();
// enrich
$enrichment = new TransactionGroupEnrichment();
$enrichment->setUser($admin);
$transactions = $enrichment->enrich($paginator->getCollection());
/** @var TransactionGroupTransformer $transformer */ /** @var TransactionGroupTransformer $transformer */
$transformer = app(TransactionGroupTransformer::class); $transformer = app(TransactionGroupTransformer::class);
$transformer->setParameters($this->parameters); $transformer->setParameters($this->parameters);
$resource = new FractalCollection($groups, $transformer, 'transactions'); $resource = new FractalCollection($transactions, $transformer, 'transactions');
$resource->setPaginator(new IlluminatePaginatorAdapter($paginator)); $resource->setPaginator(new IlluminatePaginatorAdapter($paginator));
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', self::CONTENT_TYPE); return response()->json($manager->createData($resource)->toArray())->header('Content-Type', self::CONTENT_TYPE);

View File

@@ -29,7 +29,9 @@ use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Models\Account; use FireflyIII\Models\Account;
use FireflyIII\Repositories\Account\AccountRepositoryInterface; use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use FireflyIII\Support\Http\Api\AccountFilter; use FireflyIII\Support\Http\Api\AccountFilter;
use FireflyIII\Support\JsonApi\Enrichments\AccountEnrichment;
use FireflyIII\Transformers\AccountTransformer; use FireflyIII\Transformers\AccountTransformer;
use FireflyIII\User;
use Illuminate\Http\JsonResponse; use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use Illuminate\Pagination\LengthAwarePaginator; use Illuminate\Pagination\LengthAwarePaginator;
@@ -88,9 +90,17 @@ class ShowController extends Controller
$count = $collection->count(); $count = $collection->count();
// continue sort: // continue sort:
$accounts = $collection->slice(($this->parameters->get('page') - 1) * $pageSize, $pageSize); $accounts = $collection->slice(($this->parameters->get('page') - 1) * $pageSize, $pageSize);
// enrich
/** @var User $admin */
$admin = auth()->user();
$enrichment = new AccountEnrichment();
$enrichment->setUser($admin);
$enrichment->setConvertToNative($this->convertToNative);
$enrichment->setNative($this->nativeCurrency);
$accounts = $enrichment->enrich($accounts);
// make paginator: // make paginator:
$paginator = new LengthAwarePaginator($accounts, $count, $pageSize, $this->parameters->get('page')); $paginator = new LengthAwarePaginator($accounts, $count, $pageSize, $this->parameters->get('page'));
$paginator->setPath(route('api.v1.accounts.index').$this->buildParams()); $paginator->setPath(route('api.v1.accounts.index').$this->buildParams());
@@ -118,6 +128,16 @@ class ShowController extends Controller
$account->refresh(); $account->refresh();
$manager = $this->getManager(); $manager = $this->getManager();
// enrich
/** @var User $admin */
$admin = auth()->user();
$enrichment = new AccountEnrichment();
$enrichment->setUser($admin);
$enrichment->setConvertToNative($this->convertToNative);
$enrichment->setNative($this->nativeCurrency);
$account = $enrichment->enrichSingle($account);
/** @var AccountTransformer $transformer */ /** @var AccountTransformer $transformer */
$transformer = app(AccountTransformer::class); $transformer = app(AccountTransformer::class);
$transformer->setParameters($this->parameters); $transformer->setParameters($this->parameters);

View File

@@ -27,7 +27,9 @@ namespace FireflyIII\Api\V1\Controllers\Models\Account;
use FireflyIII\Api\V1\Controllers\Controller; use FireflyIII\Api\V1\Controllers\Controller;
use FireflyIII\Api\V1\Requests\Models\Account\StoreRequest; use FireflyIII\Api\V1\Requests\Models\Account\StoreRequest;
use FireflyIII\Repositories\Account\AccountRepositoryInterface; use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use FireflyIII\Support\JsonApi\Enrichments\AccountEnrichment;
use FireflyIII\Transformers\AccountTransformer; use FireflyIII\Transformers\AccountTransformer;
use FireflyIII\User;
use Illuminate\Http\JsonResponse; use Illuminate\Http\JsonResponse;
use League\Fractal\Resource\Item; use League\Fractal\Resource\Item;
@@ -69,6 +71,15 @@ class StoreController extends Controller
$account = $this->repository->store($data); $account = $this->repository->store($data);
$manager = $this->getManager(); $manager = $this->getManager();
// enrich
/** @var User $admin */
$admin = auth()->user();
$enrichment = new AccountEnrichment();
$enrichment->setUser($admin);
$enrichment->setConvertToNative($this->convertToNative);
$enrichment->setNative($this->nativeCurrency);
$account = $enrichment->enrichSingle($account);
/** @var AccountTransformer $transformer */ /** @var AccountTransformer $transformer */
$transformer = app(AccountTransformer::class); $transformer = app(AccountTransformer::class);
$transformer->setParameters($this->parameters); $transformer->setParameters($this->parameters);

View File

@@ -28,7 +28,9 @@ use FireflyIII\Api\V1\Controllers\Controller;
use FireflyIII\Api\V1\Requests\Models\Account\UpdateRequest; use FireflyIII\Api\V1\Requests\Models\Account\UpdateRequest;
use FireflyIII\Models\Account; use FireflyIII\Models\Account;
use FireflyIII\Repositories\Account\AccountRepositoryInterface; use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use FireflyIII\Support\JsonApi\Enrichments\AccountEnrichment;
use FireflyIII\Transformers\AccountTransformer; use FireflyIII\Transformers\AccountTransformer;
use FireflyIII\User;
use Illuminate\Http\JsonResponse; use Illuminate\Http\JsonResponse;
use League\Fractal\Resource\Item; use League\Fractal\Resource\Item;
@@ -73,6 +75,15 @@ class UpdateController extends Controller
$account->refresh(); $account->refresh();
app('preferences')->mark(); app('preferences')->mark();
// enrich
/** @var User $admin */
$admin = auth()->user();
$enrichment = new AccountEnrichment();
$enrichment->setUser($admin);
$enrichment->setConvertToNative($this->convertToNative);
$enrichment->setNative($this->nativeCurrency);
$account = $enrichment->enrichSingle($account);
/** @var AccountTransformer $transformer */ /** @var AccountTransformer $transformer */
$transformer = app(AccountTransformer::class); $transformer = app(AccountTransformer::class);
$transformer->setParameters($this->parameters); $transformer->setParameters($this->parameters);

View File

@@ -30,6 +30,7 @@ use FireflyIII\Helpers\Collector\GroupCollectorInterface;
use FireflyIII\Models\Bill; use FireflyIII\Models\Bill;
use FireflyIII\Repositories\Bill\BillRepositoryInterface; use FireflyIII\Repositories\Bill\BillRepositoryInterface;
use FireflyIII\Support\Http\Api\TransactionFilter; use FireflyIII\Support\Http\Api\TransactionFilter;
use FireflyIII\Support\JsonApi\Enrichments\TransactionGroupEnrichment;
use FireflyIII\Transformers\AttachmentTransformer; use FireflyIII\Transformers\AttachmentTransformer;
use FireflyIII\Transformers\RuleTransformer; use FireflyIII\Transformers\RuleTransformer;
use FireflyIII\Transformers\TransactionGroupTransformer; use FireflyIII\Transformers\TransactionGroupTransformer;
@@ -176,7 +177,11 @@ class ListController extends Controller
// get paginator. // get paginator.
$paginator = $collector->getPaginatedGroups(); $paginator = $collector->getPaginatedGroups();
$paginator->setPath(route('api.v1.bills.transactions', [$bill->id]).$this->buildParams()); $paginator->setPath(route('api.v1.bills.transactions', [$bill->id]).$this->buildParams());
$transactions = $paginator->getCollection();
// enrich
$enrichment = new TransactionGroupEnrichment();
$enrichment->setUser($admin);
$transactions = $enrichment->enrich($paginator->getCollection());
/** @var TransactionGroupTransformer $transformer */ /** @var TransactionGroupTransformer $transformer */
$transformer = app(TransactionGroupTransformer::class); $transformer = app(TransactionGroupTransformer::class);

View File

@@ -32,6 +32,7 @@ use FireflyIII\Models\Budget;
use FireflyIII\Repositories\Budget\BudgetLimitRepositoryInterface; use FireflyIII\Repositories\Budget\BudgetLimitRepositoryInterface;
use FireflyIII\Repositories\Budget\BudgetRepositoryInterface; use FireflyIII\Repositories\Budget\BudgetRepositoryInterface;
use FireflyIII\Support\Http\Api\TransactionFilter; use FireflyIII\Support\Http\Api\TransactionFilter;
use FireflyIII\Support\JsonApi\Enrichments\TransactionGroupEnrichment;
use FireflyIII\Transformers\AttachmentTransformer; use FireflyIII\Transformers\AttachmentTransformer;
use FireflyIII\Transformers\BudgetLimitTransformer; use FireflyIII\Transformers\BudgetLimitTransformer;
use FireflyIII\Transformers\TransactionGroupTransformer; use FireflyIII\Transformers\TransactionGroupTransformer;
@@ -172,7 +173,11 @@ class ListController extends Controller
$paginator = $collector->getPaginatedGroups(); $paginator = $collector->getPaginatedGroups();
$paginator->setPath(route('api.v1.budgets.transactions', [$budget->id]).$this->buildParams()); $paginator->setPath(route('api.v1.budgets.transactions', [$budget->id]).$this->buildParams());
$transactions = $paginator->getCollection();
// enrich
$enrichment = new TransactionGroupEnrichment();
$enrichment->setUser($admin);
$transactions = $enrichment->enrich($paginator->getCollection());
/** @var TransactionGroupTransformer $transformer */ /** @var TransactionGroupTransformer $transformer */
$transformer = app(TransactionGroupTransformer::class); $transformer = app(TransactionGroupTransformer::class);
@@ -232,7 +237,11 @@ class ListController extends Controller
$paginator = $collector->getPaginatedGroups(); $paginator = $collector->getPaginatedGroups();
$paginator->setPath(route('api.v1.budgets.without-budget').$this->buildParams()); $paginator->setPath(route('api.v1.budgets.without-budget').$this->buildParams());
$transactions = $paginator->getCollection();
// enrich
$enrichment = new TransactionGroupEnrichment();
$enrichment->setUser($admin);
$transactions = $enrichment->enrich($paginator->getCollection());
/** @var TransactionGroupTransformer $transformer */ /** @var TransactionGroupTransformer $transformer */
$transformer = app(TransactionGroupTransformer::class); $transformer = app(TransactionGroupTransformer::class);

View File

@@ -30,6 +30,7 @@ use FireflyIII\Helpers\Collector\GroupCollectorInterface;
use FireflyIII\Models\Budget; use FireflyIII\Models\Budget;
use FireflyIII\Models\BudgetLimit; use FireflyIII\Models\BudgetLimit;
use FireflyIII\Support\Http\Api\TransactionFilter; use FireflyIII\Support\Http\Api\TransactionFilter;
use FireflyIII\Support\JsonApi\Enrichments\TransactionGroupEnrichment;
use FireflyIII\Transformers\TransactionGroupTransformer; use FireflyIII\Transformers\TransactionGroupTransformer;
use FireflyIII\User; use FireflyIII\User;
use Illuminate\Http\JsonResponse; use Illuminate\Http\JsonResponse;
@@ -84,7 +85,11 @@ class ListController extends Controller
$collector->setTypes($types); $collector->setTypes($types);
$paginator = $collector->getPaginatedGroups(); $paginator = $collector->getPaginatedGroups();
$paginator->setPath(route('api.v1.budgets.limits.transactions', [$budget->id, $budgetLimit->id]).$this->buildParams()); $paginator->setPath(route('api.v1.budgets.limits.transactions', [$budget->id, $budgetLimit->id]).$this->buildParams());
$transactions = $paginator->getCollection();
// enrich
$enrichment = new TransactionGroupEnrichment();
$enrichment->setUser($admin);
$transactions = $enrichment->enrich($paginator->getCollection());
/** @var TransactionGroupTransformer $transformer */ /** @var TransactionGroupTransformer $transformer */
$transformer = app(TransactionGroupTransformer::class); $transformer = app(TransactionGroupTransformer::class);

View File

@@ -30,6 +30,7 @@ use FireflyIII\Helpers\Collector\GroupCollectorInterface;
use FireflyIII\Models\Category; use FireflyIII\Models\Category;
use FireflyIII\Repositories\Category\CategoryRepositoryInterface; use FireflyIII\Repositories\Category\CategoryRepositoryInterface;
use FireflyIII\Support\Http\Api\TransactionFilter; use FireflyIII\Support\Http\Api\TransactionFilter;
use FireflyIII\Support\JsonApi\Enrichments\TransactionGroupEnrichment;
use FireflyIII\Transformers\AttachmentTransformer; use FireflyIII\Transformers\AttachmentTransformer;
use FireflyIII\Transformers\TransactionGroupTransformer; use FireflyIII\Transformers\TransactionGroupTransformer;
use FireflyIII\User; use FireflyIII\User;
@@ -139,7 +140,11 @@ class ListController extends Controller
$paginator = $collector->getPaginatedGroups(); $paginator = $collector->getPaginatedGroups();
$paginator->setPath(route('api.v1.categories.transactions', [$category->id]).$this->buildParams()); $paginator->setPath(route('api.v1.categories.transactions', [$category->id]).$this->buildParams());
$transactions = $paginator->getCollection();
// enrich
$enrichment = new TransactionGroupEnrichment();
$enrichment->setUser($admin);
$transactions = $enrichment->enrich($paginator->getCollection());
/** @var TransactionGroupTransformer $transformer */ /** @var TransactionGroupTransformer $transformer */
$transformer = app(TransactionGroupTransformer::class); $transformer = app(TransactionGroupTransformer::class);

View File

@@ -28,9 +28,11 @@ use FireflyIII\Api\V1\Controllers\Controller;
use FireflyIII\Exceptions\FireflyException; use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Models\PiggyBank; use FireflyIII\Models\PiggyBank;
use FireflyIII\Repositories\PiggyBank\PiggyBankRepositoryInterface; use FireflyIII\Repositories\PiggyBank\PiggyBankRepositoryInterface;
use FireflyIII\Support\JsonApi\Enrichments\AccountEnrichment;
use FireflyIII\Transformers\AccountTransformer; use FireflyIII\Transformers\AccountTransformer;
use FireflyIII\Transformers\AttachmentTransformer; use FireflyIII\Transformers\AttachmentTransformer;
use FireflyIII\Transformers\PiggyBankEventTransformer; use FireflyIII\Transformers\PiggyBankEventTransformer;
use FireflyIII\User;
use Illuminate\Http\JsonResponse; use Illuminate\Http\JsonResponse;
use Illuminate\Pagination\LengthAwarePaginator; use Illuminate\Pagination\LengthAwarePaginator;
use League\Fractal\Pagination\IlluminatePaginatorAdapter; use League\Fractal\Pagination\IlluminatePaginatorAdapter;
@@ -75,17 +77,26 @@ class ListController extends Controller
$collection = $piggyBank->accounts; $collection = $piggyBank->accounts;
$count = $collection->count(); $count = $collection->count();
$events = $collection->slice(($this->parameters->get('page') - 1) * $pageSize, $pageSize); $accounts = $collection->slice(($this->parameters->get('page') - 1) * $pageSize, $pageSize);
// enrich
/** @var User $admin */
$admin = auth()->user();
$enrichment = new AccountEnrichment();
$enrichment->setUser($admin);
$enrichment->setConvertToNative($this->convertToNative);
$enrichment->setNative($this->nativeCurrency);
$accounts = $enrichment->enrich($accounts);
// make paginator: // make paginator:
$paginator = new LengthAwarePaginator($events, $count, $pageSize, $this->parameters->get('page')); $paginator = new LengthAwarePaginator($accounts, $count, $pageSize, $this->parameters->get('page'));
$paginator->setPath(route('api.v1.piggy-banks.accounts', [$piggyBank->id]).$this->buildParams()); $paginator->setPath(route('api.v1.piggy-banks.accounts', [$piggyBank->id]).$this->buildParams());
/** @var AccountTransformer $transformer */ /** @var AccountTransformer $transformer */
$transformer = app(AccountTransformer::class); $transformer = app(AccountTransformer::class);
$transformer->setParameters($this->parameters); $transformer->setParameters($this->parameters);
$resource = new FractalCollection($events, $transformer, 'accounts'); $resource = new FractalCollection($accounts, $transformer, 'accounts');
$resource->setPaginator(new IlluminatePaginatorAdapter($paginator)); $resource->setPaginator(new IlluminatePaginatorAdapter($paginator));
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', self::CONTENT_TYPE); return response()->json($manager->createData($resource)->toArray())->header('Content-Type', self::CONTENT_TYPE);

View File

@@ -30,6 +30,7 @@ use FireflyIII\Helpers\Collector\GroupCollectorInterface;
use FireflyIII\Models\Recurrence; use FireflyIII\Models\Recurrence;
use FireflyIII\Repositories\Recurring\RecurringRepositoryInterface; use FireflyIII\Repositories\Recurring\RecurringRepositoryInterface;
use FireflyIII\Support\Http\Api\TransactionFilter; use FireflyIII\Support\Http\Api\TransactionFilter;
use FireflyIII\Support\JsonApi\Enrichments\TransactionGroupEnrichment;
use FireflyIII\Transformers\TransactionGroupTransformer; use FireflyIII\Transformers\TransactionGroupTransformer;
use FireflyIII\User; use FireflyIII\User;
use Illuminate\Http\JsonResponse; use Illuminate\Http\JsonResponse;
@@ -110,7 +111,11 @@ class ListController extends Controller
$paginator = $collector->getPaginatedGroups(); $paginator = $collector->getPaginatedGroups();
$paginator->setPath(route('api.v1.transactions.index').$this->buildParams()); $paginator->setPath(route('api.v1.transactions.index').$this->buildParams());
$transactions = $paginator->getCollection();
// enrich
$enrichment = new TransactionGroupEnrichment();
$enrichment->setUser($admin);
$transactions = $enrichment->enrich($paginator->getCollection());
/** @var TransactionGroupTransformer $transformer */ /** @var TransactionGroupTransformer $transformer */
$transformer = app(TransactionGroupTransformer::class); $transformer = app(TransactionGroupTransformer::class);

View File

@@ -29,6 +29,7 @@ use FireflyIII\Api\V1\Requests\Models\Rule\TestRequest;
use FireflyIII\Api\V1\Requests\Models\Rule\TriggerRequest; use FireflyIII\Api\V1\Requests\Models\Rule\TriggerRequest;
use FireflyIII\Models\Rule; use FireflyIII\Models\Rule;
use FireflyIII\Repositories\Rule\RuleRepositoryInterface; use FireflyIII\Repositories\Rule\RuleRepositoryInterface;
use FireflyIII\Support\JsonApi\Enrichments\TransactionGroupEnrichment;
use FireflyIII\TransactionRules\Engine\RuleEngineInterface; use FireflyIII\TransactionRules\Engine\RuleEngineInterface;
use FireflyIII\Transformers\TransactionGroupTransformer; use FireflyIII\Transformers\TransactionGroupTransformer;
use FireflyIII\User; use FireflyIII\User;
@@ -94,6 +95,11 @@ class TriggerController extends Controller
$transactions = $ruleEngine->find(); $transactions = $ruleEngine->find();
$count = $transactions->count(); $count = $transactions->count();
// enrich
$enrichment = new TransactionGroupEnrichment();
$enrichment->setUser($rule->user);
$transactions = $enrichment->enrich($transactions);
$paginator = new LengthAwarePaginator($transactions, $count, 31337, $this->parameters->get('page')); $paginator = new LengthAwarePaginator($transactions, $count, 31337, $this->parameters->get('page'));
$paginator->setPath(route('api.v1.rules.test', [$rule->id]).$this->buildParams()); $paginator->setPath(route('api.v1.rules.test', [$rule->id]).$this->buildParams());

View File

@@ -30,6 +30,7 @@ use FireflyIII\Api\V1\Requests\Models\RuleGroup\TriggerRequest;
use FireflyIII\Exceptions\FireflyException; use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Models\RuleGroup; use FireflyIII\Models\RuleGroup;
use FireflyIII\Repositories\RuleGroup\RuleGroupRepositoryInterface; use FireflyIII\Repositories\RuleGroup\RuleGroupRepositoryInterface;
use FireflyIII\Support\JsonApi\Enrichments\TransactionGroupEnrichment;
use FireflyIII\TransactionRules\Engine\RuleEngineInterface; use FireflyIII\TransactionRules\Engine\RuleEngineInterface;
use FireflyIII\Transformers\TransactionGroupTransformer; use FireflyIII\Transformers\TransactionGroupTransformer;
use FireflyIII\User; use FireflyIII\User;
@@ -100,6 +101,11 @@ class TriggerController extends Controller
$transactions = $ruleEngine->find(); $transactions = $ruleEngine->find();
$count = $transactions->count(); $count = $transactions->count();
// enrich
$enrichment = new TransactionGroupEnrichment();
$enrichment->setUser($group->user);
$transactions = $enrichment->enrich($transactions);
$paginator = new LengthAwarePaginator($transactions, $count, 31337, $this->parameters->get('page')); $paginator = new LengthAwarePaginator($transactions, $count, 31337, $this->parameters->get('page'));
$paginator->setPath(route('api.v1.rule-groups.test', [$group->id]).$this->buildParams()); $paginator->setPath(route('api.v1.rule-groups.test', [$group->id]).$this->buildParams());

View File

@@ -30,6 +30,7 @@ use FireflyIII\Helpers\Collector\GroupCollectorInterface;
use FireflyIII\Models\Tag; use FireflyIII\Models\Tag;
use FireflyIII\Repositories\Tag\TagRepositoryInterface; use FireflyIII\Repositories\Tag\TagRepositoryInterface;
use FireflyIII\Support\Http\Api\TransactionFilter; use FireflyIII\Support\Http\Api\TransactionFilter;
use FireflyIII\Support\JsonApi\Enrichments\TransactionGroupEnrichment;
use FireflyIII\Transformers\AttachmentTransformer; use FireflyIII\Transformers\AttachmentTransformer;
use FireflyIII\Transformers\TransactionGroupTransformer; use FireflyIII\Transformers\TransactionGroupTransformer;
use FireflyIII\User; use FireflyIII\User;
@@ -141,7 +142,12 @@ class ListController extends Controller
} }
$paginator = $collector->getPaginatedGroups(); $paginator = $collector->getPaginatedGroups();
$paginator->setPath(route('api.v1.tags.transactions', [$tag->id]).$this->buildParams()); $paginator->setPath(route('api.v1.tags.transactions', [$tag->id]).$this->buildParams());
$transactions = $paginator->getCollection();
// enrich
$enrichment = new TransactionGroupEnrichment();
$enrichment->setUser($admin);
$transactions = $enrichment->enrich($paginator->getCollection());
/** @var TransactionGroupTransformer $transformer */ /** @var TransactionGroupTransformer $transformer */
$transformer = app(TransactionGroupTransformer::class); $transformer = app(TransactionGroupTransformer::class);

View File

@@ -30,6 +30,7 @@ use FireflyIII\Helpers\Collector\GroupCollectorInterface;
use FireflyIII\Models\TransactionGroup; use FireflyIII\Models\TransactionGroup;
use FireflyIII\Models\TransactionJournal; use FireflyIII\Models\TransactionJournal;
use FireflyIII\Support\Http\Api\TransactionFilter; use FireflyIII\Support\Http\Api\TransactionFilter;
use FireflyIII\Support\JsonApi\Enrichments\TransactionGroupEnrichment;
use FireflyIII\Transformers\TransactionGroupTransformer; use FireflyIII\Transformers\TransactionGroupTransformer;
use FireflyIII\User; use FireflyIII\User;
use Illuminate\Http\JsonResponse; use Illuminate\Http\JsonResponse;
@@ -85,7 +86,11 @@ class ShowController extends Controller
} }
$paginator = $collector->getPaginatedGroups(); $paginator = $collector->getPaginatedGroups();
$paginator->setPath(route('api.v1.transactions.index').$this->buildParams()); $paginator->setPath(route('api.v1.transactions.index').$this->buildParams());
$transactions = $paginator->getCollection();
// enrich
$enrichment = new TransactionGroupEnrichment();
$enrichment->setUser($admin);
$transactions = $enrichment->enrich($paginator->getCollection());
/** @var TransactionGroupTransformer $transformer */ /** @var TransactionGroupTransformer $transformer */
$transformer = app(TransactionGroupTransformer::class); $transformer = app(TransactionGroupTransformer::class);
@@ -137,6 +142,11 @@ class ShowController extends Controller
throw new NotFoundHttpException(); throw new NotFoundHttpException();
} }
// enrich
$enrichment = new TransactionGroupEnrichment();
$enrichment->setUser($admin);
$selectedGroup = $enrichment->enrichSingle($selectedGroup);
/** @var TransactionGroupTransformer $transformer */ /** @var TransactionGroupTransformer $transformer */
$transformer = app(TransactionGroupTransformer::class); $transformer = app(TransactionGroupTransformer::class);
$transformer->setParameters($this->parameters); $transformer->setParameters($this->parameters);

View File

@@ -34,6 +34,7 @@ use FireflyIII\Helpers\Collector\GroupCollectorInterface;
use FireflyIII\Repositories\TransactionGroup\TransactionGroupRepositoryInterface; use FireflyIII\Repositories\TransactionGroup\TransactionGroupRepositoryInterface;
use FireflyIII\Rules\IsDuplicateTransaction; use FireflyIII\Rules\IsDuplicateTransaction;
use FireflyIII\Support\Http\Api\TransactionFilter; use FireflyIII\Support\Http\Api\TransactionFilter;
use FireflyIII\Support\JsonApi\Enrichments\TransactionGroupEnrichment;
use FireflyIII\Transformers\TransactionGroupTransformer; use FireflyIII\Transformers\TransactionGroupTransformer;
use FireflyIII\User; use FireflyIII\User;
use Illuminate\Http\JsonResponse; use Illuminate\Http\JsonResponse;
@@ -133,6 +134,11 @@ class StoreController extends Controller
throw new FireflyException('200032: Cannot find transaction. Possibly, a rule deleted this transaction after its creation.'); throw new FireflyException('200032: Cannot find transaction. Possibly, a rule deleted this transaction after its creation.');
} }
// enrich
$enrichment = new TransactionGroupEnrichment();
$enrichment->setUser($admin);
$selectedGroup = $enrichment->enrichSingle($selectedGroup);
/** @var TransactionGroupTransformer $transformer */ /** @var TransactionGroupTransformer $transformer */
$transformer = app(TransactionGroupTransformer::class); $transformer = app(TransactionGroupTransformer::class);
$transformer->setParameters($this->parameters); $transformer->setParameters($this->parameters);

View File

@@ -30,6 +30,7 @@ use FireflyIII\Events\UpdatedTransactionGroup;
use FireflyIII\Helpers\Collector\GroupCollectorInterface; use FireflyIII\Helpers\Collector\GroupCollectorInterface;
use FireflyIII\Models\TransactionGroup; use FireflyIII\Models\TransactionGroup;
use FireflyIII\Repositories\TransactionGroup\TransactionGroupRepositoryInterface; use FireflyIII\Repositories\TransactionGroup\TransactionGroupRepositoryInterface;
use FireflyIII\Support\JsonApi\Enrichments\TransactionGroupEnrichment;
use FireflyIII\Transformers\TransactionGroupTransformer; use FireflyIII\Transformers\TransactionGroupTransformer;
use FireflyIII\User; use FireflyIII\User;
use Illuminate\Http\JsonResponse; use Illuminate\Http\JsonResponse;
@@ -99,6 +100,11 @@ class UpdateController extends Controller
throw new NotFoundHttpException(); throw new NotFoundHttpException();
} }
// enrich
$enrichment = new TransactionGroupEnrichment();
$enrichment->setUser($admin);
$selectedGroup = $enrichment->enrichSingle($selectedGroup);
/** @var TransactionGroupTransformer $transformer */ /** @var TransactionGroupTransformer $transformer */
$transformer = app(TransactionGroupTransformer::class); $transformer = app(TransactionGroupTransformer::class);
$transformer->setParameters($this->parameters); $transformer->setParameters($this->parameters);

View File

@@ -42,6 +42,8 @@ use FireflyIII\Repositories\Recurring\RecurringRepositoryInterface;
use FireflyIII\Repositories\Rule\RuleRepositoryInterface; use FireflyIII\Repositories\Rule\RuleRepositoryInterface;
use FireflyIII\Support\Http\Api\AccountFilter; use FireflyIII\Support\Http\Api\AccountFilter;
use FireflyIII\Support\Http\Api\TransactionFilter; use FireflyIII\Support\Http\Api\TransactionFilter;
use FireflyIII\Support\JsonApi\Enrichments\AccountEnrichment;
use FireflyIII\Support\JsonApi\Enrichments\TransactionGroupEnrichment;
use FireflyIII\Transformers\AccountTransformer; use FireflyIII\Transformers\AccountTransformer;
use FireflyIII\Transformers\AvailableBudgetTransformer; use FireflyIII\Transformers\AvailableBudgetTransformer;
use FireflyIII\Transformers\BillTransformer; use FireflyIII\Transformers\BillTransformer;
@@ -100,6 +102,15 @@ class ListController extends Controller
$count = $collection->count(); $count = $collection->count();
$accounts = $collection->slice(($this->parameters->get('page') - 1) * $pageSize, $pageSize); $accounts = $collection->slice(($this->parameters->get('page') - 1) * $pageSize, $pageSize);
// enrich
/** @var User $admin */
$admin = auth()->user();
$enrichment = new AccountEnrichment();
$enrichment->setUser($admin);
$enrichment->setConvertToNative($this->convertToNative);
$enrichment->setNative($this->nativeCurrency);
$accounts = $enrichment->enrich($accounts);
// make paginator: // make paginator:
$paginator = new LengthAwarePaginator($accounts, $count, $pageSize, $this->parameters->get('page')); $paginator = new LengthAwarePaginator($accounts, $count, $pageSize, $this->parameters->get('page'));
$paginator->setPath(route('api.v1.currencies.accounts', [$currency->code]).$this->buildParams()); $paginator->setPath(route('api.v1.currencies.accounts', [$currency->code]).$this->buildParams());
@@ -360,7 +371,11 @@ class ListController extends Controller
} }
$paginator = $collector->getPaginatedGroups(); $paginator = $collector->getPaginatedGroups();
$paginator->setPath(route('api.v1.currencies.transactions', [$currency->code]).$this->buildParams()); $paginator->setPath(route('api.v1.currencies.transactions', [$currency->code]).$this->buildParams());
$transactions = $paginator->getCollection();
// enrich
$enrichment = new TransactionGroupEnrichment();
$enrichment->setUser($admin);
$transactions = $enrichment->enrich($paginator->getCollection());
/** @var TransactionGroupTransformer $transformer */ /** @var TransactionGroupTransformer $transformer */
$transformer = app(TransactionGroupTransformer::class); $transformer = app(TransactionGroupTransformer::class);

View File

@@ -30,6 +30,7 @@ use FireflyIII\Helpers\Collector\GroupCollectorInterface;
use FireflyIII\Models\LinkType; use FireflyIII\Models\LinkType;
use FireflyIII\Repositories\LinkType\LinkTypeRepositoryInterface; use FireflyIII\Repositories\LinkType\LinkTypeRepositoryInterface;
use FireflyIII\Support\Http\Api\TransactionFilter; use FireflyIII\Support\Http\Api\TransactionFilter;
use FireflyIII\Support\JsonApi\Enrichments\TransactionGroupEnrichment;
use FireflyIII\Transformers\TransactionGroupTransformer; use FireflyIII\Transformers\TransactionGroupTransformer;
use FireflyIII\User; use FireflyIII\User;
use Illuminate\Http\JsonResponse; use Illuminate\Http\JsonResponse;
@@ -109,7 +110,11 @@ class ListController extends Controller
} }
$paginator = $collector->getPaginatedGroups(); $paginator = $collector->getPaginatedGroups();
$paginator->setPath(route('api.v1.transactions.index').$this->buildParams()); $paginator->setPath(route('api.v1.transactions.index').$this->buildParams());
$transactions = $paginator->getCollection();
// enrich
$enrichment = new TransactionGroupEnrichment();
$enrichment->setUser($admin);
$transactions = $enrichment->enrich($paginator->getCollection());
/** @var TransactionGroupTransformer $transformer */ /** @var TransactionGroupTransformer $transformer */
$transformer = app(TransactionGroupTransformer::class); $transformer = app(TransactionGroupTransformer::class);

View File

@@ -26,8 +26,10 @@ namespace FireflyIII\Api\V1\Controllers\Search;
use FireflyIII\Api\V1\Controllers\Controller; use FireflyIII\Api\V1\Controllers\Controller;
use FireflyIII\Support\Http\Api\AccountFilter; use FireflyIII\Support\Http\Api\AccountFilter;
use FireflyIII\Support\JsonApi\Enrichments\AccountEnrichment;
use FireflyIII\Support\Search\AccountSearch; use FireflyIII\Support\Search\AccountSearch;
use FireflyIII\Transformers\AccountTransformer; use FireflyIII\Transformers\AccountTransformer;
use FireflyIII\User;
use Illuminate\Http\JsonResponse; use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use Illuminate\Http\Response; use Illuminate\Http\Response;
@@ -81,6 +83,15 @@ class AccountController extends Controller
$accounts = $search->search(); $accounts = $search->search();
// enrich
/** @var User $admin */
$admin = auth()->user();
$enrichment = new AccountEnrichment();
$enrichment->setUser($admin);
$enrichment->setConvertToNative($this->convertToNative);
$enrichment->setNative($this->nativeCurrency);
$accounts = $enrichment->enrich($accounts);
/** @var AccountTransformer $transformer */ /** @var AccountTransformer $transformer */
$transformer = app(AccountTransformer::class); $transformer = app(AccountTransformer::class);
$transformer->setParameters($this->parameters); $transformer->setParameters($this->parameters);

View File

@@ -26,6 +26,7 @@ namespace FireflyIII\Api\V1\Controllers\Search;
use FireflyIII\Api\V1\Controllers\Controller; use FireflyIII\Api\V1\Controllers\Controller;
use FireflyIII\Exceptions\FireflyException; use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Support\JsonApi\Enrichments\TransactionGroupEnrichment;
use FireflyIII\Support\Search\SearchInterface; use FireflyIII\Support\Search\SearchInterface;
use FireflyIII\Transformers\TransactionGroupTransformer; use FireflyIII\Transformers\TransactionGroupTransformer;
use Illuminate\Http\JsonResponse; use Illuminate\Http\JsonResponse;
@@ -57,7 +58,11 @@ class TransactionController extends Controller
$parameters = ['search' => $fullQuery]; $parameters = ['search' => $fullQuery];
$url = route('api.v1.search.transactions').'?'.http_build_query($parameters); $url = route('api.v1.search.transactions').'?'.http_build_query($parameters);
$groups->setPath($url); $groups->setPath($url);
$transactions = $groups->getCollection();
// enrich
$enrichment = new TransactionGroupEnrichment();
$enrichment->setUser(auth()->user());
$transactions = $enrichment->enrich($groups->getCollection());
/** @var TransactionGroupTransformer $transformer */ /** @var TransactionGroupTransformer $transformer */
$transformer = app(TransactionGroupTransformer::class); $transformer = app(TransactionGroupTransformer::class);

View File

@@ -102,7 +102,7 @@ class BasicController extends Controller
$balanceData = $this->getBalanceInformation($start, $end); $balanceData = $this->getBalanceInformation($start, $end);
$billData = $this->getBillInformation($start, $end); $billData = $this->getBillInformation($start, $end);
$spentData = $this->getLeftToSpendInfo($start, $end); $spentData = $this->getLeftToSpendInfo($start, $end);
$netWorthData = $this->getNetWorthInfo($start, $end); $netWorthData = $this->getNetWorthInfo($end);
// $balanceData = []; // $balanceData = [];
// $billData = []; // $billData = [];
// $spentData = []; // $spentData = [];
@@ -319,18 +319,13 @@ class BasicController extends Controller
return $return; return $return;
} }
private function getNetWorthInfo(Carbon $start, Carbon $end): array private function getNetWorthInfo(Carbon $end): array
{ {
Log::debug('getNetWorthInfo'); $end->endOfDay();
/** @var User $user */ /** @var User $user */
$user = auth()->user(); $user = auth()->user();
$date = now(config('app.timezone')); Log::debug(sprintf('getNetWorthInfo up until "%s".', $end->format('Y-m-d H:i:s')));
// start and end in the future? use $end
if ($this->notInDateRange($date, $start, $end)) {
/** @var Carbon $date */
$date = session('end', today(config('app.timezone'))->endOfMonth());
}
/** @var NetWorthInterface $netWorthHelper */ /** @var NetWorthInterface $netWorthHelper */
$netWorthHelper = app(NetWorthInterface::class); $netWorthHelper = app(NetWorthInterface::class);
@@ -346,7 +341,7 @@ class BasicController extends Controller
} }
); );
$netWorthSet = $netWorthHelper->byAccounts($filtered, $date); $netWorthSet = $netWorthHelper->byAccounts($filtered, $end);
$return = []; $return = [];
foreach ($netWorthSet as $key => $data) { foreach ($netWorthSet as $key => $data) {
if ('native' === $key) { if ('native' === $key) {
@@ -370,6 +365,22 @@ class BasicController extends Controller
'sub_title' => '', 'sub_title' => '',
]; ];
} }
if (0 === count($return)) {
$return[] = [
'key' => sprintf('net-worth-in-%s', $this->nativeCurrency->code),
'title' => trans('firefly.box_net_worth_in_currency', ['currency' => $this->nativeCurrency->symbol]),
'monetary_value' => '0',
'currency_id' => (string) $this->nativeCurrency->id,
'currency_code' => $this->nativeCurrency->code,
'currency_symbol' => $this->nativeCurrency->symbol,
'currency_decimal_places' => $this->nativeCurrency->decimal_places,
'value_parsed' => app('amount')->formatFlat($this->nativeCurrency->symbol, $this->nativeCurrency->decimal_places, '0', false),
'local_icon' => 'line-chart',
'sub_title' => '',
];
}
Log::debug('End of getNetWorthInfo'); Log::debug('End of getNetWorthInfo');
return $return; return $return;

View File

@@ -27,6 +27,7 @@ namespace FireflyIII\Api\V1\Controllers\System;
use FireflyIII\Api\V1\Controllers\Controller; use FireflyIII\Api\V1\Controllers\Controller;
use FireflyIII\Transformers\UserTransformer; use FireflyIII\Transformers\UserTransformer;
use Illuminate\Http\JsonResponse; use Illuminate\Http\JsonResponse;
use Illuminate\Support\Facades\DB;
use League\Fractal\Resource\Item; use League\Fractal\Resource\Item;
/** /**
@@ -48,7 +49,7 @@ class AboutController extends Controller
$replace = ['\~', '# ']; $replace = ['\~', '# '];
$phpVersion = str_replace($search, $replace, PHP_VERSION); $phpVersion = str_replace($search, $replace, PHP_VERSION);
$phpOs = str_replace($search, $replace, PHP_OS); $phpOs = str_replace($search, $replace, PHP_OS);
$currentDriver = \DB::getDriverName(); $currentDriver = DB::getDriverName();
$data $data
= [ = [
'version' => config('firefly.version'), 'version' => config('firefly.version'),

View File

@@ -65,7 +65,7 @@ class TestRequest extends FormRequest
private function getAccounts(): array private function getAccounts(): array
{ {
return $this->get('accounts'); return $this->get('accounts') ?? [];
} }
public function rules(): array public function rules(): array

View File

@@ -59,7 +59,7 @@ class TestRequest extends FormRequest
private function getAccounts(): array private function getAccounts(): array
{ {
return $this->get('accounts'); return $this->get('accounts') ?? [];
} }
public function rules(): array public function rules(): array

View File

@@ -30,6 +30,7 @@ use FireflyIII\Handlers\Events\UpdatedGroupEventHandler;
use FireflyIII\Models\TransactionGroup; use FireflyIII\Models\TransactionGroup;
use FireflyIII\Models\TransactionJournal; use FireflyIII\Models\TransactionJournal;
use Illuminate\Console\Command; use Illuminate\Console\Command;
use Illuminate\Support\Facades\DB;
class CorrectsGroupAccounts extends Command class CorrectsGroupAccounts extends Command
{ {
@@ -45,7 +46,7 @@ class CorrectsGroupAccounts extends Command
{ {
$groups = []; $groups = [];
$res = TransactionJournal::groupBy('transaction_group_id') $res = TransactionJournal::groupBy('transaction_group_id')
->get(['transaction_group_id', \DB::raw('COUNT(transaction_group_id) as the_count')])// @phpstan-ignore-line ->get(['transaction_group_id', DB::raw('COUNT(transaction_group_id) as the_count')])// @phpstan-ignore-line
; ;
/** @var TransactionJournal $journal */ /** @var TransactionJournal $journal */

View File

@@ -33,6 +33,7 @@ use FireflyIII\Models\Budget;
use FireflyIII\Models\Category; use FireflyIII\Models\Category;
use FireflyIII\Models\CurrencyExchangeRate; use FireflyIII\Models\CurrencyExchangeRate;
use FireflyIII\Models\ObjectGroup; use FireflyIII\Models\ObjectGroup;
use FireflyIII\Models\Preference;
use FireflyIII\Models\Recurrence; use FireflyIII\Models\Recurrence;
use FireflyIII\Models\Rule; use FireflyIII\Models\Rule;
use FireflyIII\Models\RuleGroup; use FireflyIII\Models\RuleGroup;
@@ -89,6 +90,7 @@ class CorrectsGroupInformation extends Command
Category::class, Category::class,
ObjectGroup::class, ObjectGroup::class,
CurrencyExchangeRate::class, CurrencyExchangeRate::class,
Preference::class,
Recurrence::class, Recurrence::class,
RuleGroup::class, RuleGroup::class,
Rule::class, Rule::class,

View File

@@ -30,6 +30,7 @@ use FireflyIII\Models\Transaction;
use FireflyIII\Models\TransactionJournal; use FireflyIII\Models\TransactionJournal;
use FireflyIII\Support\Models\AccountBalanceCalculator; use FireflyIII\Support\Models\AccountBalanceCalculator;
use Illuminate\Console\Command; use Illuminate\Console\Command;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Log;
class CorrectsUnevenAmount extends Command class CorrectsUnevenAmount extends Command
@@ -118,10 +119,10 @@ class CorrectsUnevenAmount extends Command
private function fixUnevenAmounts(): void private function fixUnevenAmounts(): void
{ {
$journals = \DB::table('transactions') $journals = DB::table('transactions')
->groupBy('transaction_journal_id') ->groupBy('transaction_journal_id')
->whereNull('deleted_at') ->whereNull('deleted_at')
->get(['transaction_journal_id', \DB::raw('SUM(amount) AS the_sum')]) // @phpstan-ignore-line ->get(['transaction_journal_id', DB::raw('SUM(amount) AS the_sum')]) // @phpstan-ignore-line
; ;
/** @var \stdClass $entry */ /** @var \stdClass $entry */
@@ -262,7 +263,7 @@ class CorrectsUnevenAmount extends Command
private function matchCurrencies(): void private function matchCurrencies(): void
{ {
$journals = TransactionJournal::leftJoin('transactions', 'transaction_journals.id', 'transactions.transaction_journal_id') $journals = TransactionJournal::leftJoin('transactions', 'transaction_journals.id', 'transactions.transaction_journal_id')
->where('transactions.transaction_currency_id', '!=', \DB::raw('transaction_journals.transaction_currency_id')) ->where('transactions.transaction_currency_id', '!=', DB::raw('transaction_journals.transaction_currency_id'))
->get(['transaction_journals.*']) ->get(['transaction_journals.*'])
; ;

View File

@@ -29,6 +29,7 @@ use FireflyIII\Models\Transaction;
use FireflyIII\Models\TransactionJournal; use FireflyIII\Models\TransactionJournal;
use Illuminate\Console\Command; use Illuminate\Console\Command;
use Illuminate\Database\QueryException; use Illuminate\Database\QueryException;
use Illuminate\Support\Facades\DB;
class RemovesEmptyJournals extends Command class RemovesEmptyJournals extends Command
{ {
@@ -56,7 +57,7 @@ class RemovesEmptyJournals extends Command
{ {
$set = Transaction::whereNull('deleted_at') $set = Transaction::whereNull('deleted_at')
->groupBy('transactions.transaction_journal_id') ->groupBy('transactions.transaction_journal_id')
->get([\DB::raw('COUNT(transactions.transaction_journal_id) as the_count'), 'transaction_journal_id']) // @phpstan-ignore-line ->get([DB::raw('COUNT(transactions.transaction_journal_id) as the_count'), 'transaction_journal_id']) // @phpstan-ignore-line
; ;
$total = 0; $total = 0;

View File

@@ -106,7 +106,7 @@ class ExportsData extends Command
$exporter->setExportTags($options['export']['tags']); $exporter->setExportTags($options['export']['tags']);
$exporter->setExportRecurring($options['export']['recurring']); $exporter->setExportRecurring($options['export']['recurring']);
$exporter->setExportRules($options['export']['rules']); $exporter->setExportRules($options['export']['rules']);
$exporter->setExportBills($options['export']['subscriptions']); $exporter->setExportBills($options['export']['bills']);
$exporter->setExportPiggies($options['export']['piggies']); $exporter->setExportPiggies($options['export']['piggies']);
$data = $exporter->export(); $data = $exporter->export();
if (0 === count($data)) { if (0 === count($data)) {

View File

@@ -31,6 +31,7 @@ use FireflyIII\Support\Cronjobs\AutoBudgetCronjob;
use FireflyIII\Support\Cronjobs\BillWarningCronjob; use FireflyIII\Support\Cronjobs\BillWarningCronjob;
use FireflyIII\Support\Cronjobs\ExchangeRatesCronjob; use FireflyIII\Support\Cronjobs\ExchangeRatesCronjob;
use FireflyIII\Support\Cronjobs\RecurringCronjob; use FireflyIII\Support\Cronjobs\RecurringCronjob;
use FireflyIII\Support\Cronjobs\UpdateCheckCronjob;
use Illuminate\Console\Command; use Illuminate\Console\Command;
use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Log;
@@ -43,6 +44,7 @@ class Cron extends Command
protected $signature = 'firefly-iii:cron protected $signature = 'firefly-iii:cron
{--F|force : Force the cron job(s) to execute.} {--F|force : Force the cron job(s) to execute.}
{--date= : Set the date in YYYY-MM-DD to make Firefly III think that\'s the current date.} {--date= : Set the date in YYYY-MM-DD to make Firefly III think that\'s the current date.}
{--check-version : Check if there is a new Firefly III version. Other tasks will be skipped unless also requested.}
{--download-cer : Download exchange rates. Other tasks will be skipped unless also requested.} {--download-cer : Download exchange rates. Other tasks will be skipped unless also requested.}
{--create-recurring : Create recurring transactions. Other tasks will be skipped unless also requested.} {--create-recurring : Create recurring transactions. Other tasks will be skipped unless also requested.}
{--create-auto-budgets : Create auto budgets. Other tasks will be skipped unless also requested.} {--create-auto-budgets : Create auto budgets. Other tasks will be skipped unless also requested.}
@@ -51,7 +53,11 @@ class Cron extends Command
public function handle(): int public function handle(): int
{ {
$doAll = !$this->option('download-cer') && !$this->option('create-recurring') && !$this->option('create-auto-budgets') && !$this->option('send-bill-warnings'); $doAll = !$this->option('download-cer')
&& !$this->option('create-recurring')
&& !$this->option('create-auto-budgets')
&& !$this->option('send-bill-warnings')
&& !$this->option('check-version');
$date = null; $date = null;
try { try {
@@ -72,6 +78,17 @@ class Cron extends Command
} }
} }
// check for new version
if ($doAll || $this->option('check-version')) {
try {
$this->checkForUpdates($force);
} catch (FireflyException $e) {
app('log')->error($e->getMessage());
app('log')->error($e->getTraceAsString());
$this->friendlyError($e->getMessage());
}
}
// Fire recurring transaction cron job. // Fire recurring transaction cron job.
if ($doAll || $this->option('create-recurring')) { if ($doAll || $this->option('create-recurring')) {
try { try {
@@ -204,4 +221,21 @@ class Cron extends Command
$this->friendlyPositive(sprintf('"Send bill warnings" cron ran with success: %s', $autoBudget->message)); $this->friendlyPositive(sprintf('"Send bill warnings" cron ran with success: %s', $autoBudget->message));
} }
} }
private function checkForUpdates(bool $force): void
{
$updateCheck = new UpdateCheckCronjob();
$updateCheck->setForce($force);
$updateCheck->fire();
if ($updateCheck->jobErrored) {
$this->friendlyError(sprintf('Error in "update check" cron: %s', $updateCheck->message));
}
if ($updateCheck->jobFired) {
$this->friendlyInfo(sprintf('"Update check" cron fired: %s', $updateCheck->message));
}
if ($updateCheck->jobSucceeded) {
$this->friendlyPositive(sprintf('"Update check" cron ran with success: %s', $updateCheck->message));
}
}
} }

View File

@@ -29,6 +29,7 @@ use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Models\Preference; use FireflyIII\Models\Preference;
use Illuminate\Console\Command; use Illuminate\Console\Command;
use Illuminate\Contracts\Encryption\DecryptException; use Illuminate\Contracts\Encryption\DecryptException;
use Illuminate\Support\Facades\DB;
class RemovesDatabaseDecryption extends Command class RemovesDatabaseDecryption extends Command
{ {
@@ -101,7 +102,7 @@ class RemovesDatabaseDecryption extends Command
private function decryptField(string $table, string $field): void private function decryptField(string $table, string $field): void
{ {
$rows = \DB::table($table)->get(['id', $field]); $rows = DB::table($table)->get(['id', $field]);
/** @var \stdClass $row */ /** @var \stdClass $row */
foreach ($rows as $row) { foreach ($rows as $row) {
@@ -135,7 +136,7 @@ class RemovesDatabaseDecryption extends Command
} }
if ($value !== $original) { if ($value !== $original) {
\DB::table($table)->where('id', $id)->update([$field => $value]); DB::table($table)->where('id', $id)->update([$field => $value]);
} }
} }

View File

@@ -26,6 +26,7 @@ namespace FireflyIII\Console\Commands\Upgrade;
use FireflyIII\Console\Commands\ShowsFriendlyMessages; use FireflyIII\Console\Commands\ShowsFriendlyMessages;
use Illuminate\Console\Command; use Illuminate\Console\Command;
use Illuminate\Support\Facades\DB;
class RepairsPostgresSequences extends Command class RepairsPostgresSequences extends Command
{ {
@@ -40,7 +41,7 @@ class RepairsPostgresSequences extends Command
*/ */
public function handle(): int public function handle(): int
{ {
if ('pgsql' !== \DB::connection()->getName()) { if ('pgsql' !== DB::connection()->getName()) {
return 0; return 0;
} }
$this->friendlyLine('Going to verify PostgreSQL table sequences.'); $this->friendlyLine('Going to verify PostgreSQL table sequences.');
@@ -49,8 +50,8 @@ class RepairsPostgresSequences extends Command
foreach ($tablesToCheck as $tableToCheck) { foreach ($tablesToCheck as $tableToCheck) {
$this->friendlyLine(sprintf('Checking the next id sequence for table "%s".', $tableToCheck)); $this->friendlyLine(sprintf('Checking the next id sequence for table "%s".', $tableToCheck));
$highestId = \DB::table($tableToCheck)->select(\DB::raw('MAX(id)'))->first(); $highestId = DB::table($tableToCheck)->select(DB::raw('MAX(id)'))->first();
$nextId = \DB::table($tableToCheck)->select(\DB::raw(sprintf('nextval(\'%s_id_seq\')', $tableToCheck)))->first(); $nextId = DB::table($tableToCheck)->select(DB::raw(sprintf('nextval(\'%s_id_seq\')', $tableToCheck)))->first();
if (null === $nextId) { if (null === $nextId) {
$this->friendlyInfo(sprintf('nextval is NULL for table "%s", go to next table.', $tableToCheck)); $this->friendlyInfo(sprintf('nextval is NULL for table "%s", go to next table.', $tableToCheck));
@@ -58,9 +59,9 @@ class RepairsPostgresSequences extends Command
} }
if ($nextId->nextval < $highestId->max) { // @phpstan-ignore-line if ($nextId->nextval < $highestId->max) { // @phpstan-ignore-line
\DB::select(sprintf('SELECT setval(\'%s_id_seq\', %d)', $tableToCheck, $highestId->max)); DB::select(sprintf('SELECT setval(\'%s_id_seq\', %d)', $tableToCheck, $highestId->max));
$highestId = \DB::table($tableToCheck)->select(\DB::raw('MAX(id)'))->first(); $highestId = DB::table($tableToCheck)->select(DB::raw('MAX(id)'))->first();
$nextId = \DB::table($tableToCheck)->select(\DB::raw(sprintf('nextval(\'%s_id_seq\')', $tableToCheck)))->first(); $nextId = DB::table($tableToCheck)->select(DB::raw(sprintf('nextval(\'%s_id_seq\')', $tableToCheck)))->first();
if ($nextId->nextval > $highestId->max) { // @phpstan-ignore-line if ($nextId->nextval > $highestId->max) { // @phpstan-ignore-line
$this->friendlyInfo(sprintf('Table "%s" autoincrement corrected.', $tableToCheck)); $this->friendlyInfo(sprintf('Table "%s" autoincrement corrected.', $tableToCheck));
} }

View File

@@ -31,6 +31,7 @@ use FireflyIII\Models\Transaction;
use FireflyIII\Models\TransactionJournal; use FireflyIII\Models\TransactionJournal;
use Illuminate\Console\Command; use Illuminate\Console\Command;
use Illuminate\Support\Collection; use Illuminate\Support\Collection;
use Illuminate\Support\Facades\DB;
class UpgradesJournalMetaData extends Command class UpgradesJournalMetaData extends Command
{ {
@@ -86,8 +87,8 @@ class UpgradesJournalMetaData extends Command
$this->migrateCategories(); $this->migrateCategories();
// empty tables // empty tables
\DB::table('budget_transaction')->delete(); DB::table('budget_transaction')->delete();
\DB::table('category_transaction')->delete(); DB::table('category_transaction')->delete();
} }
private function migrateBudgets(): void private function migrateBudgets(): void
@@ -108,12 +109,12 @@ class UpgradesJournalMetaData extends Command
private function getIdsForBudgets(): array private function getIdsForBudgets(): array
{ {
$transactions = \DB::table('budget_transaction')->distinct()->pluck('transaction_id')->toArray(); $transactions = DB::table('budget_transaction')->distinct()->pluck('transaction_id')->toArray();
$array = []; $array = [];
$chunks = array_chunk($transactions, 500); $chunks = array_chunk($transactions, 500);
foreach ($chunks as $chunk) { foreach ($chunks as $chunk) {
$set = \DB::table('transactions')->whereIn('transactions.id', $chunk)->pluck('transaction_journal_id')->toArray(); $set = DB::table('transactions')->whereIn('transactions.id', $chunk)->pluck('transaction_journal_id')->toArray();
$array = array_merge($array, $set); $array = array_merge($array, $set);
} }
@@ -171,12 +172,12 @@ class UpgradesJournalMetaData extends Command
private function getIdsForCategories(): array private function getIdsForCategories(): array
{ {
$transactions = \DB::table('category_transaction')->distinct()->pluck('transaction_id')->toArray(); $transactions = DB::table('category_transaction')->distinct()->pluck('transaction_id')->toArray();
$array = []; $array = [];
$chunks = array_chunk($transactions, 500); $chunks = array_chunk($transactions, 500);
foreach ($chunks as $chunk) { foreach ($chunks as $chunk) {
$set = \DB::table('transactions') $set = DB::table('transactions')
->whereIn('transactions.id', $chunk) ->whereIn('transactions.id', $chunk)
->pluck('transaction_journal_id')->toArray() ->pluck('transaction_journal_id')->toArray()
; ;

View File

@@ -35,6 +35,7 @@ use FireflyIII\Repositories\Journal\JournalRepositoryInterface;
use FireflyIII\Services\Internal\Destroy\JournalDestroyService; use FireflyIII\Services\Internal\Destroy\JournalDestroyService;
use Illuminate\Console\Command; use Illuminate\Console\Command;
use Illuminate\Support\Collection; use Illuminate\Support\Collection;
use Illuminate\Support\Facades\DB;
class UpgradesToGroups extends Command class UpgradesToGroups extends Command
{ {
@@ -364,7 +365,7 @@ class UpgradesToGroups extends Command
private function giveGroup(array $array): void private function giveGroup(array $array): void
{ {
$groupId = \DB::table('transaction_groups')->insertGetId( $groupId = DB::table('transaction_groups')->insertGetId(
[ [
'created_at' => date('Y-m-d H:i:s'), 'created_at' => date('Y-m-d H:i:s'),
'updated_at' => date('Y-m-d H:i:s'), 'updated_at' => date('Y-m-d H:i:s'),
@@ -372,7 +373,7 @@ class UpgradesToGroups extends Command
'user_id' => $array['user_id'], 'user_id' => $array['user_id'],
] ]
); );
\DB::table('transaction_journals')->where('id', $array['id'])->update(['transaction_group_id' => $groupId]); DB::table('transaction_journals')->where('id', $array['id'])->update(['transaction_group_id' => $groupId]);
++$this->count; ++$this->count;
} }

View File

@@ -76,7 +76,7 @@ class TagFactory
$longitude = 0.0 === (float) $data['longitude'] ? null : (float) $data['longitude']; // intentional float $longitude = 0.0 === (float) $data['longitude'] ? null : (float) $data['longitude']; // intentional float
$array = [ $array = [
'user_id' => $this->user->id, 'user_id' => $this->user->id,
'user_group_id' => $this->user->user_group_id, 'user_group_id' => $this->userGroup->id,
'tag' => trim($data['tag']), 'tag' => trim($data['tag']),
'tagMode' => 'nothing', 'tagMode' => 'nothing',
'date' => $data['date'], 'date' => $data['date'],

View File

@@ -79,7 +79,7 @@ class TransactionGroupFactory
$group = new TransactionGroup(); $group = new TransactionGroup();
$group->user()->associate($this->user); $group->user()->associate($this->user);
$group->userGroup()->associate($data['user_group']); $group->userGroup()->associate($this->userGroup);
$group->title = $title; $group->title = $title;
$group->save(); $group->save();
@@ -93,7 +93,8 @@ class TransactionGroupFactory
*/ */
public function setUser(User $user): void public function setUser(User $user): void
{ {
$this->user = $user; $this->user = $user;
$this->userGroup = $user->userGroup;
} }
public function setUserGroup(UserGroup $userGroup): void public function setUserGroup(UserGroup $userGroup): void

View File

@@ -136,6 +136,7 @@ class MonthReportGenerator implements ReportGeneratorInterface
; ;
$journals = $collector->getExtractedJournals(); $journals = $collector->getExtractedJournals();
$journals = array_reverse($journals, true); $journals = array_reverse($journals, true);
// this call is correct.
Log::debug(sprintf('getAuditReport: Call finalAccountBalance with date/time "%s"', $date->toIso8601String())); Log::debug(sprintf('getAuditReport: Call finalAccountBalance with date/time "%s"', $date->toIso8601String()));
$dayBeforeBalance = Steam::finalAccountBalance($account, $date); $dayBeforeBalance = Steam::finalAccountBalance($account, $date);
$startBalance = $dayBeforeBalance['balance']; $startBalance = $dayBeforeBalance['balance'];
@@ -171,6 +172,7 @@ class MonthReportGenerator implements ReportGeneratorInterface
$journals[$index]['invoice_date'] = $journalRepository->getMetaDateById($journal['transaction_journal_id'], 'invoice_date'); $journals[$index]['invoice_date'] = $journalRepository->getMetaDateById($journal['transaction_journal_id'], 'invoice_date');
} }
$locale = app('steam')->getLocale(); $locale = app('steam')->getLocale();
// call is correct.
Log::debug(sprintf('getAuditReport end: Call finalAccountBalance with date/time "%s"', $this->end->toIso8601String())); Log::debug(sprintf('getAuditReport end: Call finalAccountBalance with date/time "%s"', $this->end->toIso8601String()));
return [ return [

View File

@@ -28,6 +28,7 @@ use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Helpers\Update\UpdateTrait; use FireflyIII\Helpers\Update\UpdateTrait;
use FireflyIII\Models\Configuration; use FireflyIII\Models\Configuration;
use FireflyIII\Repositories\User\UserRepositoryInterface; use FireflyIII\Repositories\User\UserRepositoryInterface;
use Illuminate\Support\Facades\Log;
/** /**
* Class VersionCheckEventHandler * Class VersionCheckEventHandler
@@ -45,13 +46,13 @@ class VersionCheckEventHandler
*/ */
public function checkForUpdates(RequestedVersionCheckStatus $event): void public function checkForUpdates(RequestedVersionCheckStatus $event): void
{ {
app('log')->debug('Now in checkForUpdates()'); Log::debug('Now in checkForUpdates()');
// should not check for updates: // should not check for updates:
$permission = app('fireflyconfig')->get('permission_update_check', -1); $permission = app('fireflyconfig')->get('permission_update_check', -1);
$value = (int) $permission->data; $value = (int) $permission->data;
if (1 !== $value) { if (1 !== $value) {
app('log')->debug('Update check is not enabled.'); Log::debug('Update check is not enabled.');
$this->warnToCheckForUpdates($event); $this->warnToCheckForUpdates($event);
return; return;
@@ -61,7 +62,7 @@ class VersionCheckEventHandler
$repository = app(UserRepositoryInterface::class); $repository = app(UserRepositoryInterface::class);
$user = $event->user; $user = $event->user;
if (!$repository->hasRole($user, 'owner')) { if (!$repository->hasRole($user, 'owner')) {
app('log')->debug('User is not admin, done.'); Log::debug('User is not admin, done.');
return; return;
} }
@@ -70,14 +71,14 @@ class VersionCheckEventHandler
$lastCheckTime = app('fireflyconfig')->get('last_update_check', time()); $lastCheckTime = app('fireflyconfig')->get('last_update_check', time());
$now = time(); $now = time();
$diff = $now - $lastCheckTime->data; $diff = $now - $lastCheckTime->data;
app('log')->debug(sprintf('Last check time is %d, current time is %d, difference is %d', $lastCheckTime->data, $now, $diff)); Log::debug(sprintf('Last check time is %d, current time is %d, difference is %d', $lastCheckTime->data, $now, $diff));
if ($diff < 604800) { if ($diff < 604800) {
app('log')->debug(sprintf('Checked for updates less than a week ago (on %s).', date('Y-m-d H:i:s', $lastCheckTime->data))); Log::debug(sprintf('Checked for updates less than a week ago (on %s).', date('Y-m-d H:i:s', $lastCheckTime->data)));
return; return;
} }
// last check time was more than a week ago. // last check time was more than a week ago.
app('log')->debug('Have not checked for a new version in a week!'); Log::debug('Have not checked for a new version in a week!');
$release = $this->getLatestRelease(); $release = $this->getLatestRelease();
session()->flash($release['level'], $release['message']); session()->flash($release['level'], $release['message']);
@@ -93,7 +94,7 @@ class VersionCheckEventHandler
$repository = app(UserRepositoryInterface::class); $repository = app(UserRepositoryInterface::class);
$user = $event->user; $user = $event->user;
if (!$repository->hasRole($user, 'owner')) { if (!$repository->hasRole($user, 'owner')) {
app('log')->debug('User is not admin, done.'); Log::debug('User is not admin, done.');
return; return;
} }
@@ -102,14 +103,14 @@ class VersionCheckEventHandler
$lastCheckTime = app('fireflyconfig')->get('last_update_warning', time()); $lastCheckTime = app('fireflyconfig')->get('last_update_warning', time());
$now = time(); $now = time();
$diff = $now - $lastCheckTime->data; $diff = $now - $lastCheckTime->data;
app('log')->debug(sprintf('Last warning time is %d, current time is %d, difference is %d', $lastCheckTime->data, $now, $diff)); Log::debug(sprintf('Last warning time is %d, current time is %d, difference is %d', $lastCheckTime->data, $now, $diff));
if ($diff < 604800 * 4) { if ($diff < 604800 * 4) {
app('log')->debug(sprintf('Warned about updates less than four weeks ago (on %s).', date('Y-m-d H:i:s', $lastCheckTime->data))); Log::debug(sprintf('Warned about updates less than four weeks ago (on %s).', date('Y-m-d H:i:s', $lastCheckTime->data)));
return; return;
} }
// last check time was more than a week ago. // last check time was more than a week ago.
app('log')->debug('Have warned about a new version in four weeks!'); Log::debug('Have warned about a new version in four weeks!');
session()->flash('info', (string) trans('firefly.disabled_but_check')); session()->flash('info', (string) trans('firefly.disabled_but_check'));
app('fireflyconfig')->set('last_update_warning', time()); app('fireflyconfig')->set('last_update_warning', time());

View File

@@ -26,11 +26,14 @@ namespace FireflyIII\Handlers\Observer;
use FireflyIII\Models\Account; use FireflyIII\Models\Account;
use FireflyIII\Models\Attachment; use FireflyIII\Models\Attachment;
use FireflyIII\Models\PiggyBank; use FireflyIII\Models\Transaction;
use FireflyIII\Models\TransactionGroup;
use FireflyIII\Models\TransactionJournal;
use FireflyIII\Repositories\Attachment\AttachmentRepositoryInterface; use FireflyIII\Repositories\Attachment\AttachmentRepositoryInterface;
use FireflyIII\Repositories\UserGroups\Account\AccountRepositoryInterface; use FireflyIII\Repositories\UserGroups\Account\AccountRepositoryInterface;
use FireflyIII\Support\Facades\Amount; use FireflyIII\Support\Facades\Amount;
use FireflyIII\Support\Http\Api\ExchangeRateConverter; use FireflyIII\Support\Http\Api\ExchangeRateConverter;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Log;
/** /**
@@ -72,24 +75,31 @@ class AccountObserver
*/ */
public function deleting(Account $account): void public function deleting(Account $account): void
{ {
// app('log')->debug('Observe "deleting" of an account.'); app('log')->debug('Observe "deleting" of an account.');
$account->accountMeta()->delete();
$repository = app(AttachmentRepositoryInterface::class); $repository = app(AttachmentRepositoryInterface::class);
$repository->setUser($account->user); $repository->setUser($account->user);
/** @var PiggyBank $piggy */ DB::table('account_piggy_bank')->where('account_id', $account->id)->delete();
foreach ($account->piggyBanks()->get() as $piggy) {
$piggy->accounts()->detach($account);
}
/** @var Attachment $attachment */ /** @var Attachment $attachment */
foreach ($account->attachments()->get() as $attachment) { foreach ($account->attachments()->get() as $attachment) {
$repository->destroy($attachment); $repository->destroy($attachment);
} }
foreach ($account->transactions()->get() as $transaction) {
$transaction->delete(); $journalIds = Transaction::where('account_id', $account->id)->get(['transactions.transaction_journal_id'])->pluck('transaction_journal_id')->toArray();
$groupIds = TransactionJournal::whereIn('id', $journalIds)->get(['transaction_journals.transaction_group_id'])->pluck('transaction_group_id')->toArray();
if (count($journalIds) > 0) {
Transaction::whereIn('transaction_journal_id', $journalIds)->delete();
TransactionJournal::whereIn('id', $journalIds)->delete();
} }
if (count($groupIds) > 0) {
TransactionGroup::whereIn('id', $groupIds)->delete();
}
Log::debug(sprintf('Delete %d journal(s)', count($journalIds)));
Log::debug(sprintf('Delete %d group(s)', count($groupIds)));
$account->notes()->delete(); $account->notes()->delete();
$account->locations()->delete(); $account->locations()->delete();
} }

View File

@@ -115,6 +115,7 @@ class ReconcileController extends Controller
$startDate = clone $start; $startDate = clone $start;
$startDate->subDay()->endOfDay(); // this is correct, subday endofday ends at 23:59:59 $startDate->subDay()->endOfDay(); // this is correct, subday endofday ends at 23:59:59
// both are validated and are correct.
Log::debug(sprintf('reconcile: Call finalAccountBalance with date/time "%s"', $startDate->toIso8601String())); Log::debug(sprintf('reconcile: Call finalAccountBalance with date/time "%s"', $startDate->toIso8601String()));
Log::debug(sprintf('reconcile2: Call finalAccountBalance with date/time "%s"', $end->toIso8601String())); Log::debug(sprintf('reconcile2: Call finalAccountBalance with date/time "%s"', $end->toIso8601String()));
$startBalance = Steam::bcround(Steam::finalAccountBalance($account, $startDate)['balance'], $currency->decimal_places); $startBalance = Steam::bcround(Steam::finalAccountBalance($account, $startDate)['balance'], $currency->decimal_places);

View File

@@ -29,6 +29,7 @@ use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Helpers\Collector\GroupCollectorInterface; use FireflyIII\Helpers\Collector\GroupCollectorInterface;
use FireflyIII\Http\Controllers\Controller; use FireflyIII\Http\Controllers\Controller;
use FireflyIII\Models\Account; use FireflyIII\Models\Account;
use FireflyIII\Models\Transaction;
use FireflyIII\Repositories\Account\AccountRepositoryInterface; use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use FireflyIII\Support\Facades\Steam; use FireflyIII\Support\Facades\Steam;
use FireflyIII\Support\Http\Controllers\PeriodOverview; use FireflyIII\Support\Http\Controllers\PeriodOverview;
@@ -80,6 +81,7 @@ class ShowController extends Controller
* */ * */
public function show(Request $request, Account $account, ?Carbon $start = null, ?Carbon $end = null) public function show(Request $request, Account $account, ?Carbon $start = null, ?Carbon $end = null)
{ {
$objectType = config(sprintf('firefly.shortNamesByFullName.%s', $account->accountType->type)); $objectType = config(sprintf('firefly.shortNamesByFullName.%s', $account->accountType->type));
if (!$this->isEditableAccount($account)) { if (!$this->isEditableAccount($account)) {
@@ -121,12 +123,7 @@ class ShowController extends Controller
/** @var GroupCollectorInterface $collector */ /** @var GroupCollectorInterface $collector */
$collector = app(GroupCollectorInterface::class); $collector = app(GroupCollectorInterface::class);
$collector $collector->setAccounts(new Collection([$account]))->setLimit($pageSize)->setPage($page)->withAccountInformation()->withCategoryInformation()->setRange($start, $end);
->setAccounts(new Collection([$account]))
->setLimit($pageSize)
->setPage($page)->withAccountInformation()->withCategoryInformation()
->setRange($start, $end)
;
// this search will not include transaction groups where this asset account (or liability) // this search will not include transaction groups where this asset account (or liability)
// is just part of ONE of the journals. To force this: // is just part of ONE of the journals. To force this:
@@ -136,8 +133,14 @@ class ShowController extends Controller
$groups->setPath(route('accounts.show', [$account->id, $start->format('Y-m-d'), $end->format('Y-m-d')])); $groups->setPath(route('accounts.show', [$account->id, $start->format('Y-m-d'), $end->format('Y-m-d')]));
$showAll = false; $showAll = false;
Log::debug(sprintf('show: Call finalAccountBalance with date/time "%s"', $end->toIso8601String())); // correct
$balances = Steam::filterAccountBalance(Steam::finalAccountBalance($account, $end), $account, $this->convertToNative, $accountCurrency); $now = today()->endOfDay();
if ($now->gt($end) || $now->lt($start)) {
$now = $end;
}
Log::debug(sprintf('show: Call finalAccountBalance with date/time "%s"', $now->toIso8601String()));
$balances = Steam::filterAccountBalance(Steam::finalAccountBalance($account, $now), $account, $this->convertToNative, $accountCurrency);
return view( return view(
'accounts.show', 'accounts.show',
@@ -202,6 +205,7 @@ class ShowController extends Controller
$groups->setPath(route('accounts.show.all', [$account->id])); $groups->setPath(route('accounts.show.all', [$account->id]));
$chartUrl = route('chart.account.period', [$account->id, $start->format('Y-m-d'), $end->format('Y-m-d')]); $chartUrl = route('chart.account.period', [$account->id, $start->format('Y-m-d'), $end->format('Y-m-d')]);
$showAll = true; $showAll = true;
// correct
Log::debug(sprintf('showAll: Call finalAccountBalance with date/time "%s"', $end->toIso8601String())); Log::debug(sprintf('showAll: Call finalAccountBalance with date/time "%s"', $end->toIso8601String()));
$balances = Steam::filterAccountBalance(Steam::finalAccountBalance($account, $end), $account, $this->convertToNative, $accountCurrency); $balances = Steam::filterAccountBalance(Steam::finalAccountBalance($account, $end), $account, $this->convertToNative, $accountCurrency);

View File

@@ -41,6 +41,7 @@ use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use Illuminate\Http\Response; use Illuminate\Http\Response;
use Illuminate\Routing\Redirector; use Illuminate\Routing\Redirector;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Log;
use Illuminate\Validation\ValidationException; use Illuminate\Validation\ValidationException;
@@ -223,7 +224,7 @@ class LoginController extends Controller
{ {
Log::channel('audit')->info('Show login form (1.1).'); Log::channel('audit')->info('Show login form (1.1).');
$count = \DB::table('users')->count(); $count = DB::table('users')->count();
$guard = config('auth.defaults.guard'); $guard = config('auth.defaults.guard');
$title = (string) trans('firefly.login_page_title'); $title = (string) trans('firefly.login_page_title');

View File

@@ -424,8 +424,8 @@ class AccountController extends Controller
{ {
$start->startOfDay(); $start->startOfDay();
$end->endOfDay(); $end->endOfDay();
// TODO not sure if these date ranges will work as expected.
Log::debug(sprintf('Now in period("%s", "%s")', $start->format('Y-m-d H:i:s'), $end->format('Y-m-d H:i:s'))); Log::debug(sprintf('Now in period("%s", "%s")', $start->format('Y-m-d H:i:s'), $end->format('Y-m-d H:i:s')));
$chartData = [];
$cache = new CacheProperties(); $cache = new CacheProperties();
$cache->addProperty('chart.account.period'); $cache->addProperty('chart.account.period');
$cache->addProperty($start); $cache->addProperty($start);
@@ -454,7 +454,6 @@ class AccountController extends Controller
$range = Steam::filterAccountBalances($range, $account, $this->convertToNative, $accountCurrency); $range = Steam::filterAccountBalances($range, $account, $this->convertToNative, $accountCurrency);
// temp, get end balance. // temp, get end balance.
Log::debug('temp get end balance');
Log::debug(sprintf('period: Call finalAccountBalance with date/time "%s"', $end->toIso8601String())); Log::debug(sprintf('period: Call finalAccountBalance with date/time "%s"', $end->toIso8601String()));
Steam::finalAccountBalance($account, $end); Steam::finalAccountBalance($account, $end);
Log::debug('END temp get end balance done'); Log::debug('END temp get end balance done');
@@ -508,7 +507,7 @@ class AccountController extends Controller
$chartData = []; $chartData = [];
foreach ($return as $key => $info) { foreach ($return as $key => $info) {
if (3 === strlen($key)) { if ('balance' !== $key && 'native_balance' !== $key) {
// assume it's a currency: // assume it's a currency:
$setCurrency = $this->currencyRepository->findByCode($key); $setCurrency = $this->currencyRepository->findByCode($key);
$info['currency_symbol'] = $setCurrency->symbol; $info['currency_symbol'] = $setCurrency->symbol;

View File

@@ -42,6 +42,7 @@ use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use Illuminate\Routing\Redirector; use Illuminate\Routing\Redirector;
use Illuminate\Support\Facades\Artisan; use Illuminate\Support\Facades\Artisan;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Route; use Illuminate\Support\Facades\Route;
use Illuminate\View\View; use Illuminate\View\View;
@@ -268,8 +269,8 @@ class DebugController extends Controller
{ {
$maxFileSize = Steam::phpBytes((string) ini_get('upload_max_filesize')); $maxFileSize = Steam::phpBytes((string) ini_get('upload_max_filesize'));
$maxPostSize = Steam::phpBytes((string) ini_get('post_max_size')); $maxPostSize = Steam::phpBytes((string) ini_get('post_max_size'));
$drivers = \DB::availableDrivers(); $drivers = DB::availableDrivers();
$currentDriver = \DB::getDriverName(); $currentDriver = DB::getDriverName();
return [ return [
'db_version' => app('fireflyconfig')->get('db_version', 1)->data, 'db_version' => app('fireflyconfig')->get('db_version', 1)->data,

View File

@@ -195,6 +195,7 @@ class ReconcileController extends Controller
$startDate->subDay(); $startDate->subDay();
$currency = $this->accountRepos->getAccountCurrency($account) ?? $this->defaultCurrency; $currency = $this->accountRepos->getAccountCurrency($account) ?? $this->defaultCurrency;
// correct
Log::debug(sprintf('transactions: Call finalAccountBalance with date/time "%s"', $startDate->toIso8601String())); Log::debug(sprintf('transactions: Call finalAccountBalance with date/time "%s"', $startDate->toIso8601String()));
Log::debug(sprintf('transactions2: Call finalAccountBalance with date/time "%s"', $end->toIso8601String())); Log::debug(sprintf('transactions2: Call finalAccountBalance with date/time "%s"', $end->toIso8601String()));
$startBalance = Steam::bcround(Steam::finalAccountBalance($account, $startDate)['balance'], $currency->decimal_places); $startBalance = Steam::bcround(Steam::finalAccountBalance($account, $startDate)['balance'], $currency->decimal_places);

View File

@@ -31,6 +31,7 @@ use FireflyIII\Models\Account;
use FireflyIII\Models\PiggyBank; use FireflyIII\Models\PiggyBank;
use FireflyIII\Repositories\ObjectGroup\OrganisesObjectGroups; use FireflyIII\Repositories\ObjectGroup\OrganisesObjectGroups;
use FireflyIII\Repositories\PiggyBank\PiggyBankRepositoryInterface; use FireflyIII\Repositories\PiggyBank\PiggyBankRepositoryInterface;
use FireflyIII\Support\JsonApi\Enrichments\AccountEnrichment;
use FireflyIII\Transformers\AccountTransformer; use FireflyIII\Transformers\AccountTransformer;
use FireflyIII\Transformers\PiggyBankTransformer; use FireflyIII\Transformers\PiggyBankTransformer;
use Illuminate\Contracts\View\Factory; use Illuminate\Contracts\View\Factory;
@@ -81,25 +82,25 @@ class IndexController extends Controller
{ {
$this->cleanupObjectGroups(); $this->cleanupObjectGroups();
$this->piggyRepos->resetOrder(); $this->piggyRepos->resetOrder();
$collection = $this->piggyRepos->getPiggyBanks(); $collection = $this->piggyRepos->getPiggyBanks();
/** @var Carbon $end */ /** @var Carbon $end */
$end = session('end', today(config('app.timezone'))->endOfMonth()); $end = session('end', today(config('app.timezone'))->endOfMonth());
// transform piggies using the transformer: // transform piggies using the transformer:
$parameters = new ParameterBag(); // $parameters = new ParameterBag();
$parameters->set('end', $end); // $parameters->set('end', $end);
/** @var AccountTransformer $accountTransformer */ // /** @var AccountTransformer $accountTransformer */
$accountTransformer = app(AccountTransformer::class); // $accountTransformer = app(AccountTransformer::class);
$accountTransformer->setParameters($parameters); // $accountTransformer->setParameters($parameters);
// data // data
$piggyBanks = $this->groupPiggyBanks($collection); $piggyBanks = $this->groupPiggyBanks($collection);
$accounts = $this->collectAccounts($collection); $accounts = $this->collectAccounts($collection);
$accounts = $this->mergeAccountsAndPiggies($piggyBanks, $accounts); $accounts = $this->mergeAccountsAndPiggies($piggyBanks, $accounts);
$piggyBanks = $this->makeSums($piggyBanks); $piggyBanks = $this->makeSums($piggyBanks);
ksort($piggyBanks); ksort($piggyBanks);
@@ -144,6 +145,11 @@ class IndexController extends Controller
$accountTransformer = app(AccountTransformer::class); $accountTransformer = app(AccountTransformer::class);
$accountTransformer->setParameters($parameters); $accountTransformer->setParameters($parameters);
// enrich each account.
$enrichment = new AccountEnrichment();
$enrichment->setUser(auth()->user());
$enrichment->setConvertToNative($this->convertToNative);
$enrichment->setNative($this->defaultCurrency);
$return = []; $return = [];
/** @var PiggyBank $piggy */ /** @var PiggyBank $piggy */
@@ -152,6 +158,7 @@ class IndexController extends Controller
/** @var Account $account */ /** @var Account $account */
foreach ($accounts as $account) { foreach ($accounts as $account) {
$account = $enrichment->enrichSingle($account);
$array = $accountTransformer->transform($account); $array = $accountTransformer->transform($account);
$accountId = (int) $array['id']; $accountId = (int) $array['id'];
if (!array_key_exists($accountId, $return)) { if (!array_key_exists($accountId, $return)) {

View File

@@ -42,6 +42,7 @@ use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use Illuminate\Routing\Redirector; use Illuminate\Routing\Redirector;
use Illuminate\Support\Collection; use Illuminate\Support\Collection;
use Illuminate\Support\Facades\DB;
use Illuminate\View\View; use Illuminate\View\View;
use Laravel\Passport\ClientRepository; use Laravel\Passport\ClientRepository;
@@ -139,7 +140,7 @@ class ProfileController extends Controller
/** @var User $user */ /** @var User $user */
$user = auth()->user(); $user = auth()->user();
$isInternalAuth = $this->internalAuth; $isInternalAuth = $this->internalAuth;
$count = \DB::table('oauth_clients')->where('personal_access_client', true)->whereNull('user_id')->count(); $count = DB::table('oauth_clients')->where('personal_access_client', true)->whereNull('user_id')->count();
$subTitle = $user->email; $subTitle = $user->email;
$userId = $user->id; $userId = $user->id;
$enabled2FA = null !== $user->mfa_secret; $enabled2FA = null !== $user->mfa_secret;

View File

@@ -28,6 +28,7 @@ use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Support\System\OAuthKeys; use FireflyIII\Support\System\OAuthKeys;
use Illuminate\Database\QueryException; use Illuminate\Database\QueryException;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Log;
/** /**
@@ -83,7 +84,7 @@ class Installer
// Log::debug('Now in routine hasNoTables()'); // Log::debug('Now in routine hasNoTables()');
try { try {
\DB::table('users')->count(); DB::table('users')->count();
} catch (QueryException $e) { } catch (QueryException $e) {
$message = $e->getMessage(); $message = $e->getMessage();
Log::error(sprintf('Error message trying to access users-table: %s', $message)); Log::error(sprintf('Error message trying to access users-table: %s', $message));

View File

@@ -380,9 +380,10 @@ class CreateRecurringTransactions implements ShouldQueue
} }
$array = [ $array = [
'user' => $recurrence->user_id, 'user' => $recurrence->user,
'group_title' => $groupTitle, 'user_group' => $recurrence->user->userGroup,
'transactions' => $this->getTransactionData($recurrence, $repetition, $date), 'group_title' => $groupTitle,
'transactions' => $this->getTransactionData($recurrence, $repetition, $date),
]; ];
/** @var TransactionGroup $group */ /** @var TransactionGroup $group */
@@ -421,7 +422,8 @@ class CreateRecurringTransactions implements ShouldQueue
$single = [ $single = [
'type' => null === $transaction?->transactionType?->type ? strtolower($recurrence->transactionType->type) : strtolower($transaction->transactionType->type), // @phpstan-ignore-line 'type' => null === $transaction?->transactionType?->type ? strtolower($recurrence->transactionType->type) : strtolower($transaction->transactionType->type), // @phpstan-ignore-line
'date' => $date, 'date' => $date,
'user' => $recurrence->user_id, 'user' => $recurrence->user,
'user_group' => $recurrence->user->userGroup,
'currency_id' => $transaction->transaction_currency_id, 'currency_id' => $transaction->transaction_currency_id,
'currency_code' => null, 'currency_code' => null,
'description' => $transaction->description, 'description' => $transaction->description,

View File

@@ -48,14 +48,15 @@ class Account extends Model
protected $casts protected $casts
= [ = [
'created_at' => 'datetime', 'created_at' => 'datetime',
'updated_at' => 'datetime', 'updated_at' => 'datetime',
'user_id' => 'integer', 'user_id' => 'integer',
'deleted_at' => 'datetime', 'user_group_id' => 'integer',
'active' => 'boolean', 'deleted_at' => 'datetime',
'encrypted' => 'boolean', 'active' => 'boolean',
'virtual_balance' => 'string', 'encrypted' => 'boolean',
'native_virtual_balance' => 'string', 'virtual_balance' => 'string',
'native_virtual_balance' => 'string',
]; ];
protected $fillable = ['user_id', 'user_group_id', 'account_type_id', 'name', 'active', 'virtual_balance', 'iban', 'native_virtual_balance']; protected $fillable = ['user_id', 'user_group_id', 'account_type_id', 'name', 'active', 'virtual_balance', 'iban', 'native_virtual_balance'];

View File

@@ -42,13 +42,15 @@ class Attachment extends Model
protected $casts protected $casts
= [ = [
'created_at' => 'datetime', 'created_at' => 'datetime',
'updated_at' => 'datetime', 'updated_at' => 'datetime',
'deleted_at' => 'datetime', 'deleted_at' => 'datetime',
'uploaded' => 'boolean', 'uploaded' => 'boolean',
'user_id' => 'integer',
'user_group_id' => 'integer',
]; ];
protected $fillable = ['attachable_id', 'attachable_type', 'user_id', 'md5', 'filename', 'mime', 'title', 'description', 'size', 'uploaded']; protected $fillable = ['attachable_id', 'attachable_type', 'user_id', 'user_group_id', 'md5', 'filename', 'mime', 'title', 'description', 'size', 'uploaded'];
/** /**
* Route binder. Converts the key in the URL to the specified object (or throw 404). * Route binder. Converts the key in the URL to the specified object (or throw 404).

View File

@@ -41,14 +41,16 @@ class AvailableBudget extends Model
protected $casts protected $casts
= [ = [
'created_at' => 'datetime', 'created_at' => 'datetime',
'updated_at' => 'datetime', 'updated_at' => 'datetime',
'deleted_at' => 'datetime', 'deleted_at' => 'datetime',
'start_date' => 'date', 'start_date' => 'date',
'end_date' => 'date', 'end_date' => 'date',
'transaction_currency_id' => 'int', 'transaction_currency_id' => 'int',
'amount' => 'string', 'amount' => 'string',
'native_amount' => 'string', 'native_amount' => 'string',
'user_id' => 'integer',
'user_group_id' => 'integer',
]; ];
protected $fillable = ['user_id', 'user_group_id', 'transaction_currency_id', 'amount', 'start_date', 'end_date', 'start_date_tz', 'end_date_tz', 'native_amount']; protected $fillable = ['user_id', 'user_group_id', 'transaction_currency_id', 'amount', 'start_date', 'end_date', 'start_date_tz', 'end_date_tz', 'native_amount'];

View File

@@ -43,14 +43,16 @@ class Budget extends Model
protected $casts protected $casts
= [ = [
'created_at' => 'datetime', 'created_at' => 'datetime',
'updated_at' => 'datetime', 'updated_at' => 'datetime',
'deleted_at' => 'datetime', 'deleted_at' => 'datetime',
'active' => 'boolean', 'active' => 'boolean',
'encrypted' => 'boolean', 'encrypted' => 'boolean',
'user_id' => 'integer',
'user_group_id' => 'integer',
]; ];
protected $fillable = ['user_id', 'name', 'active', 'order', 'user_group_id']; protected $fillable = ['user_id', 'user_group_id', 'name', 'active', 'order', 'user_group_id'];
protected $hidden = ['encrypted']; protected $hidden = ['encrypted'];

View File

@@ -42,10 +42,12 @@ class Category extends Model
protected $casts protected $casts
= [ = [
'created_at' => 'datetime', 'created_at' => 'datetime',
'updated_at' => 'datetime', 'updated_at' => 'datetime',
'deleted_at' => 'datetime', 'deleted_at' => 'datetime',
'encrypted' => 'boolean', 'encrypted' => 'boolean',
'user_id' => 'integer',
'user_group_id' => 'integer',
]; ];
protected $fillable = ['user_id', 'user_group_id', 'name']; protected $fillable = ['user_id', 'user_group_id', 'name'];

View File

@@ -40,14 +40,15 @@ class CurrencyExchangeRate extends Model
protected $casts protected $casts
= [ = [
'created_at' => 'datetime', 'created_at' => 'datetime',
'updated_at' => 'datetime', 'updated_at' => 'datetime',
'user_id' => 'int', 'user_id' => 'integer',
'from_currency_id' => 'int', 'user_group_id' => 'integer',
'to_currency_id' => 'int', 'from_currency_id' => 'integer',
'date' => SeparateTimezoneCaster::class, 'to_currency_id' => 'integer',
'rate' => 'string', 'date' => SeparateTimezoneCaster::class,
'user_rate' => 'string', 'rate' => 'string',
'user_rate' => 'string',
]; ];
protected $fillable = ['user_id', 'from_currency_id', 'to_currency_id', 'date', 'date_tz', 'rate']; protected $fillable = ['user_id', 'from_currency_id', 'to_currency_id', 'date', 'date_tz', 'rate'];

View File

@@ -36,6 +36,13 @@ class GroupMembership extends Model
use ReturnsIntegerIdTrait; use ReturnsIntegerIdTrait;
use ReturnsIntegerUserIdTrait; use ReturnsIntegerUserIdTrait;
protected $casts = [
'created_at' => 'datetime',
'updated_at' => 'datetime',
'user_id' => 'integer',
'user_group_id' => 'integer',
];
protected $fillable = ['user_id', 'user_group_id', 'user_role_id']; protected $fillable = ['user_id', 'user_group_id', 'user_role_id'];
public function user(): BelongsTo public function user(): BelongsTo

View File

@@ -39,10 +39,12 @@ class InvitedUser extends Model
protected $casts protected $casts
= [ = [
'expires' => SeparateTimezoneCaster::class, 'expires' => SeparateTimezoneCaster::class,
'redeemed' => 'boolean', 'redeemed' => 'boolean',
'user_id' => 'integer',
'user_group_id' => 'integer',
]; ];
protected $fillable = ['user_id', 'email', 'invite_code', 'expires', 'expires_tz', 'redeemed']; protected $fillable = ['user_group_id', 'user_id', 'email', 'invite_code', 'expires', 'expires_tz', 'redeemed'];
/** /**
* Route binder. Converts the key in the URL to the specified object (or throw 404). * Route binder. Converts the key in the URL to the specified object (or throw 404).

View File

@@ -40,10 +40,11 @@ class ObjectGroup extends Model
protected $casts protected $casts
= [ = [
'created_at' => 'datetime', 'created_at' => 'datetime',
'updated_at' => 'datetime', 'updated_at' => 'datetime',
'user_id' => 'integer', 'user_id' => 'integer',
'deleted_at' => 'datetime', 'user_group_id' => 'integer',
'deleted_at' => 'datetime',
]; ];
protected $fillable = ['title', 'order', 'user_id', 'user_group_id']; protected $fillable = ['title', 'order', 'user_id', 'user_group_id'];

View File

@@ -37,9 +37,11 @@ class Preference extends Model
protected $casts protected $casts
= [ = [
'created_at' => 'datetime', 'created_at' => 'datetime',
'updated_at' => 'datetime', 'updated_at' => 'datetime',
'data' => 'array', 'data' => 'array',
'user_id' => 'integer',
'user_group_id' => 'integer',
]; ];
protected $fillable = ['user_id', 'data', 'name', 'user_group_id']; protected $fillable = ['user_id', 'data', 'name', 'user_group_id'];

View File

@@ -44,22 +44,24 @@ class Recurrence extends Model
protected $casts protected $casts
= [ = [
'created_at' => 'datetime', 'created_at' => 'datetime',
'updated_at' => 'datetime', 'updated_at' => 'datetime',
'deleted_at' => 'datetime', 'deleted_at' => 'datetime',
'title' => 'string', 'title' => 'string',
'id' => 'int', 'id' => 'int',
'description' => 'string', 'description' => 'string',
'first_date' => SeparateTimezoneCaster::class, 'first_date' => SeparateTimezoneCaster::class,
'repeat_until' => SeparateTimezoneCaster::class, 'repeat_until' => SeparateTimezoneCaster::class,
'latest_date' => SeparateTimezoneCaster::class, 'latest_date' => SeparateTimezoneCaster::class,
'repetitions' => 'int', 'repetitions' => 'int',
'active' => 'bool', 'active' => 'bool',
'apply_rules' => 'bool', 'apply_rules' => 'bool',
'user_id' => 'integer',
'user_group_id' => 'integer',
]; ];
protected $fillable protected $fillable
= ['user_id', 'transaction_type_id', 'title', 'description', 'first_date', 'first_date_tz', 'repeat_until', 'repeat_until_tz', 'latest_date', 'latest_date_tz', 'repetitions', 'apply_rules', 'active']; = ['user_id', 'user_group_id', 'transaction_type_id', 'title', 'description', 'first_date', 'first_date_tz', 'repeat_until', 'repeat_until_tz', 'latest_date', 'latest_date_tz', 'repetitions', 'apply_rules', 'active'];
protected $table = 'recurrences'; protected $table = 'recurrences';

View File

@@ -41,17 +41,19 @@ class Rule extends Model
protected $casts protected $casts
= [ = [
'created_at' => 'datetime', 'created_at' => 'datetime',
'updated_at' => 'datetime', 'updated_at' => 'datetime',
'deleted_at' => 'datetime', 'deleted_at' => 'datetime',
'active' => 'boolean', 'active' => 'boolean',
'order' => 'int', 'order' => 'int',
'stop_processing' => 'boolean', 'stop_processing' => 'boolean',
'id' => 'int', 'id' => 'int',
'strict' => 'boolean', 'strict' => 'boolean',
'user_id' => 'integer',
'user_group_id' => 'integer',
]; ];
protected $fillable = ['rule_group_id', 'order', 'active', 'title', 'description', 'user_id', 'strict']; protected $fillable = ['rule_group_id', 'order', 'active', 'title', 'description', 'user_id', 'user_group_id', 'strict'];
/** /**
* Route binder. Converts the key in the URL to the specified object (or throw 404). * Route binder. Converts the key in the URL to the specified object (or throw 404).

View File

@@ -41,12 +41,14 @@ class RuleGroup extends Model
protected $casts protected $casts
= [ = [
'created_at' => 'datetime', 'created_at' => 'datetime',
'updated_at' => 'datetime', 'updated_at' => 'datetime',
'deleted_at' => 'datetime', 'deleted_at' => 'datetime',
'active' => 'boolean', 'active' => 'boolean',
'stop_processing' => 'boolean', 'stop_processing' => 'boolean',
'order' => 'int', 'order' => 'int',
'user_id' => 'integer',
'user_group_id' => 'integer',
]; ];
protected $fillable = ['user_id', 'user_group_id', 'stop_processing', 'order', 'title', 'description', 'active']; protected $fillable = ['user_id', 'user_group_id', 'stop_processing', 'order', 'title', 'description', 'active'];

View File

@@ -42,13 +42,15 @@ class Tag extends Model
protected $casts protected $casts
= [ = [
'created_at' => 'datetime', 'created_at' => 'datetime',
'updated_at' => 'datetime', 'updated_at' => 'datetime',
'deleted_at' => 'datetime', 'deleted_at' => 'datetime',
'date' => SeparateTimezoneCaster::class, 'date' => SeparateTimezoneCaster::class,
'zoomLevel' => 'int', 'zoomLevel' => 'int',
'latitude' => 'float', 'latitude' => 'float',
'longitude' => 'float', 'longitude' => 'float',
'user_id' => 'integer',
'user_group_id' => 'integer',
]; ];
protected $fillable = ['user_id', 'user_group_id', 'tag', 'date', 'date_tz', 'description', 'tagMode']; protected $fillable = ['user_id', 'user_group_id', 'tag', 'date', 'date_tz', 'description', 'tagMode'];

View File

@@ -40,12 +40,14 @@ class TransactionGroup extends Model
protected $casts protected $casts
= [ = [
'id' => 'integer', 'id' => 'integer',
'created_at' => 'datetime', 'created_at' => 'datetime',
'updated_at' => 'datetime', 'updated_at' => 'datetime',
'deleted_at' => 'datetime', 'deleted_at' => 'datetime',
'title' => 'string', 'title' => 'string',
'date' => 'datetime', 'date' => 'datetime',
'user_id' => 'integer',
'user_group_id' => 'integer',
]; ];
protected $fillable = ['user_id', 'user_group_id', 'title']; protected $fillable = ['user_id', 'user_group_id', 'title'];

View File

@@ -54,17 +54,19 @@ class TransactionJournal extends Model
protected $casts protected $casts
= [ = [
'created_at' => 'datetime', 'created_at' => 'datetime',
'updated_at' => 'datetime', 'updated_at' => 'datetime',
'deleted_at' => 'datetime', 'deleted_at' => 'datetime',
'date' => SeparateTimezoneCaster::class, 'date' => SeparateTimezoneCaster::class,
'interest_date' => 'date', 'interest_date' => 'date',
'book_date' => 'date', 'book_date' => 'date',
'process_date' => 'date', 'process_date' => 'date',
'order' => 'int', 'order' => 'int',
'tag_count' => 'int', 'tag_count' => 'int',
'encrypted' => 'boolean', 'encrypted' => 'boolean',
'completed' => 'boolean', 'completed' => 'boolean',
'user_id' => 'integer',
'user_group_id' => 'integer',
]; ];
protected $fillable protected $fillable

View File

@@ -44,10 +44,12 @@ class Webhook extends Model
protected $casts protected $casts
= [ = [
'active' => 'boolean', 'active' => 'boolean',
'trigger' => 'integer', 'trigger' => 'integer',
'response' => 'integer', 'response' => 'integer',
'delivery' => 'integer', 'delivery' => 'integer',
'user_id' => 'integer',
'user_group_id' => 'integer',
]; ];
protected $fillable = ['active', 'trigger', 'response', 'delivery', 'user_id', 'user_group_id', 'url', 'title', 'secret']; protected $fillable = ['active', 'trigger', 'response', 'delivery', 'user_id', 'user_group_id', 'url', 'title', 'secret'];

View File

@@ -498,6 +498,8 @@ class AccountRepository implements AccountRepositoryInterface
} }
$query->orderBy('accounts.active', 'DESC'); $query->orderBy('accounts.active', 'DESC');
$query->orderBy('accounts.name', 'ASC'); $query->orderBy('accounts.name', 'ASC');
$query->orderBy('accounts.account_type_id', 'ASC');
$query->orderBy('accounts.id', 'ASC');
} }
return $query->get(['accounts.*']); return $query->get(['accounts.*']);

View File

@@ -42,6 +42,7 @@ use FireflyIII\Support\Repositories\UserGroup\UserGroupTrait;
use Illuminate\Database\Query\JoinClause; use Illuminate\Database\Query\JoinClause;
use Illuminate\Pagination\LengthAwarePaginator; use Illuminate\Pagination\LengthAwarePaginator;
use Illuminate\Support\Collection; use Illuminate\Support\Collection;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Log;
/** /**
@@ -556,7 +557,7 @@ class BillRepository implements BillRepositoryInterface
return $this->user->bills() return $this->user->bills()
->where('active', true) ->where('active', true)
->orderBy('bills.name', 'ASC') ->orderBy('bills.name', 'ASC')
->get(['bills.*', \DB::raw('((bills.amount_min + bills.amount_max) / 2) AS expectedAmount')]) // @phpstan-ignore-line ->get(['bills.*', DB::raw('((bills.amount_min + bills.amount_max) / 2) AS expectedAmount')]) // @phpstan-ignore-line
; ;
} }

View File

@@ -214,7 +214,6 @@ class OperationsRepository implements OperationsRepositoryInterface
Log::debug(sprintf('Start of %s.', __METHOD__)); Log::debug(sprintf('Start of %s.', __METHOD__));
// this collector excludes all transfers TO liabilities (which are also withdrawals) // this collector excludes all transfers TO liabilities (which are also withdrawals)
// because those expenses only become expenses once they move from the liability to the friend. // because those expenses only become expenses once they move from the liability to the friend.
// 2024-12-24 disable the exclusion for now. // 2024-12-24 disable the exclusion for now.
$repository = app(AccountRepositoryInterface::class); $repository = app(AccountRepositoryInterface::class);
@@ -245,7 +244,7 @@ class OperationsRepository implements OperationsRepositoryInterface
} }
if (null !== $currency) { if (null !== $currency) {
Log::debug(sprintf('Limit to currency %s', $currency->code)); Log::debug(sprintf('Limit to currency %s', $currency->code));
$collector->setNormalCurrency($currency); $collector->setCurrency($currency);
} }
$collector->setBudgets($budgets); $collector->setBudgets($budgets);
$journals = $collector->getExtractedJournals(); $journals = $collector->getExtractedJournals();

View File

@@ -26,6 +26,7 @@ namespace FireflyIII\Repositories\Currency;
use Carbon\Carbon; use Carbon\Carbon;
use FireflyIII\Models\CurrencyExchangeRate; use FireflyIII\Models\CurrencyExchangeRate;
use FireflyIII\Models\TransactionCurrency; use FireflyIII\Models\TransactionCurrency;
use FireflyIII\Models\UserGroup;
use FireflyIII\User; use FireflyIII\User;
use Illuminate\Contracts\Auth\Authenticatable; use Illuminate\Contracts\Auth\Authenticatable;
use Illuminate\Support\Collection; use Illuminate\Support\Collection;
@@ -36,6 +37,7 @@ use Illuminate\Support\Collection;
class CurrencyRepository implements CurrencyRepositoryInterface class CurrencyRepository implements CurrencyRepositoryInterface
{ {
private User $user; private User $user;
private UserGroup $userGroup;
#[\Override] #[\Override]
public function find(int $currencyId): ?TransactionCurrency public function find(int $currencyId): ?TransactionCurrency
@@ -109,7 +111,14 @@ class CurrencyRepository implements CurrencyRepositoryInterface
public function setUser(null|Authenticatable|User $user): void public function setUser(null|Authenticatable|User $user): void
{ {
if ($user instanceof User) { if ($user instanceof User) {
$this->user = $user; $this->user = $user;
$this->userGroup = $user->userGroup;
} }
} }
#[\Override]
public function setUserGroup(UserGroup $userGroup): void
{
$this->userGroup = $userGroup;
}
} }

View File

@@ -26,6 +26,7 @@ namespace FireflyIII\Repositories\Currency;
use Carbon\Carbon; use Carbon\Carbon;
use FireflyIII\Models\CurrencyExchangeRate; use FireflyIII\Models\CurrencyExchangeRate;
use FireflyIII\Models\TransactionCurrency; use FireflyIII\Models\TransactionCurrency;
use FireflyIII\Models\UserGroup;
use FireflyIII\User; use FireflyIII\User;
use Illuminate\Contracts\Auth\Authenticatable; use Illuminate\Contracts\Auth\Authenticatable;
use Illuminate\Support\Collection; use Illuminate\Support\Collection;
@@ -67,4 +68,6 @@ interface CurrencyRepositoryInterface
public function setExchangeRate(TransactionCurrency $fromCurrency, TransactionCurrency $toCurrency, Carbon $date, float $rate): CurrencyExchangeRate; public function setExchangeRate(TransactionCurrency $fromCurrency, TransactionCurrency $toCurrency, Carbon $date, float $rate): CurrencyExchangeRate;
public function setUser(null|Authenticatable|User $user): void; public function setUser(null|Authenticatable|User $user): void;
public function setUserGroup(UserGroup $userGroup): void;
} }

View File

@@ -233,8 +233,8 @@ trait ModifiesPiggyBanks
$difference = bcsub($piggyBank->target_amount, $currentAmount); $difference = bcsub($piggyBank->target_amount, $currentAmount);
// an amount will be removed, create "negative" event: // an amount will be removed, create "negative" event:
Log::debug(sprintf('ChangedAmount: is triggered with difference "%s"', $difference)); // Log::debug(sprintf('ChangedAmount: is triggered with difference "%s"', $difference));
event(new ChangedAmount($piggyBank, $difference, null, null)); // event(new ChangedAmount($piggyBank, $difference, null, null));
// question is, from which account(s) to remove the difference? // question is, from which account(s) to remove the difference?
// solution: just start from the top until there is no more money left to remove. // solution: just start from the top until there is no more money left to remove.

View File

@@ -361,6 +361,8 @@ class AccountRepository implements AccountRepositoryInterface
} }
$query->orderBy('accounts.order', 'ASC'); $query->orderBy('accounts.order', 'ASC');
$query->orderBy('accounts.name', 'ASC'); $query->orderBy('accounts.name', 'ASC');
$query->orderBy('accounts.account_type_id', 'ASC');
$query->orderBy('accounts.id', 'ASC');
} }
return $query->get(['accounts.*']); return $query->get(['accounts.*']);

View File

@@ -37,7 +37,7 @@ class UpdateRequest implements UpdateRequestInterface
{ {
public function getUpdateInformation(string $channel): array public function getUpdateInformation(string $channel): array
{ {
app('log')->debug(sprintf('Now in getUpdateInformation(%s)', $channel)); Log::debug(sprintf('Now in getUpdateInformation(%s)', $channel));
$information = [ $information = [
'level' => 'error', 'level' => 'error',
'message' => (string) trans('firefly.unknown_error'), 'message' => (string) trans('firefly.unknown_error'),
@@ -46,8 +46,8 @@ class UpdateRequest implements UpdateRequestInterface
// try to get array from update server: // try to get array from update server:
$updateInfo = $this->contactServer($channel); $updateInfo = $this->contactServer($channel);
if ('error' === $updateInfo['level']) { if ('error' === $updateInfo['level']) {
app('log')->error('Update information contains an error.'); Log::error('Update information contains an error.');
app('log')->error($updateInfo['message']); Log::error($updateInfo['message']);
$information['message'] = $updateInfo['message']; $information['message'] = $updateInfo['message'];
return $information; return $information;
@@ -59,7 +59,7 @@ class UpdateRequest implements UpdateRequestInterface
private function contactServer(string $channel): array private function contactServer(string $channel): array
{ {
app('log')->debug(sprintf('Now in contactServer(%s)', $channel)); Log::debug(sprintf('Now in contactServer(%s)', $channel));
// always fall back to current version: // always fall back to current version:
$return = [ $return = [
'version' => config('firefly.version'), 'version' => config('firefly.version'),
@@ -69,7 +69,7 @@ class UpdateRequest implements UpdateRequestInterface
]; ];
$url = config('firefly.update_endpoint'); $url = config('firefly.update_endpoint');
app('log')->debug(sprintf('Going to call %s', $url)); Log::debug(sprintf('Going to call %s', $url));
try { try {
$client = new Client(); $client = new Client();
@@ -81,17 +81,17 @@ class UpdateRequest implements UpdateRequestInterface
]; ];
$res = $client->request('GET', $url, $options); $res = $client->request('GET', $url, $options);
} catch (GuzzleException $e) { } catch (GuzzleException $e) {
app('log')->error('Ran into Guzzle error.'); Log::error('Ran into Guzzle error.');
app('log')->error($e->getMessage()); Log::error($e->getMessage());
app('log')->error($e->getTraceAsString()); Log::error($e->getTraceAsString());
$return['message'] = sprintf('Guzzle: %s', strip_tags($e->getMessage())); $return['message'] = sprintf('Guzzle: %s', strip_tags($e->getMessage()));
return $return; return $return;
} }
if (200 !== $res->getStatusCode()) { if (200 !== $res->getStatusCode()) {
app('log')->error(sprintf('Response status from server is %d.', $res->getStatusCode())); Log::error(sprintf('Response status from server is %d.', $res->getStatusCode()));
app('log')->error((string) $res->getBody()); Log::error((string) $res->getBody());
$return['message'] = sprintf('Error: %d', $res->getStatusCode()); $return['message'] = sprintf('Error: %d', $res->getStatusCode());
return $return; return $return;
@@ -101,16 +101,16 @@ class UpdateRequest implements UpdateRequestInterface
try { try {
$json = json_decode($body, true, 512, JSON_THROW_ON_ERROR); $json = json_decode($body, true, 512, JSON_THROW_ON_ERROR);
} catch (\JsonException $e) { } catch (\JsonException $e) {
app('log')->error('Body is not valid JSON'); Log::error('Body is not valid JSON');
app('log')->error($body); Log::error($body);
$return['message'] = 'Invalid JSON :('; $return['message'] = 'Invalid JSON :(';
return $return; return $return;
} }
if (!array_key_exists($channel, $json['firefly_iii'])) { if (!array_key_exists($channel, $json['firefly_iii'])) {
app('log')->error(sprintf('No valid update channel "%s"', $channel)); Log::error(sprintf('No valid update channel "%s"', $channel));
app('log')->error($body); Log::error($body);
$return['message'] = sprintf('Unknown update channel "%s" :(', $channel); $return['message'] = sprintf('Unknown update channel "%s" :(', $channel);
} }
@@ -124,7 +124,7 @@ class UpdateRequest implements UpdateRequestInterface
$return['level'] = 'success'; $return['level'] = 'success';
$return['date'] = $date->startOfDay(); $return['date'] = $date->startOfDay();
app('log')->info('Response from update server', $response); Log::info('Response from update server', $response);
return $return; return $return;
} }
@@ -134,7 +134,7 @@ class UpdateRequest implements UpdateRequestInterface
*/ */
private function parseResult(array $information): array private function parseResult(array $information): array
{ {
app('log')->debug('Now in parseResult()', $information); Log::debug('Now in parseResult()', $information);
$current = (string) config('firefly.version'); $current = (string) config('firefly.version');
$latest = (string) $information['version']; $latest = (string) $information['version'];
@@ -148,7 +148,7 @@ class UpdateRequest implements UpdateRequestInterface
$compare = version_compare($latest, $current); $compare = version_compare($latest, $current);
app('log')->debug(sprintf('Current version is "%s", latest is "%s", result is: %d', $current, $latest, $compare)); Log::debug(sprintf('Current version is "%s", latest is "%s", result is: %d', $current, $latest, $compare));
// -1: you're running a newer version: // -1: you're running a newer version:
if (-1 === $compare) { if (-1 === $compare) {
@@ -206,7 +206,7 @@ class UpdateRequest implements UpdateRequestInterface
'level' => 'info', 'level' => 'info',
'message' => (string) trans('firefly.update_newer_version_alert', ['your_version' => $current, 'new_version' => $latest]), 'message' => (string) trans('firefly.update_newer_version_alert', ['your_version' => $current, 'new_version' => $latest]),
]; ];
app('log')->debug('User is running a newer version', $return); Log::debug('User is running a newer version', $return);
return $return; return $return;
} }
@@ -217,14 +217,14 @@ class UpdateRequest implements UpdateRequestInterface
'level' => 'info', 'level' => 'info',
'message' => (string) trans('firefly.update_current_version_alert', ['version' => $current]), 'message' => (string) trans('firefly.update_current_version_alert', ['version' => $current]),
]; ];
app('log')->debug('User is the current version.', $return); Log::debug('User is the current version.', $return);
return $return; return $return;
} }
private function releasedNewAlpha(string $current, string $latest, Carbon $date): array private function releasedNewAlpha(string $current, string $latest, Carbon $date): array
{ {
app('log')->debug('New release is also a alpha!'); Log::debug('New release is also a alpha!');
$message = (string) trans( $message = (string) trans(
'firefly.update_new_version_alert', 'firefly.update_new_version_alert',
[ [
@@ -242,7 +242,7 @@ class UpdateRequest implements UpdateRequestInterface
private function releasedNewBeta(string $current, string $latest, Carbon $date): array private function releasedNewBeta(string $current, string $latest, Carbon $date): array
{ {
app('log')->debug('New release is also a beta!'); Log::debug('New release is also a beta!');
$message = (string) trans( $message = (string) trans(
'firefly.update_new_version_alert', 'firefly.update_new_version_alert',
[ [
@@ -260,7 +260,7 @@ class UpdateRequest implements UpdateRequestInterface
private function releasedNewVersion(string $current, string $latest, Carbon $date): array private function releasedNewVersion(string $current, string $latest, Carbon $date): array
{ {
app('log')->debug('New release is old enough.'); Log::debug('New release is old enough.');
$message = (string) trans( $message = (string) trans(
'firefly.update_new_version_alert', 'firefly.update_new_version_alert',
[ [
@@ -269,7 +269,7 @@ class UpdateRequest implements UpdateRequestInterface
'date' => $date->isoFormat((string) trans('config.month_and_day_js')), 'date' => $date->isoFormat((string) trans('config.month_and_day_js')),
] ]
); );
app('log')->debug('New release is here!', [$message]); Log::debug('New release is here!', [$message]);
event(new NewVersionAvailable($message)); event(new NewVersionAvailable($message));
return [ return [

View File

@@ -31,6 +31,7 @@ use FireflyIII\Models\RecurrenceTransaction;
use FireflyIII\Models\Transaction; use FireflyIII\Models\Transaction;
use FireflyIII\Models\TransactionJournal; use FireflyIII\Models\TransactionJournal;
use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Builder;
use Illuminate\Support\Facades\DB;
/** /**
* Class AccountDestroyService * Class AccountDestroyService
@@ -46,8 +47,6 @@ class AccountDestroyService
$this->moveTransactions($account, $moveTo); $this->moveTransactions($account, $moveTo);
$this->updateRecurrences($account, $moveTo); $this->updateRecurrences($account, $moveTo);
} }
$this->destroyJournals($account);
// delete recurring transactions with this account: // delete recurring transactions with this account:
if (null === $moveTo) { if (null === $moveTo) {
$this->destroyRecurrences($account); $this->destroyRecurrences($account);
@@ -59,6 +58,7 @@ class AccountDestroyService
// delete account meta: // delete account meta:
$account->accountMeta()->delete(); $account->accountMeta()->delete();
// delete account. // delete account.
// at this point the account observer interferes and deletes most of the other stuff.
$account->delete(); $account->delete();
} }
@@ -134,28 +134,8 @@ class AccountDestroyService
private function updateRecurrences(Account $account, Account $moveTo): void private function updateRecurrences(Account $account, Account $moveTo): void
{ {
\DB::table('recurrences_transactions')->where('source_id', $account->id)->update(['source_id' => $moveTo->id]); DB::table('recurrences_transactions')->where('source_id', $account->id)->update(['source_id' => $moveTo->id]);
\DB::table('recurrences_transactions')->where('destination_id', $account->id)->update(['destination_id' => $moveTo->id]); DB::table('recurrences_transactions')->where('destination_id', $account->id)->update(['destination_id' => $moveTo->id]);
}
private function destroyJournals(Account $account): void
{
/** @var JournalDestroyService $service */
$service = app(JournalDestroyService::class);
app('log')->debug('Now trigger account delete response #'.$account->id);
/** @var Transaction $transaction */
foreach ($account->transactions()->get() as $transaction) {
app('log')->debug('Now at transaction #'.$transaction->id);
/** @var null|TransactionJournal $journal */
$journal = $transaction->transactionJournal()->first();
if (null !== $journal) {
app('log')->debug('Call for deletion of journal #'.$journal->id);
$service->destroy($journal);
}
}
} }
private function destroyRecurrences(Account $account): void private function destroyRecurrences(Account $account): void

View File

@@ -248,7 +248,8 @@ trait AccountServiceTrait
'source_name' => $sourceName, 'source_name' => $sourceName,
'destination_id' => $destId, 'destination_id' => $destId,
'destination_name' => $destName, 'destination_name' => $destName,
'user' => $account->user_id, 'user' => $account->user,
'user_group' => $account->user->userGroup,
'currency_id' => $currency->id, 'currency_id' => $currency->id,
'order' => 0, 'order' => 0,
'amount' => $amount, 'amount' => $amount,
@@ -472,7 +473,8 @@ trait AccountServiceTrait
'source_name' => $sourceName, 'source_name' => $sourceName,
'destination_id' => $destId, 'destination_id' => $destId,
'destination_name' => $destName, 'destination_name' => $destName,
'user' => $account->user_id, 'user' => $account->user,
'user_group' => $account->user->userGroup,
'currency_id' => $currency->id, 'currency_id' => $currency->id,
'order' => 0, 'order' => 0,
'amount' => $amount, 'amount' => $amount,

View File

@@ -27,6 +27,7 @@ namespace FireflyIII\Support\Cronjobs;
use Carbon\Carbon; use Carbon\Carbon;
use FireflyIII\Jobs\DownloadExchangeRates; use FireflyIII\Jobs\DownloadExchangeRates;
use FireflyIII\Models\Configuration; use FireflyIII\Models\Configuration;
use Illuminate\Support\Facades\Log;
/** /**
* Class ExchangeRatesCronjob * Class ExchangeRatesCronjob
@@ -41,23 +42,23 @@ class ExchangeRatesCronjob extends AbstractCronjob
$diff = time() - $lastTime; $diff = time() - $lastTime;
$diffForHumans = today(config('app.timezone'))->diffForHumans(Carbon::createFromTimestamp($lastTime), null, true); $diffForHumans = today(config('app.timezone'))->diffForHumans(Carbon::createFromTimestamp($lastTime), null, true);
if (0 === $lastTime) { if (0 === $lastTime) {
app('log')->info('Exchange rates cron-job has never fired before.'); Log::info('Exchange rates cron-job has never fired before.');
} }
// less than half a day ago: // less than half a day ago:
if ($lastTime > 0 && $diff <= 43200) { if ($lastTime > 0 && $diff <= 43200) {
app('log')->info(sprintf('It has been %s since the exchange rates cron-job has fired.', $diffForHumans)); Log::info(sprintf('It has been %s since the exchange rates cron-job has fired.', $diffForHumans));
if (false === $this->force) { if (false === $this->force) {
app('log')->info('The exchange rates cron-job will not fire now.'); Log::info('The exchange rates cron-job will not fire now.');
$this->message = sprintf('It has been %s since the exchange rates cron-job has fired. It will not fire now.', $diffForHumans); $this->message = sprintf('It has been %s since the exchange rates cron-job has fired. It will not fire now.', $diffForHumans);
return; return;
} }
app('log')->info('Execution of the exchange rates cron-job has been FORCED.'); Log::info('Execution of the exchange rates cron-job has been FORCED.');
} }
if ($lastTime > 0 && $diff > 43200) { if ($lastTime > 0 && $diff > 43200) {
app('log')->info(sprintf('It has been %s since the exchange rates cron-job has fired. It will fire now!', $diffForHumans)); Log::info(sprintf('It has been %s since the exchange rates cron-job has fired. It will fire now!', $diffForHumans));
} }
$this->fireExchangeRateJob(); $this->fireExchangeRateJob();
@@ -66,7 +67,7 @@ class ExchangeRatesCronjob extends AbstractCronjob
private function fireExchangeRateJob(): void private function fireExchangeRateJob(): void
{ {
app('log')->info(sprintf('Will now fire exchange rates cron job task for date "%s".', $this->date->format('Y-m-d'))); Log::info(sprintf('Will now fire exchange rates cron job task for date "%s".', $this->date->format('Y-m-d')));
/** @var DownloadExchangeRates $job */ /** @var DownloadExchangeRates $job */
$job = app(DownloadExchangeRates::class); $job = app(DownloadExchangeRates::class);
@@ -80,6 +81,6 @@ class ExchangeRatesCronjob extends AbstractCronjob
$this->message = 'Exchange rates cron job fired successfully.'; $this->message = 'Exchange rates cron job fired successfully.';
app('fireflyconfig')->set('last_cer_job', (int) $this->date->format('U')); app('fireflyconfig')->set('last_cer_job', (int) $this->date->format('U'));
app('log')->info('Done with exchange rates job task.'); Log::info('Done with exchange rates job task.');
} }
} }

View File

@@ -0,0 +1,88 @@
<?php
/*
* UpdateCheckCronjob.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\Support\Cronjobs;
use FireflyIII\Helpers\Update\UpdateTrait;
use FireflyIII\Models\Configuration;
use FireflyIII\Support\Facades\FireflyConfig;
use Illuminate\Support\Facades\Log;
class UpdateCheckCronjob extends AbstractCronjob
{
use UpdateTrait;
#[\Override]
public function fire(): void
{
Log::debug('Now in checkForUpdates()');
// should not check for updates:
$permission = app('fireflyconfig')->get('permission_update_check', -1);
$value = (int) $permission->data;
if (1 !== $value) {
Log::debug('Update check is not enabled.');
// get stuff from job:
$this->jobFired = false;
$this->jobErrored = true;
$this->jobSucceeded = false;
$this->message = 'The update check is not enabled.';
return;
}
// TODO this is duplicate.
/** @var Configuration $lastCheckTime */
$lastCheckTime = FireflyConfig::get('last_update_check', time());
$now = time();
$diff = $now - $lastCheckTime->data;
Log::debug(sprintf('Last check time is %d, current time is %d, difference is %d', $lastCheckTime->data, $now, $diff));
if ($diff < 604800 && false === $this->force) {
// get stuff from job:
$this->jobFired = false;
$this->jobErrored = true;
$this->jobSucceeded = false;
$this->message = sprintf('Checked for updates less than a week ago (on %s).', date('Y-m-d H:i:s', $lastCheckTime->data));
return;
}
// last check time was more than a week ago.
Log::debug('Have not checked for a new version in a week!');
$release = $this->getLatestRelease();
if ('error' === $release['level']) {
// get stuff from job:
$this->jobFired = true;
$this->jobErrored = true;
$this->jobSucceeded = false;
$this->message = $release['message'];
return;
}
// get stuff from job:
$this->jobFired = true;
$this->jobErrored = false;
$this->jobSucceeded = false;
$this->message = $release['message'];
}
}

View File

@@ -199,7 +199,7 @@ trait ModelInformation
++$index; ++$index;
// amount_exactly: // amount_exactly:
$journalTriggers[$index] = 'amount_exactly'; $journalTriggers[$index] = 'amount_is';
$values[$index] = $destination->amount; $values[$index] = $destination->amount;
++$index; ++$index;
@@ -244,7 +244,7 @@ trait ModelInformation
// notes (if) // notes (if)
$notes = $journal->notes()->first(); $notes = $journal->notes()->first();
if (null !== $notes) { if (null !== $notes) {
$journalTriggers[$index] = 'notes_are'; $journalTriggers[$index] = 'notes_is';
$values[$index] = $notes->text; $values[$index] = $notes->text;
} }

View File

@@ -25,14 +25,19 @@ declare(strict_types=1);
namespace FireflyIII\Support\JsonApi\Enrichments; namespace FireflyIII\Support\JsonApi\Enrichments;
use Carbon\Carbon; use Carbon\Carbon;
use FireflyIII\Enums\TransactionTypeEnum;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Helpers\Collector\GroupCollectorInterface;
use FireflyIII\Models\Account; use FireflyIII\Models\Account;
use FireflyIII\Models\AccountMeta;
use FireflyIII\Models\AccountType; use FireflyIII\Models\AccountType;
use FireflyIII\Models\ObjectGroup; use FireflyIII\Models\Location;
use FireflyIII\Models\Note;
use FireflyIII\Models\TransactionCurrency; use FireflyIII\Models\TransactionCurrency;
use FireflyIII\Repositories\UserGroups\Account\AccountRepositoryInterface; use FireflyIII\Models\UserGroup;
use FireflyIII\Repositories\UserGroups\Currency\CurrencyRepositoryInterface;
use FireflyIII\Support\Facades\Balance; use FireflyIII\Support\Facades\Balance;
use FireflyIII\Support\Http\Api\ExchangeRateConverter; use FireflyIII\Support\Facades\Steam;
use FireflyIII\User;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Collection; use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Log;
@@ -44,27 +49,50 @@ use Illuminate\Support\Facades\Log;
*/ */
class AccountEnrichment implements EnrichmentInterface class AccountEnrichment implements EnrichmentInterface
{ {
private array $balances; // private array $balances;
private Collection $collection; // private array $currencies;
private array $currencies; // private CurrencyRepositoryInterface $currencyRepository;
private CurrencyRepositoryInterface $currencyRepository; // private TransactionCurrency $default;
private TransactionCurrency $default; // private ?Carbon $end;
private ?Carbon $end; // private array $grouped;
private array $grouped; // private array $objectGroups;
private array $objectGroups; // private AccountRepositoryInterface $repository;
private AccountRepositoryInterface $repository; // private ?Carbon $start;
private ?Carbon $start;
private Collection $collection;
private bool $convertToNative;
private User $user;
private UserGroup $userGroup;
private TransactionCurrency $native;
private array $accountIds;
private array $accountTypeIds;
private array $accountTypes;
private array $currencies;
private array $meta;
private array $openingBalances;
private array $notes;
private array $locations;
public function __construct() public function __construct()
{ {
$this->repository = app(AccountRepositoryInterface::class); $this->convertToNative = false;
$this->currencyRepository = app(CurrencyRepositoryInterface::class); $this->accountIds = [];
$this->start = null; $this->openingBalances = [];
$this->end = null; $this->currencies = [];
$this->accountTypeIds = [];
$this->accountTypes = [];
$this->meta = [];
$this->notes = [];
$this->locations = [];
// $this->repository = app(AccountRepositoryInterface::class);
// $this->currencyRepository = app(CurrencyRepositoryInterface::class);
// $this->start = null;
// $this->end = null;
} }
#[\Override] #[\Override]
public function enrichSingle(Model $model): Account public function enrichSingle(array|Model $model): Account|array
{ {
Log::debug(__METHOD__); Log::debug(__METHOD__);
$collection = new Collection([$model]); $collection = new Collection([$model]);
@@ -80,20 +108,27 @@ class AccountEnrichment implements EnrichmentInterface
public function enrich(Collection $collection): Collection public function enrich(Collection $collection): Collection
{ {
Log::debug(sprintf('Now doing account enrichment for %d account(s)', $collection->count())); Log::debug(sprintf('Now doing account enrichment for %d account(s)', $collection->count()));
// prep local fields
$this->collection = $collection;
$this->default = app('amount')->getNativeCurrency();
$this->currencies = [];
$this->balances = [];
$this->objectGroups = [];
$this->grouped = [];
// do everything here: // prep local fields
$this->getLastActivity(); $this->collection = $collection;
$this->collectAccountTypes(); $this->collectAccountIds();
$this->getAccountTypes();
$this->collectMetaData(); $this->collectMetaData();
$this->getMetaBalances(); $this->collectNotes();
$this->getObjectGroups(); $this->collectLocations();
$this->collectOpeningBalances();
// $this->default = app('amount')->getNativeCurrency();
// $this->currencies = [];
// $this->balances = [];
// $this->objectGroups = [];
// $this->grouped = [];
//
// // do everything here:
// $this->getLastActivity();
// $this->collectAccountTypes();
// $this->collectMetaData();
// $this->getMetaBalances();
// $this->getObjectGroups();
// $this->collection->transform(function (Account $account) { // $this->collection->transform(function (Account $account) {
// $account->user_array = ['id' => 1, 'bla bla' => 'bla']; // $account->user_array = ['id' => 1, 'bla bla' => 'bla'];
@@ -106,176 +141,177 @@ class AccountEnrichment implements EnrichmentInterface
// return $account; // return $account;
// }); // });
$this->appendCollectedData();
return $this->collection; return $this->collection;
} }
/** private function getAccountTypes(): void
* TODO this method refers to a single-use method inside Steam that could be moved here.
*/
private function getLastActivity(): void
{ {
$lastActivity = $this->repository->getLastActivity($this->collection); $types = AccountType::whereIn('id', $this->accountTypeIds)->get();
foreach ($lastActivity as $row) {
$this->collection->where('id', $row['account_id'])->first()->last_activity = Carbon::parse($row['date_max'], config('app.timezone')); /** @var AccountType $type */
foreach ($types as $type) {
$this->accountTypes[(int) $type->id] = $type->type;
} }
} }
/** private function collectAccountIds(): void
* TODO this method refers to a single-use method inside Steam that could be moved here.
*/
private function collectAccountTypes(): void
{ {
$accountTypes = $this->repository->getAccountTypes($this->collection); /** @var Account $account */
$types = []; foreach ($this->collection as $account) {
$this->accountIds[] = (int) $account->id;
/** @var AccountType $row */ $this->accountTypeIds[] = (int) $account->account_type_id;
foreach ($accountTypes as $row) {
$types[$row->id] = $row->type;
} }
$this->collection->transform(function (Account $account) use ($types) { $this->accountIds = array_unique($this->accountIds);
$account->account_type_string = $types[$account->id]; $this->accountTypeIds = array_unique($this->accountTypeIds);
}
return $account; private function appendCollectedData(): void
{
$accountTypes = $this->accountTypes;
$meta = $this->meta;
$currencies = $this->currencies;
$notes = $this->notes;
$openingBalances = $this->openingBalances;
$locations = $this->locations;
$this->collection = $this->collection->map(function (Account $item) use ($accountTypes, $meta, $currencies, $notes, $openingBalances, $locations) {
$item->full_account_type = $accountTypes[(int) $item->account_type_id] ?? null;
$accountMeta = [
'currency' => null,
'location' => [
'latitude' => null,
'longitude' => null,
'zoom_level' => null,
],
];
if (array_key_exists((int) $item->id, $meta)) {
foreach ($meta[(int) $item->id] as $name => $value) {
$accountMeta[$name] = $value;
}
}
// also add currency, if present.
if (array_key_exists('currency_id', $accountMeta)) {
$currencyId = (int) $accountMeta['currency_id'];
$accountMeta['currency'] = $currencies[$currencyId];
}
// if notes, add notes.
if (array_key_exists($item->id, $notes)) {
$accountMeta['notes'] = $notes[$item->id];
}
// if opening balance, add opening balance
if (array_key_exists($item->id, $openingBalances)) {
$accountMeta['opening_balance_date'] = $openingBalances[$item->id]['date'];
$accountMeta['opening_balance_amount'] = $openingBalances[$item->id]['amount'];
}
// if location, add location:
if (array_key_exists($item->id, $locations)) {
$accountMeta['location'] = $locations[$item->id];
}
$item->meta = $accountMeta;
return $item;
}); });
} }
private function collectOpeningBalances(): void
{
// use new group collector:
/** @var GroupCollectorInterface $collector */
$collector = app(GroupCollectorInterface::class);
$collector->setUser($this->user)->setAccounts($this->collection)
->withAccountInformation()
->setTypes([TransactionTypeEnum::OPENING_BALANCE->value])
;
$journals = $collector->getExtractedJournals();
foreach ($journals as $journal) {
$this->openingBalances[(int) $journal['source_account_id']]
= [
'amount' => Steam::negative($journal['amount']),
'date' => $journal['date'],
];
$this->openingBalances[(int) $journal['destination_account_id']]
= [
'amount' => Steam::positive($journal['amount']),
'date' => $journal['date'],
];
}
}
private function collectLocations(): void
{
$locations = Location::query()->whereIn('locatable_id', $this->accountIds)
->where('locatable_type', Account::class)->get(['locations.locatable_id', 'locations.latitude', 'locations.longitude', 'locations.zoom_level'])->toArray()
;
foreach ($locations as $location) {
$this->locations[(int) $location['locatable_id']]
= [
'latitude' => (float) $location['latitude'],
'longitude' => (float) $location['longitude'],
'zoom_level' => (int) $location['zoom_level'],
];
}
Log::debug(sprintf('Enrich with %d locations(s)', count($this->locations)));
}
private function collectMetaData(): void private function collectMetaData(): void
{ {
$metaFields = $this->repository->getMetaValues($this->collection, ['is_multi_currency', 'currency_id', 'account_role', 'account_number', 'liability_direction', 'interest', 'interest_period', 'current_debt']); $set = AccountMeta::whereIn('name', ['is_multi_currency', 'currency_id', 'account_role', 'account_number', 'liability_direction', 'interest', 'interest_period', 'current_debt'])
$currencyIds = $metaFields->where('name', 'currency_id')->pluck('data')->toArray(); ->whereIn('account_id', $this->accountIds)
->get(['account_meta.id', 'account_meta.account_id', 'account_meta.name', 'account_meta.data'])->toArray()
$currencies = [];
foreach ($this->currencyRepository->getByIds($currencyIds) as $currency) {
$id = $currency->id;
$currencies[$id] = $currency;
}
$this->collection->transform(function (Account $account) use ($metaFields, $currencies) {
$set = $metaFields->where('account_id', $account->id);
foreach ($set as $entry) {
$account->{$entry->name} = $entry->data;
if ('currency_id' === $entry->name) {
$id = (int) $entry->data;
$account->currency_name = $currencies[$id]?->name;
$account->currency_code = $currencies[$id]?->code;
$account->currency_symbol = $currencies[$id]?->symbol;
$account->currency_decimal_places = $currencies[$id]?->decimal_places;
}
}
return $account;
});
}
private function getMetaBalances(): void
{
$this->balances = Balance::getAccountBalances($this->collection, today());
$balances = $this->balances;
$default = $this->default;
// get start and end, so the balance difference can be generated.
$start = null;
$end = null;
if (null !== $this->start) {
$start = Balance::getAccountBalances($this->collection, $this->start);
}
if (null !== $this->end) {
$end = Balance::getAccountBalances($this->collection, $this->end);
}
$this->collection->transform(function (Account $account) use ($balances, $default, $start, $end) {
$converter = new ExchangeRateConverter();
$native = [
'currency_id' => $this->default->id,
'currency_name' => $this->default->name,
'currency_code' => $this->default->code,
'currency_symbol' => $this->default->symbol,
'currency_decimal_places' => $this->default->decimal_places,
'balance' => '0',
'period_start_balance' => null,
'period_end_balance' => null,
'balance_difference' => null,
];
if (array_key_exists($account->id, $balances)) {
$set = [];
foreach ($balances[$account->id] as $currencyId => $entry) {
$left = $start[$account->id][$currencyId]['balance'] ?? null;
$right = $end[$account->id][$currencyId]['balance'] ?? null;
$diff = null;
if (null !== $left && null !== $right) {
$diff = bcsub($right, $left);
}
$item = [
'currency_id' => $entry['currency']->id,
'currency_name' => $entry['currency']->name,
'currency_code' => $entry['currency']->code,
'currency_symbol' => $entry['currency']->symbol,
'currency_decimal_places' => $entry['currency']->decimal_places,
'balance' => $entry['balance'],
'period_start_balance' => $left,
'period_end_balance' => $right,
'balance_difference' => $diff,
];
$set[] = $item;
if ($converter->enabled()) {
$native['balance'] = bcadd($native['balance'], $converter->convert($entry['currency'], $default, today(), $entry['balance']));
if (null !== $diff) {
$native['period_start_balance'] = $converter->convert($entry['currency'], $default, today(), $item['period_start_balance']);
$native['period_end_balance'] = $converter->convert($entry['currency'], $default, today(), $item['period_end_balance']);
$native['balance_difference'] = bcsub($native['period_end_balance'], $native['period_start_balance']);
}
}
}
$account->balance = $set;
if ($converter->enabled()) {
$account->native_balance = $native;
}
}
return $account;
});
}
private function getObjectGroups(): void
{
$set = \DB::table('object_groupables')
->where('object_groupable_type', Account::class)
->whereIn('object_groupable_id', $this->collection->pluck('id')->toArray())
->distinct()
->get(['object_groupables.object_groupable_id', 'object_groupables.object_group_id'])
; ;
// get the groups:
$groupIds = $set->pluck('object_group_id')->toArray();
$groups = ObjectGroup::whereIn('id', $groupIds)->get();
/** @var ObjectGroup $group */ /** @var array $entry */
foreach ($groups as $group) {
$this->objectGroups[$group->id] = $group;
}
/** @var \stdClass $entry */
foreach ($set as $entry) { foreach ($set as $entry) {
$this->grouped[(int) $entry->object_groupable_id] = (int) $entry->object_group_id; $this->meta[(int) $entry['account_id']][$entry['name']] = (string) $entry['data'];
} if ('currency_id' === $entry['name']) {
$this->collection->transform(function (Account $account) { $this->currencies[(int) $entry['data']] = true;
$account->object_group_id = $this->grouped[$account->id] ?? null;
if (null !== $account->object_group_id) {
$account->object_group_title = $this->objectGroups[$account->object_group_id]->title;
$account->object_group_order = $this->objectGroups[$account->object_group_id]->order;
} }
}
return $account; $currencies = TransactionCurrency::whereIn('id', array_keys($this->currencies))->get();
}); foreach ($currencies as $currency) {
$this->currencies[(int) $currency->id] = $currency;
}
foreach ($this->currencies as $id => $currency) {
if (true === $currency) {
throw new FireflyException(sprintf('Currency #%d not found.', $id));
}
}
} }
public function setEnd(?Carbon $end): void public function setUserGroup(UserGroup $userGroup): void
{ {
$this->end = $end; $this->userGroup = $userGroup;
} }
public function setStart(?Carbon $start): void public function setUser(User $user): void
{ {
$this->start = $start; $this->user = $user;
$this->userGroup = $user->userGroup;
}
public function setConvertToNative(bool $convertToNative): void
{
$this->convertToNative = $convertToNative;
}
public function setNative(TransactionCurrency $native): void
{
$this->native = $native;
}
private function collectNotes(): void
{
$notes = Note::query()->whereIn('noteable_id', $this->accountIds)
->whereNotNull('notes.text')
->where('notes.text', '!=', '')
->where('noteable_type', Account::class)->get(['notes.noteable_id', 'notes.text'])->toArray()
;
foreach ($notes as $note) {
$this->notes[(int) $note['noteable_id']] = (string) $note['text'];
}
Log::debug(sprintf('Enrich with %d note(s)', count($this->notes)));
} }
} }

View File

@@ -24,6 +24,8 @@ declare(strict_types=1);
namespace FireflyIII\Support\JsonApi\Enrichments; namespace FireflyIII\Support\JsonApi\Enrichments;
use FireflyIII\Models\UserGroup;
use FireflyIII\User;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Collection; use Illuminate\Support\Collection;
@@ -31,5 +33,9 @@ interface EnrichmentInterface
{ {
public function enrich(Collection $collection): Collection; public function enrich(Collection $collection): Collection;
public function enrichSingle(Model $model): Model; public function enrichSingle(array|Model $model): array|Model;
public function setUserGroup(UserGroup $userGroup): void;
public function setUser(User $user): void;
} }

View File

@@ -0,0 +1,250 @@
<?php
/*
* TransactionGroupEnrichment.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\Support\JsonApi\Enrichments;
use Carbon\Carbon;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Models\Attachment;
use FireflyIII\Models\Location;
use FireflyIII\Models\Note;
use FireflyIII\Models\Tag;
use FireflyIII\Models\TransactionGroup;
use FireflyIII\Models\TransactionJournal;
use FireflyIII\Models\TransactionJournalMeta;
use FireflyIII\Models\UserGroup;
use FireflyIII\User;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
class TransactionGroupEnrichment implements EnrichmentInterface
{
private Collection $collection;
private array $notes;
private array $tags;
private array $locations;
private array $journalIds;
private User $user;
private UserGroup $userGroup;
private array $metaData;
private array $dateFields;
private array $attachmentCount;
public function __construct()
{
$this->notes = [];
$this->journalIds = [];
$this->tags = [];
$this->metaData = [];
$this->locations = [];
$this->attachmentCount = [];
$this->dateFields = ['interest_date', 'book_date', 'process_date', 'due_date', 'payment_date', 'invoice_date'];
}
#[\Override]
public function enrich(Collection $collection): Collection
{
Log::debug(sprintf('Now doing account enrichment for %d transaction group(s)', $collection->count()));
// prep local fields
$this->collection = $collection;
$this->collectJournalIds();
// collect first, then enrich.
$this->collectNotes();
$this->collectTags();
$this->collectMetaData();
$this->collectLocations();
$this->collectAttachmentCount();
$this->appendCollectedData();
return $this->collection;
}
#[\Override]
public function enrichSingle(array|Model $model): array|TransactionGroup
{
Log::debug(__METHOD__);
if (is_array($model)) {
$collection = new Collection([$model]);
$collection = $this->enrich($collection);
return $collection->first();
}
throw new FireflyException('Cannot enrich single model.');
}
private function collectJournalIds(): void
{
/** @var array $group */
foreach ($this->collection as $group) {
foreach ($group['transactions'] as $journal) {
$this->journalIds[] = $journal['transaction_journal_id'];
}
}
$this->journalIds = array_unique($this->journalIds);
}
public function setUserGroup(UserGroup $userGroup): void
{
$this->userGroup = $userGroup;
}
public function setUser(User $user): void
{
$this->user = $user;
$this->userGroup = $user->userGroup;
}
private function collectNotes(): void
{
$notes = Note::query()->whereIn('noteable_id', $this->journalIds)
->whereNotNull('notes.text')
->where('notes.text', '!=', '')
->where('noteable_type', TransactionJournal::class)->get(['notes.noteable_id', 'notes.text'])->toArray()
;
foreach ($notes as $note) {
$this->notes[(int) $note['noteable_id']] = (string) $note['text'];
}
Log::debug(sprintf('Enrich with %d note(s)', count($this->notes)));
}
private function collectTags(): void
{
$set = Tag::leftJoin('tag_transaction_journal', 'tags.id', '=', 'tag_transaction_journal.tag_id')
->whereIn('tag_transaction_journal.transaction_journal_id', $this->journalIds)
->get(['tag_transaction_journal.transaction_journal_id', 'tags.tag'])->toArray()
;
foreach ($set as $item) {
$journalId = $item['transaction_journal_id'];
$this->tags[$journalId] ??= [];
$this->tags[$journalId][] = $item['tag'];
}
}
private function collectMetaData(): void
{
$set = TransactionJournalMeta::whereIn('transaction_journal_id', $this->journalIds)->get(['transaction_journal_id', 'name', 'data'])->toArray();
foreach ($set as $entry) {
$name = $entry['name'];
$data = (string) $entry['data'];
if ('' === $data) {
continue;
}
if (in_array($name, $this->dateFields, true)) {
$this->metaData[$entry['transaction_journal_id']][$name] = Carbon::parse($data);
continue;
}
$this->metaData[(int) $entry['transaction_journal_id']][$name] = $data;
}
}
private function collectLocations(): void
{
$locations = Location::query()->whereIn('locatable_id', $this->journalIds)
->where('locatable_type', TransactionJournal::class)->get(['locations.locatable_id', 'locations.latitude', 'locations.longitude', 'locations.zoom_level'])->toArray()
;
foreach ($locations as $location) {
$this->locations[(int) $location['locatable_id']]
= [
'latitude' => (float) $location['latitude'],
'longitude' => (float) $location['longitude'],
'zoom_level' => (int) $location['zoom_level'],
];
}
Log::debug(sprintf('Enrich with %d locations(s)', count($this->locations)));
}
private function collectAttachmentCount(): void
{
// select count(id) as nr_of_attachments, attachable_id from attachments
// group by attachable_id
$attachments = Attachment::query()
->whereIn('attachable_id', $this->journalIds)
->where('attachable_type', TransactionJournal::class)
->groupBy('attachable_id')
->get(['attachable_id', DB::raw('COUNT(id) as nr_of_attachments')]) // @phpstan-ignore-line
->toArray()
;
foreach ($attachments as $row) {
$this->attachmentCount[(int) $row['attachable_id']] = (int) $row['nr_of_attachments'];
}
}
private function appendCollectedData(): void
{
$notes = $this->notes;
$tags = $this->tags;
$metaData = $this->metaData;
$locations = $this->locations;
$attachmentCount = $this->attachmentCount;
$this->collection = $this->collection->map(function (array $item) use ($notes, $tags, $metaData, $locations, $attachmentCount) {
foreach ($item['transactions'] as $index => $transaction) {
$journalId = (int) $transaction['transaction_journal_id'];
// attach notes if they exist:
$item['transactions'][$index]['notes'] = array_key_exists($journalId, $notes) ? $notes[$journalId] : null;
// attach tags if they exist:
$item['transactions'][$index]['tags'] = array_key_exists($journalId, $tags) ? $tags[$journalId] : [];
// attachment count
$item['transactions'][$index]['attachment_count'] = array_key_exists($journalId, $attachmentCount) ? $attachmentCount[$journalId] : 0;
// default location data
$item['transactions'][$index]['location'] = [
'latitude' => null,
'longitude' => null,
'zoom_level' => null,
];
// append meta data
$item['transactions'][$index]['meta'] = [];
$item['transactions'][$index]['meta_date'] = [];
if (array_key_exists($journalId, $metaData)) {
// loop al meta data:
foreach ($metaData[$journalId] as $name => $value) {
if (in_array($name, $this->dateFields, true)) {
$item['transactions'][$index]['meta_date'][$name] = Carbon::parse($value);
continue;
}
$item['transactions'][$index]['meta'][$name] = $value;
}
}
// append location data
if (array_key_exists($journalId, $locations)) {
$item['transactions'][$index]['location'] = $locations[$journalId];
}
}
return $item;
});
}
}

View File

@@ -51,16 +51,25 @@ class TransactionSummarizer
public function groupByCurrencyId(array $journals, string $method = 'negative'): array public function groupByCurrencyId(array $journals, string $method = 'negative'): array
{ {
Log::debug(sprintf('Now in groupByCurrencyId(array, "%s")', $method));
$array = []; $array = [];
foreach ($journals as $journal) { foreach ($journals as $journal) {
$field = 'amount'; $field = 'amount';
// grab default currency information. // grab default currency information.
$currencyId = (int) $journal['currency_id']; $currencyId = (int) $journal['currency_id'];
$currencyName = $journal['currency_name']; $currencyName = $journal['currency_name'];
$currencySymbol = $journal['currency_symbol']; $currencySymbol = $journal['currency_symbol'];
$currencyCode = $journal['currency_code']; $currencyCode = $journal['currency_code'];
$currencyDecimalPlaces = $journal['currency_decimal_places']; $currencyDecimalPlaces = $journal['currency_decimal_places'];
// prepare foreign currency info:
$foreignCurrencyId = 0;
$foreignCurrencyName = null;
$foreignCurrencySymbol = null;
$foreignCurrencyCode = null;
$foreignCurrencyDecimalPlaces = null;
if ($this->convertToNative) { if ($this->convertToNative) {
// if convert to native, use the native amount yes or no? // if convert to native, use the native amount yes or no?
$useNative = $this->default->id !== (int) $journal['currency_id']; $useNative = $this->default->id !== (int) $journal['currency_id'];
@@ -85,9 +94,19 @@ class TransactionSummarizer
} }
} }
if (!$this->convertToNative) { if (!$this->convertToNative) {
// default to the normal amount, but also Log::debug(sprintf('Journal #%d also includes foreign amount (foreign is %s)', $journal['transaction_journal_id'], $journal['foreign_currency_code']));
// use foreign amount?
$foreignCurrencyId = (int) $journal['foreign_currency_id'];
if (0 !== $foreignCurrencyId) {
$foreignCurrencyName = $journal['foreign_currency_name'];
$foreignCurrencySymbol = $journal['foreign_currency_symbol'];
$foreignCurrencyCode = $journal['foreign_currency_code'];
$foreignCurrencyDecimalPlaces = $journal['foreign_currency_decimal_places'];
}
} }
$amount = (string) ($journal[$field] ?? '0');
// first process normal amount
$amount = (string) ($journal[$field] ?? '0');
$array[$currencyId] ??= [ $array[$currencyId] ??= [
'sum' => '0', 'sum' => '0',
'currency_id' => $currencyId, 'currency_id' => $currencyId,
@@ -96,12 +115,34 @@ class TransactionSummarizer
'currency_code' => $currencyCode, 'currency_code' => $currencyCode,
'currency_decimal_places' => $currencyDecimalPlaces, 'currency_decimal_places' => $currencyDecimalPlaces,
]; ];
if ('positive' === $method) { if ('positive' === $method) {
$array[$currencyId]['sum'] = bcadd($array[$currencyId]['sum'], app('steam')->positive($amount)); $array[$currencyId]['sum'] = bcadd($array[$currencyId]['sum'], app('steam')->positive($amount));
} }
if ('negative' === $method) { if ('negative' === $method) {
$array[$currencyId]['sum'] = bcadd($array[$currencyId]['sum'], app('steam')->negative($amount)); $array[$currencyId]['sum'] = bcadd($array[$currencyId]['sum'], app('steam')->negative($amount));
} }
// then process foreign amount, if it exists.
if (0 !== $foreignCurrencyId) {
$amount = (string) ($journal['foreign_amount'] ?? '0');
$array[$foreignCurrencyId] ??= [
'sum' => '0',
'currency_id' => $foreignCurrencyId,
'currency_name' => $foreignCurrencyName,
'currency_symbol' => $foreignCurrencySymbol,
'currency_code' => $foreignCurrencyCode,
'currency_decimal_places' => $foreignCurrencyDecimalPlaces,
];
if ('positive' === $method) {
$array[$foreignCurrencyId]['sum'] = bcadd($array[$foreignCurrencyId]['sum'], app('steam')->positive($amount));
}
if ('negative' === $method) {
$array[$foreignCurrencyId]['sum'] = bcadd($array[$foreignCurrencyId]['sum'], app('steam')->negative($amount));
}
}
// $array[$currencyId]['sum'] = bcadd($array[$currencyId]['sum'], app('steam')->{$method}($amount)); // $array[$currencyId]['sum'] = bcadd($array[$currencyId]['sum'], app('steam')->{$method}($amount));
// Log::debug(sprintf('Journal #%d adds amount %s %s', $journal['transaction_journal_id'], $currencyCode, $amount)); // Log::debug(sprintf('Journal #%d adds amount %s %s', $journal['transaction_journal_id'], $currencyCode, $amount));
} }

View File

@@ -48,7 +48,7 @@ class Steam
if (!in_array($type, $list, true)) { if (!in_array($type, $list, true)) {
return null; return null;
} }
$result = $account->accountMeta->where('name', 'currency_id')->first(); $result = $account->accountMeta()->where('name', 'currency_id')->first();
if (null === $result) { if (null === $result) {
return null; return null;
} }
@@ -76,8 +76,15 @@ class Steam
$balances = []; $balances = [];
$formatted = $start->format('Y-m-d'); $formatted = $start->format('Y-m-d');
Log::debug(sprintf('finalAccountBalanceInRange: Call finalAccountBalance with date/time "%s"', $start->toIso8601String())); /*
$startBalance = $this->finalAccountBalance($account, $start); * To make sure the start balance is correct, we need to get the balance at the exact end of the previous day.
* Since we just did "startOfDay" we can do subDay()->endOfDay() to get the correct moment.
* THAT will be the start balance.
*/
$request = clone $start;
$request->subDay()->endOfDay();
Log::debug(sprintf('finalAccountBalanceInRange: Call finalAccountBalance with date/time "%s"', $request->toIso8601String()));
$startBalance = $this->finalAccountBalance($account, $request);
$nativeCurrency = app('amount')->getNativeCurrencyByUserGroup($account->user->userGroup); $nativeCurrency = app('amount')->getNativeCurrencyByUserGroup($account->user->userGroup);
$accountCurrency = $this->getAccountCurrency($account); $accountCurrency = $this->getAccountCurrency($account);
$hasCurrency = null !== $accountCurrency; $hasCurrency = null !== $accountCurrency;
@@ -141,6 +148,8 @@ class Steam
$entryCurrency = $currencies[$entry->transaction_currency_id]; $entryCurrency = $currencies[$entry->transaction_currency_id];
Log::debug(sprintf('Processing transaction(s) on moment %s', $carbon->format('Y-m-d H:i:s'))); Log::debug(sprintf('Processing transaction(s) on moment %s', $carbon->format('Y-m-d H:i:s')));
// add amount to current balance in currency code.
$currentBalance[$entryCurrency->code] ??= '0'; $currentBalance[$entryCurrency->code] ??= '0';
$currentBalance[$entryCurrency->code] = bcadd($sumOfDay, $currentBalance[$entryCurrency->code]); $currentBalance[$entryCurrency->code] = bcadd($sumOfDay, $currentBalance[$entryCurrency->code]);
@@ -149,9 +158,14 @@ class Steam
$currentBalance['balance'] = bcadd($currentBalance['balance'], $sumOfDay); $currentBalance['balance'] = bcadd($currentBalance['balance'], $sumOfDay);
} }
// if convert to native add the converted amount to "native_balance". // if convert to native add the converted amount to "native_balance".
// if there is a request to convert, convert to "native_balance" and use "balance" for whichever amount is in the native currency.
if ($convertToNative) { if ($convertToNative) {
$nativeSumOfDay = $converter->convert($entryCurrency, $nativeCurrency, $carbon, $sumOfDay); $nativeSumOfDay = $converter->convert($entryCurrency, $nativeCurrency, $carbon, $sumOfDay);
$currentBalance['native_balance'] = bcadd($currentBalance['native_balance'], $nativeSumOfDay); $currentBalance['native_balance'] = bcadd($currentBalance['native_balance'], $nativeSumOfDay);
if ($currency->id === $entryCurrency->id) {
$currentBalance['balance'] = bcadd($currentBalance['balance'], $sumOfDay);
}
} }
// just set it. // just set it.
$balances[$carbonKey] = $currentBalance; $balances[$carbonKey] = $currentBalance;
@@ -274,21 +288,33 @@ class Steam
* --> "native_balance": balance in the user's native balance, with all amounts converted to native. * --> "native_balance": balance in the user's native balance, with all amounts converted to native.
* "EUR": balance in EUR (or whatever currencies the account has balance in) * "EUR": balance in EUR (or whatever currencies the account has balance in)
*/ */
public function finalAccountBalance(Account $account, Carbon $date): array public function finalAccountBalance(Account $account, Carbon $date, ?TransactionCurrency $native = null, ?bool $convertToNative = null): array
{ {
$cache = new CacheProperties(); $cache = new CacheProperties();
$cache->addProperty($account->id); $cache->addProperty($account->id);
$cache->addProperty($date); $cache->addProperty($date);
if ($cache->has()) { if ($cache->has()) {
// Log::debug(sprintf('CACHED finalAccountBalance(#%d, %s)', $account->id, $date->format('Y-m-d H:i:s'))); Log::debug(sprintf('CACHED finalAccountBalance(#%d, %s)', $account->id, $date->format('Y-m-d H:i:s')));
return $cache->get(); return $cache->get();
} }
Log::debug(sprintf('finalAccountBalance(#%d, %s)', $account->id, $date->format('Y-m-d H:i:s'))); Log::debug(sprintf('finalAccountBalance(#%d, %s)', $account->id, $date->format('Y-m-d H:i:s')));
if (null === $convertToNative) {
$convertToNative = Amount::convertToNative($account->user);
}
if (null === $native) {
$native = Amount::getNativeCurrencyByUserGroup($account->user->userGroup);
}
// account balance thing.
$currencyPresent = isset($account->meta) && array_key_exists('currency', $account->meta) && null !== $account->meta['currency'];
if ($currencyPresent) {
$accountCurrency = $account->meta['currency'];
}
if (!$currencyPresent) {
$native = Amount::getNativeCurrencyByUserGroup($account->user->userGroup); $accountCurrency = $this->getAccountCurrency($account);
$convertToNative = Amount::convertToNative($account->user); }
$accountCurrency = $this->getAccountCurrency($account);
$hasCurrency = null !== $accountCurrency; $hasCurrency = null !== $accountCurrency;
$currency = $hasCurrency ? $accountCurrency : $native; $currency = $hasCurrency ? $accountCurrency : $native;
$return = [ $return = [
@@ -361,8 +387,8 @@ class Steam
$defaultCurrency = app('amount')->getNativeCurrency(); $defaultCurrency = app('amount')->getNativeCurrency();
if ($convertToNative) { if ($convertToNative) {
if ($defaultCurrency->id === $currency?->id) { if ($defaultCurrency->id === $currency?->id) {
Log::debug(sprintf('Unset "native_balance" and [%s] for account #%d', $defaultCurrency->code, $account->id)); Log::debug(sprintf('Unset [%s] for account #%d (no longer unset "native_balance")', $defaultCurrency->code, $account->id));
unset($set['native_balance'], $set[$defaultCurrency->code]); unset($set[$defaultCurrency->code]);
} }
// todo rethink this logic. // todo rethink this logic.
if (null !== $currency && $defaultCurrency->id !== $currency->id) { if (null !== $currency && $defaultCurrency->id !== $currency->id) {

View File

@@ -31,6 +31,7 @@ use FireflyIII\Models\TransactionCurrency;
use FireflyIII\Repositories\Account\AccountRepositoryInterface; use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use FireflyIII\Support\Facades\Amount; use FireflyIII\Support\Facades\Amount;
use FireflyIII\Support\Facades\Steam; use FireflyIII\Support\Facades\Steam;
use FireflyIII\Support\Http\Api\ExchangeRateConverter;
use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Log;
use Symfony\Component\HttpFoundation\ParameterBag; use Symfony\Component\HttpFoundation\ParameterBag;
@@ -61,26 +62,25 @@ class AccountTransformer extends AbstractTransformer
*/ */
public function transform(Account $account): array public function transform(Account $account): array
{ {
$this->repository->setUser($account->user); if (null === $account->meta) {
$account->meta = [];
}
// get account type: // get account type:
$accountType = (string) config(sprintf('firefly.shortNamesByFullName.%s', $account->full_account_type));
$fullType = $account->accountType->type; $liabilityType = (string) config(sprintf('firefly.shortLiabilityNameByFullName.%s', $account->full_account_type));
$accountType = (string) config(sprintf('firefly.shortNamesByFullName.%s', $fullType));
$liabilityType = (string) config(sprintf('firefly.shortLiabilityNameByFullName.%s', $fullType));
$liabilityType = '' === $liabilityType ? null : strtolower($liabilityType); $liabilityType = '' === $liabilityType ? null : strtolower($liabilityType);
$liabilityDirection = $this->repository->getMetaValue($account, 'liability_direction');
$convertToNative = Amount::convertToNative();
$liabilityDirection = $account->meta['liability_direction'] ?? null;
// get account role (will only work if the type is asset). // get account role (will only work if the type is asset).
$native = Amount::getNativeCurrency();
$accountRole = $this->getAccountRole($account, $accountType); $accountRole = $this->getAccountRole($account, $accountType);
// date (for balance etc.)
$date = $this->getDate(); $date = $this->getDate();
$date->endOfDay(); $date->endOfDay();
[$currencyId, $currencyCode, $currencySymbol, $decimalPlaces] = $this->getCurrency($account);
[$creditCardType, $monthlyPaymentDate] = $this->getCCInfo($account, $accountRole, $accountType); [$creditCardType, $monthlyPaymentDate] = $this->getCCInfo($account, $accountRole, $accountType);
[$openingBalance, $nativeOpeningBalance, $openingBalanceDate] = $this->getOpeningBalance($account, $accountType, $convertToNative); [$openingBalance, $nativeOpeningBalance, $openingBalanceDate] = $this->getOpeningBalance($account, $accountType);
[$interest, $interestPeriod] = $this->getInterest($account, $accountType); [$interest, $interestPeriod] = $this->getInterest($account, $accountType);
$native = $this->native; $native = $this->native;
@@ -89,17 +89,13 @@ class AccountTransformer extends AbstractTransformer
$native = null; $native = null;
} }
$openingBalance = app('steam')->bcround($openingBalance, $decimalPlaces); $decimalPlaces = (int) $account->meta['currency']?->decimal_places;
$includeNetWorth = '0' !== $this->repository->getMetaValue($account, 'include_net_worth'); $decimalPlaces = 0 === $decimalPlaces ? 2 : $decimalPlaces;
$longitude = null; $openingBalance = Steam::bcround($openingBalance, $decimalPlaces);
$latitude = null; $includeNetWorth = '0' !== ($account->meta['include_net_worth'] ?? null);
$zoomLevel = null; $longitude = $account->meta['location']['longitude'] ?? null;
$location = $this->repository->getLocation($account); $latitude = $account->meta['location']['latitude'] ?? null;
if (null !== $location) { $zoomLevel = $account->meta['location']['zoom_level'] ?? null;
$longitude = $location->longitude;
$latitude = $location->latitude;
$zoomLevel = (int) $location->zoom_level;
}
// no order for some accounts: // no order for some accounts:
$order = $account->order; $order = $account->order;
@@ -108,13 +104,13 @@ class AccountTransformer extends AbstractTransformer
} }
// balance, native balance, virtual balance, native virtual balance? // balance, native balance, virtual balance, native virtual balance?
Log::debug(sprintf('transform: Call finalAccountBalance with date/time "%s"', $date->toIso8601String())); Log::debug(sprintf('transform: Call finalAccountBalance with date/time "%s"', $date->toIso8601String()));
$finalBalance = Steam::finalAccountBalance($account, $date); $finalBalance = Steam::finalAccountBalance($account, $date, $this->native, $this->convertToNative);
if ($convertToNative) { if ($this->convertToNative) {
$finalBalance['balance'] = $finalBalance[$currencyCode] ?? '0'; $finalBalance['balance'] = $finalBalance[$account->meta['currency']?->code] ?? '0';
} }
$currentBalance = app('steam')->bcround($finalBalance['balance'] ?? '0', $decimalPlaces); $currentBalance = Steam::bcround($finalBalance['balance'] ?? '0', $decimalPlaces);
$nativeCurrentBalance = $convertToNative ? app('steam')->bcround($finalBalance['native_balance'] ?? '0', $native->decimal_places) : null; $nativeCurrentBalance = $this->convertToNative ? Steam::bcround($finalBalance['native_balance'] ?? '0', $native->decimal_places) : null;
return [ return [
'id' => (string) $account->id, 'id' => (string) $account->id,
@@ -125,10 +121,10 @@ class AccountTransformer extends AbstractTransformer
'name' => $account->name, 'name' => $account->name,
'type' => strtolower($accountType), 'type' => strtolower($accountType),
'account_role' => $accountRole, 'account_role' => $accountRole,
'currency_id' => $currencyId, 'currency_id' => $account->meta['currency_id'] ?? null,
'currency_code' => $currencyCode, 'currency_code' => $account->meta['currency']?->code,
'currency_symbol' => $currencySymbol, 'currency_symbol' => $account->meta['currency']?->symbol,
'currency_decimal_places' => $decimalPlaces, 'currency_decimal_places' => $account->meta['currency']?->decimal_places,
'native_currency_id' => null === $native ? null : (string) $native->id, 'native_currency_id' => null === $native ? null : (string) $native->id,
'native_currency_code' => $native?->code, 'native_currency_code' => $native?->code,
'native_currency_symbol' => $native?->symbol, 'native_currency_symbol' => $native?->symbol,
@@ -136,14 +132,14 @@ class AccountTransformer extends AbstractTransformer
'current_balance' => $currentBalance, 'current_balance' => $currentBalance,
'native_current_balance' => $nativeCurrentBalance, 'native_current_balance' => $nativeCurrentBalance,
'current_balance_date' => $date->toAtomString(), 'current_balance_date' => $date->toAtomString(),
'notes' => $this->repository->getNoteText($account), 'notes' => $account->meta['notes'] ?? null,
'monthly_payment_date' => $monthlyPaymentDate, 'monthly_payment_date' => $monthlyPaymentDate,
'credit_card_type' => $creditCardType, 'credit_card_type' => $creditCardType,
'account_number' => $this->repository->getMetaValue($account, 'account_number'), 'account_number' => $account->meta['account_number'] ?? null,
'iban' => '' === $account->iban ? null : $account->iban, 'iban' => '' === $account->iban ? null : $account->iban,
'bic' => $this->repository->getMetaValue($account, 'BIC'), 'bic' => $account->meta['BIC'] ?? null,
'virtual_balance' => app('steam')->bcround($account->virtual_balance, $decimalPlaces), 'virtual_balance' => Steam::bcround($account->virtual_balance, $decimalPlaces),
'native_virtual_balance' => $this->convertToNative ? app('steam')->bcround($account->native_virtual_balance, $native->decimal_places) : null, 'native_virtual_balance' => $this->convertToNative ? Steam::bcround($account->native_virtual_balance, $native->decimal_places) : null,
'opening_balance' => $openingBalance, 'opening_balance' => $openingBalance,
'native_opening_balance' => $nativeOpeningBalance, 'native_opening_balance' => $nativeOpeningBalance,
'opening_balance_date' => $openingBalanceDate, 'opening_balance_date' => $openingBalanceDate,
@@ -151,7 +147,7 @@ class AccountTransformer extends AbstractTransformer
'liability_direction' => $liabilityDirection, 'liability_direction' => $liabilityDirection,
'interest' => $interest, 'interest' => $interest,
'interest_period' => $interestPeriod, 'interest_period' => $interestPeriod,
'current_debt' => $this->repository->getMetaValue($account, 'current_debt'), 'current_debt' => $account->meta['current_debt'] ?? null,
'include_net_worth' => $includeNetWorth, 'include_net_worth' => $includeNetWorth,
'longitude' => $longitude, 'longitude' => $longitude,
'latitude' => $latitude, 'latitude' => $latitude,
@@ -159,7 +155,7 @@ class AccountTransformer extends AbstractTransformer
'links' => [ 'links' => [
[ [
'rel' => 'self', 'rel' => 'self',
'uri' => '/accounts/'.$account->id, 'uri' => sprintf('/accounts/%d', $account->id),
], ],
], ],
]; ];
@@ -167,7 +163,7 @@ class AccountTransformer extends AbstractTransformer
private function getAccountRole(Account $account, string $accountType): ?string private function getAccountRole(Account $account, string $accountType): ?string
{ {
$accountRole = $this->repository->getMetaValue($account, 'account_role'); $accountRole = $account->meta['account_role'] ?? null;
if ('asset' !== $accountType || '' === (string) $accountRole) { if ('asset' !== $accountType || '' === (string) $accountRole) {
$accountRole = null; $accountRole = null;
} }
@@ -188,29 +184,13 @@ class AccountTransformer extends AbstractTransformer
return $date; return $date;
} }
private function getCurrency(Account $account): array
{
$currency = $this->repository->getAccountCurrency($account);
// only grab native when result is null:
if (null === $currency) {
$currency = $this->native;
}
$currencyId = (string) $currency->id;
$currencyCode = $currency->code;
$decimalPlaces = $currency->decimal_places;
$currencySymbol = $currency->symbol;
return [$currencyId, $currencyCode, $currencySymbol, $decimalPlaces];
}
private function getCCInfo(Account $account, ?string $accountRole, string $accountType): array private function getCCInfo(Account $account, ?string $accountRole, string $accountType): array
{ {
$monthlyPaymentDate = null; $monthlyPaymentDate = null;
$creditCardType = null; $creditCardType = null;
if ('ccAsset' === $accountRole && 'asset' === $accountType) { if ('ccAsset' === $accountRole && 'asset' === $accountType) {
$creditCardType = $this->repository->getMetaValue($account, 'cc_type'); $creditCardType = $account->meta['cc_type'] ?? null;
$monthlyPaymentDate = $this->repository->getMetaValue($account, 'cc_monthly_payment_date'); $monthlyPaymentDate = $account->meta['cc_monthly_payment_date'] ?? null;
} }
if (null !== $monthlyPaymentDate) { if (null !== $monthlyPaymentDate) {
// try classic date: // try classic date:
@@ -229,18 +209,16 @@ class AccountTransformer extends AbstractTransformer
return [$creditCardType, $monthlyPaymentDate]; return [$creditCardType, $monthlyPaymentDate];
} }
/** private function getOpeningBalance(Account $account, string $accountType): array
* TODO refactor call to get~OpeningBalanceAmount / Date because it is a lot of queries
*/
private function getOpeningBalance(Account $account, string $accountType, bool $convertToNative): array
{ {
$openingBalance = null; $openingBalance = null;
$openingBalanceDate = null; $openingBalanceDate = null;
$nativeOpeningBalance = null; $nativeOpeningBalance = null;
if (in_array($accountType, ['asset', 'liabilities'], true)) { if (in_array($accountType, ['asset', 'liabilities'], true)) {
$openingBalance = $this->repository->getOpeningBalanceAmount($account, false); // grab from meta.
$nativeOpeningBalance = $this->repository->getOpeningBalanceAmount($account, true); $openingBalance = $account->meta['opening_balance_amount'] ?? null;
$openingBalanceDate = $this->repository->getOpeningBalanceDate($account); $nativeOpeningBalance = null;
$openingBalanceDate = $account->meta['opening_balance_date'] ?? null;
} }
if (null !== $openingBalanceDate) { if (null !== $openingBalanceDate) {
$object = Carbon::createFromFormat('Y-m-d H:i:s', $openingBalanceDate, config('app.timezone')); $object = Carbon::createFromFormat('Y-m-d H:i:s', $openingBalanceDate, config('app.timezone'));
@@ -248,6 +226,13 @@ class AccountTransformer extends AbstractTransformer
$object = today(config('app.timezone')); $object = today(config('app.timezone'));
} }
$openingBalanceDate = $object->toAtomString(); $openingBalanceDate = $object->toAtomString();
// NOW do conversion.
if ($this->convertToNative && null !== $account->meta['currency']) {
$converter = new ExchangeRateConverter();
$nativeOpeningBalance = $converter->convert($account->meta['currency'], $this->native, $object, $openingBalance);
}
} }
return [$openingBalance, $nativeOpeningBalance, $openingBalanceDate]; return [$openingBalance, $nativeOpeningBalance, $openingBalanceDate];
@@ -258,8 +243,8 @@ class AccountTransformer extends AbstractTransformer
$interest = null; $interest = null;
$interestPeriod = null; $interestPeriod = null;
if ('liabilities' === $accountType) { if ('liabilities' === $accountType) {
$interest = $this->repository->getMetaValue($account, 'interest'); $interest = $account->meta['interest'] ?? null;
$interestPeriod = $this->repository->getMetaValue($account, 'interest_period'); $interestPeriod = $account->meta['interest_period'] ?? null;
} }
return [$interest, $interestPeriod]; return [$interest, $interestPeriod];

View File

@@ -54,7 +54,7 @@ class PiggyBankEventTransformer extends AbstractTransformer
public function transform(PiggyBankEvent $event): array public function transform(PiggyBankEvent $event): array
{ {
// get account linked to piggy bank // get account linked to piggy bank
$account = $event->piggyBank->account; $account = $event->piggyBank->accounts()->first();
// set up repositories. // set up repositories.
$this->repository->setUser($account->user); $this->repository->setUser($account->user);

View File

@@ -37,6 +37,7 @@ use FireflyIII\Models\TransactionJournal;
use FireflyIII\Repositories\TransactionGroup\TransactionGroupRepositoryInterface; use FireflyIII\Repositories\TransactionGroup\TransactionGroupRepositoryInterface;
use FireflyIII\Support\NullArrayObject; use FireflyIII\Support\NullArrayObject;
use Illuminate\Support\Collection; use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Log;
/** /**
* Class TransactionGroupTransformer * Class TransactionGroupTransformer
@@ -52,6 +53,7 @@ class TransactionGroupTransformer extends AbstractTransformer
*/ */
public function __construct() public function __construct()
{ {
Log::debug('TransactionGroupTransformer constructor.');
$this->groupRepos = app(TransactionGroupRepositoryInterface::class); $this->groupRepos = app(TransactionGroupRepositoryInterface::class);
$this->metaFields = [ $this->metaFields = [
'sepa_cc', 'sepa_cc',
@@ -81,13 +83,14 @@ class TransactionGroupTransformer extends AbstractTransformer
$first = new NullArrayObject(reset($group['transactions'])); $first = new NullArrayObject(reset($group['transactions']));
return [ return [
'id' => (int) $first['transaction_group_id'], 'id' => (int) $first['transaction_group_id'],
'created_at' => $first['created_at']->toAtomString(), 'created_at' => $first['created_at']->toAtomString(),
'updated_at' => $first['updated_at']->toAtomString(), 'updated_at' => $first['updated_at']->toAtomString(),
'user' => (string) $data['user_id'], 'user' => (string) $data['user_id'],
'group_title' => $data['title'], 'user_group' => (string) $data['user_group_id'],
'transactions' => $this->transformTransactions($data), 'group_title' => $data['title'],
'links' => [ 'transactions' => $this->transformTransactions($data),
'links' => [
[ [
'rel' => 'self', 'rel' => 'self',
'uri' => '/transactions/'.$first['transaction_group_id'], 'uri' => '/transactions/'.$first['transaction_group_id'],
@@ -112,107 +115,96 @@ class TransactionGroupTransformer extends AbstractTransformer
*/ */
private function transformTransaction(array $transaction): array private function transformTransaction(array $transaction): array
{ {
$row = new NullArrayObject($transaction);
// amount: // amount:
$amount = app('steam')->positive((string) ($row['amount'] ?? '0')); $amount = app('steam')->positive((string) ($transaction['amount'] ?? '0'));
$foreignAmount = null; $foreignAmount = null;
if (null !== $row['foreign_amount'] && '' !== $row['foreign_amount'] && 0 !== bccomp('0', $row['foreign_amount'])) { if (null !== $transaction['foreign_amount'] && '' !== $transaction['foreign_amount'] && 0 !== bccomp('0', $transaction['foreign_amount'])) {
$foreignAmount = app('steam')->positive($row['foreign_amount']); $foreignAmount = app('steam')->positive($transaction['foreign_amount']);
} }
$type = $this->stringFromArray($transaction, 'transaction_type_type', TransactionTypeEnum::WITHDRAWAL->value);
$metaFieldData = $this->groupRepos->getMetaFields((int) $row['transaction_journal_id'], $this->metaFields); // must be 0 (int) or NULL
$metaDateData = $this->groupRepos->getMetaDateFields((int) $row['transaction_journal_id'], $this->metaDateFields); $recurrenceTotal = $transaction['meta']['recurrence_total'] ?? null;
$type = $this->stringFromArray($transaction, 'transaction_type_type', TransactionTypeEnum::WITHDRAWAL->value); $recurrenceTotal = null !== $recurrenceTotal ? (int) $recurrenceTotal : null;
$recurrenceCount = $transaction['meta']['recurrence_count'] ?? null;
$longitude = null; $recurrenceCount = null !== $recurrenceCount ? (int) $recurrenceCount : null;
$latitude = null;
$zoomLevel = null;
$location = $this->getLocationById((int) $row['transaction_journal_id']);
if (null !== $location) {
$longitude = $location->longitude;
$latitude = $location->latitude;
$zoomLevel = $location->zoom_level;
}
return [ return [
'user' => (string) $row['user_id'], 'user' => (string) $transaction['user_id'],
'transaction_journal_id' => (string) $row['transaction_journal_id'], 'transaction_journal_id' => $transaction['transaction_journal_id'],
'type' => strtolower($type), 'type' => strtolower($type),
'date' => $row['date']->toAtomString(), 'date' => $transaction['date']->toAtomString(),
'order' => $row['order'], 'order' => $transaction['order'],
'currency_id' => (string) $row['currency_id'], 'currency_id' => (string) $transaction['currency_id'],
'currency_code' => $row['currency_code'], 'currency_code' => $transaction['currency_code'],
'currency_name' => $row['currency_name'], 'currency_name' => $transaction['currency_name'],
'currency_symbol' => $row['currency_symbol'], 'currency_symbol' => $transaction['currency_symbol'],
'currency_decimal_places' => (int) $row['currency_decimal_places'], 'currency_decimal_places' => (int) $transaction['currency_decimal_places'],
'foreign_currency_id' => $this->stringFromArray($transaction, 'foreign_currency_id', null), 'foreign_currency_id' => $this->stringFromArray($transaction, 'foreign_currency_id', null),
'foreign_currency_code' => $row['foreign_currency_code'], 'foreign_currency_code' => $transaction['foreign_currency_code'],
'foreign_currency_symbol' => $row['foreign_currency_symbol'], 'foreign_currency_symbol' => $transaction['foreign_currency_symbol'],
'foreign_currency_decimal_places' => $row['foreign_currency_decimal_places'], 'foreign_currency_decimal_places' => $transaction['foreign_currency_decimal_places'],
'amount' => $amount, 'amount' => $amount,
'foreign_amount' => $foreignAmount, 'foreign_amount' => $foreignAmount,
'description' => $row['description'], 'description' => $transaction['description'],
'source_id' => (string) $row['source_account_id'], 'source_id' => (string) $transaction['source_account_id'],
'source_name' => $row['source_account_name'], 'source_name' => $transaction['source_account_name'],
'source_iban' => $row['source_account_iban'], 'source_iban' => $transaction['source_account_iban'],
'source_type' => $row['source_account_type'], 'source_type' => $transaction['source_account_type'],
'destination_id' => (string) $row['destination_account_id'], 'destination_id' => (string) $transaction['destination_account_id'],
'destination_name' => $row['destination_account_name'], 'destination_name' => $transaction['destination_account_name'],
'destination_iban' => $row['destination_account_iban'], 'destination_iban' => $transaction['destination_account_iban'],
'destination_type' => $row['destination_account_type'], 'destination_type' => $transaction['destination_account_type'],
'budget_id' => $this->stringFromArray($transaction, 'budget_id', null), 'budget_id' => $this->stringFromArray($transaction, 'budget_id', null),
'budget_name' => $row['budget_name'], 'budget_name' => $transaction['budget_name'],
'category_id' => $this->stringFromArray($transaction, 'category_id', null), 'category_id' => $this->stringFromArray($transaction, 'category_id', null),
'category_name' => $row['category_name'], 'category_name' => $transaction['category_name'],
'bill_id' => $this->stringFromArray($transaction, 'bill_id', null), 'bill_id' => $this->stringFromArray($transaction, 'bill_id', null),
'bill_name' => $row['bill_name'], 'bill_name' => $transaction['bill_name'],
'reconciled' => $row['reconciled'], 'reconciled' => $transaction['reconciled'],
'notes' => $this->groupRepos->getNoteText((int) $row['transaction_journal_id']), 'notes' => $transaction['notes'],
'tags' => $this->groupRepos->getTags((int) $row['transaction_journal_id']), 'tags' => $transaction['tags'],
'internal_reference' => $metaFieldData['internal_reference'], 'internal_reference' => $transaction['meta']['internal_reference'] ?? null,
'external_id' => $metaFieldData['external_id'], 'external_id' => $transaction['meta']['external_id'] ?? null,
'original_source' => $metaFieldData['original_source'], 'original_source' => $transaction['meta']['original_source'] ?? null,
'recurrence_id' => $this->stringFromArray($metaFieldData->getArrayCopy(), 'recurrence_id', null), 'recurrence_id' => $transaction['meta']['recurrence_id'] ?? null,
'recurrence_total' => $this->integerFromArray($metaFieldData->getArrayCopy(), 'recurrence_total'), 'recurrence_total' => $recurrenceTotal,
'recurrence_count' => $this->integerFromArray($metaFieldData->getArrayCopy(), 'recurrence_count'), 'recurrence_count' => $recurrenceCount,
'bunq_payment_id' => $metaFieldData['bunq_payment_id'], 'bunq_payment_id' => $transaction['meta']['bunq_payment_id'] ?? null,
'external_url' => $metaFieldData['external_url'], 'external_url' => $transaction['meta']['external_url'] ?? null,
'import_hash_v2' => $metaFieldData['import_hash_v2'], 'import_hash_v2' => $transaction['meta']['import_hash_v2'] ?? null,
'sepa_cc' => $metaFieldData['sepa_cc'], 'sepa_cc' => $transaction['meta']['sepa_cc'] ?? null,
'sepa_ct_op' => $metaFieldData['sepa_ct_op'], 'sepa_ct_op' => $transaction['meta']['sepa_ct_op'] ?? null,
'sepa_ct_id' => $metaFieldData['sepa_ct_id'], 'sepa_ct_id' => $transaction['meta']['sepa_ct_id'] ?? null,
'sepa_db' => $metaFieldData['sepa_db'], 'sepa_db' => $transaction['meta']['sepa_db'] ?? null,
'sepa_country' => $metaFieldData['sepa_country'], 'sepa_country' => $transaction['meta']['sepa_country'] ?? null,
'sepa_ep' => $metaFieldData['sepa_ep'], 'sepa_ep' => $transaction['meta']['sepa_ep'] ?? null,
'sepa_ci' => $metaFieldData['sepa_ci'], 'sepa_ci' => $transaction['meta']['sepa_ci'] ?? null,
'sepa_batch_id' => $metaFieldData['sepa_batch_id'], 'sepa_batch_id' => $transaction['meta']['sepa_batch_id'] ?? null,
'interest_date' => $this->dateFromArray($metaDateData, 'interest_date'),
'book_date' => $this->dateFromArray($metaDateData, 'book_date'),
'process_date' => $this->dateFromArray($metaDateData, 'process_date'),
'due_date' => $this->dateFromArray($metaDateData, 'due_date'),
'payment_date' => $this->dateFromArray($metaDateData, 'payment_date'),
'invoice_date' => $this->dateFromArray($metaDateData, 'invoice_date'),
'interest_date' => $transaction['meta_date']['interest_date'] ?? null,
'book_date' => $transaction['meta_date']['book_date'] ?? null,
'process_date' => $transaction['meta_date']['process_date'] ?? null,
'due_date' => $transaction['meta_date']['due_date'] ?? null,
'payment_date' => $transaction['meta_date']['payment_date'] ?? null,
'invoice_date' => $transaction['meta_date']['invoice_date'] ?? null,
// location data // location data
'longitude' => $longitude, 'longitude' => $transaction['location']['longitude'],
'latitude' => $latitude, 'latitude' => $transaction['location']['latitude'],
'zoom_level' => $zoomLevel, 'zoom_level' => $transaction['location']['zoom_level'],
'has_attachments' => $transaction['attachment_count'] > 0,
'has_attachments' => $this->hasAttachments((int) $row['transaction_journal_id']),
]; ];
} }
@@ -239,40 +231,12 @@ class TransactionGroupTransformer extends AbstractTransformer
return null; return null;
} }
private function getLocationById(int $journalId): ?Location
{
return $this->groupRepos->getLocation($journalId);
}
private function getLocation(TransactionJournal $journal): ?Location private function getLocation(TransactionJournal $journal): ?Location
{ {
/** @var null|Location */ /** @var null|Location */
return $journal->locations()->first(); return $journal->locations()->first();
} }
private function integerFromArray(array $array, string $key): ?int
{
if (array_key_exists($key, $array)) {
return (int) $array[$key];
}
return null;
}
private function dateFromArray(NullArrayObject $object, string $key): ?string
{
if (null === $object[$key]) {
return null;
}
return $object[$key]->toAtomString();
}
private function hasAttachments(int $journalId): bool
{
return $this->groupRepos->countAttachments($journalId) > 0;
}
/** /**
* @throws FireflyException * @throws FireflyException
*/ */

View File

@@ -3,6 +3,33 @@
All notable changes to this project will be documented in this file. All notable changes to this project will be documented in this file.
This project adheres to [Semantic Versioning](http://semver.org/). This project adheres to [Semantic Versioning](http://semver.org/).
## 6.2.7 - 2025-02-19
### Changed
- Optimised Account and Transaction API endpoints, should be a lot faster
- Optimized account deletion, should be a lot faster
### Fixed
- [Issue 9803](https://github.com/firefly-iii/firefly-iii/issues/9803) (Left to spend - All negativ after update.) reported by @nedsined
- [Issue 9835](https://github.com/firefly-iii/firefly-iii/issues/9835) (Failed to create transaction in recurring transactions on 6.2.6) reported by @hhl5350
- [Issue 9842](https://github.com/firefly-iii/firefly-iii/issues/9842) (Net worth on dashboard does not go up to the end of month for the current month) reported by @standingduck3
- [Issue 9848](https://github.com/firefly-iii/firefly-iii/issues/9848) (Failed to export accounts data) reported by @Jaeger87
- [Issue 9855](https://github.com/firefly-iii/firefly-iii/issues/9855) (Demo Website not working) reported by @xfarrow
## 6.2.6 - 2025-02-13
### Fixed
- [Issue 9797](https://github.com/firefly-iii/firefly-iii/issues/9797) (All account charts show a horizontal line) reported by @avee87
- [Issue 9806](https://github.com/firefly-iii/firefly-iii/issues/9806) (Exchange Rates table fails to load when language is not English) reported by @polter-rnd
- [Issue 9807](https://github.com/firefly-iii/firefly-iii/issues/9807) (Start Date of Reconciliation Period Incorrectly Excludes Transactions for That Day) reported by @pwschattenberg
- [Issue 9808](https://github.com/firefly-iii/firefly-iii/issues/9808) (Default financial report line graph shows a different balance than the text) reported by @mtaygur
- [Issue 9810](https://github.com/firefly-iii/firefly-iii/issues/9810) (Foreign amount not taken into consideration for budget spent/leaving) reported by @M4xS0ch
- [Issue 9821](https://github.com/firefly-iii/firefly-iii/issues/9821) (piggy events api 500 error) reported by @4e868df3
- [Issue 9826](https://github.com/firefly-iii/firefly-iii/issues/9826) (Wrong account balance) reported by @fabienfitoussi
## 6.2.5 - 2025-02-08 ## 6.2.5 - 2025-02-08
### Fixed ### Fixed

275
composer.lock generated
View File

@@ -1874,16 +1874,16 @@
}, },
{ {
"name": "laravel/framework", "name": "laravel/framework",
"version": "v11.41.3", "version": "v11.43.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/laravel/framework.git", "url": "https://github.com/laravel/framework.git",
"reference": "3ef433d5865f30a19b6b1be247586068399b59cc" "reference": "70760d976486310b11d8e487e873077db069e77a"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/laravel/framework/zipball/3ef433d5865f30a19b6b1be247586068399b59cc", "url": "https://api.github.com/repos/laravel/framework/zipball/70760d976486310b11d8e487e873077db069e77a",
"reference": "3ef433d5865f30a19b6b1be247586068399b59cc", "reference": "70760d976486310b11d8e487e873077db069e77a",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -1991,11 +1991,11 @@
"league/flysystem-read-only": "^3.25.1", "league/flysystem-read-only": "^3.25.1",
"league/flysystem-sftp-v3": "^3.25.1", "league/flysystem-sftp-v3": "^3.25.1",
"mockery/mockery": "^1.6.10", "mockery/mockery": "^1.6.10",
"orchestra/testbench-core": "^9.6", "orchestra/testbench-core": "^9.9.4",
"pda/pheanstalk": "^5.0.6", "pda/pheanstalk": "^5.0.6",
"php-http/discovery": "^1.15", "php-http/discovery": "^1.15",
"phpstan/phpstan": "^1.11.5", "phpstan/phpstan": "^2.0",
"phpunit/phpunit": "^10.5.35|^11.3.6", "phpunit/phpunit": "^10.5.35|^11.3.6|^12.0.1",
"predis/predis": "^2.3", "predis/predis": "^2.3",
"resend/resend-php": "^0.10.0", "resend/resend-php": "^0.10.0",
"symfony/cache": "^7.0.3", "symfony/cache": "^7.0.3",
@@ -2027,7 +2027,7 @@
"mockery/mockery": "Required to use mocking (^1.6).", "mockery/mockery": "Required to use mocking (^1.6).",
"pda/pheanstalk": "Required to use the beanstalk queue driver (^5.0).", "pda/pheanstalk": "Required to use the beanstalk queue driver (^5.0).",
"php-http/discovery": "Required to use PSR-7 bridging features (^1.15).", "php-http/discovery": "Required to use PSR-7 bridging features (^1.15).",
"phpunit/phpunit": "Required to use assertions and run tests (^10.5|^11.0).", "phpunit/phpunit": "Required to use assertions and run tests (^10.5.35|^11.3.6|^12.0.1).",
"predis/predis": "Required to use the predis connector (^2.3).", "predis/predis": "Required to use the predis connector (^2.3).",
"psr/http-message": "Required to allow Storage::put to accept a StreamInterface (^1.0).", "psr/http-message": "Required to allow Storage::put to accept a StreamInterface (^1.0).",
"pusher/pusher-php-server": "Required to use the Pusher broadcast driver (^6.0|^7.0).", "pusher/pusher-php-server": "Required to use the Pusher broadcast driver (^6.0|^7.0).",
@@ -2085,7 +2085,7 @@
"issues": "https://github.com/laravel/framework/issues", "issues": "https://github.com/laravel/framework/issues",
"source": "https://github.com/laravel/framework" "source": "https://github.com/laravel/framework"
}, },
"time": "2025-01-30T13:25:22+00:00" "time": "2025-02-18T15:37:56+00:00"
}, },
{ {
"name": "laravel/passport", "name": "laravel/passport",
@@ -2165,16 +2165,16 @@
}, },
{ {
"name": "laravel/prompts", "name": "laravel/prompts",
"version": "v0.3.4", "version": "v0.3.5",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/laravel/prompts.git", "url": "https://github.com/laravel/prompts.git",
"reference": "abeaa2ba4294247d5409490d1ca1bc6248087011" "reference": "57b8f7efe40333cdb925700891c7d7465325d3b1"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/laravel/prompts/zipball/abeaa2ba4294247d5409490d1ca1bc6248087011", "url": "https://api.github.com/repos/laravel/prompts/zipball/57b8f7efe40333cdb925700891c7d7465325d3b1",
"reference": "abeaa2ba4294247d5409490d1ca1bc6248087011", "reference": "57b8f7efe40333cdb925700891c7d7465325d3b1",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -2218,9 +2218,9 @@
"description": "Add beautiful and user-friendly forms to your command-line applications.", "description": "Add beautiful and user-friendly forms to your command-line applications.",
"support": { "support": {
"issues": "https://github.com/laravel/prompts/issues", "issues": "https://github.com/laravel/prompts/issues",
"source": "https://github.com/laravel/prompts/tree/v0.3.4" "source": "https://github.com/laravel/prompts/tree/v0.3.5"
}, },
"time": "2025-01-24T15:41:01+00:00" "time": "2025-02-11T13:34:40+00:00"
}, },
{ {
"name": "laravel/sanctum", "name": "laravel/sanctum",
@@ -2288,16 +2288,16 @@
}, },
{ {
"name": "laravel/serializable-closure", "name": "laravel/serializable-closure",
"version": "v2.0.2", "version": "v2.0.3",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/laravel/serializable-closure.git", "url": "https://github.com/laravel/serializable-closure.git",
"reference": "2e1a362527783bcab6c316aad51bf36c5513ae44" "reference": "f379c13663245f7aa4512a7869f62eb14095f23f"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/laravel/serializable-closure/zipball/2e1a362527783bcab6c316aad51bf36c5513ae44", "url": "https://api.github.com/repos/laravel/serializable-closure/zipball/f379c13663245f7aa4512a7869f62eb14095f23f",
"reference": "2e1a362527783bcab6c316aad51bf36c5513ae44", "reference": "f379c13663245f7aa4512a7869f62eb14095f23f",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -2345,7 +2345,7 @@
"issues": "https://github.com/laravel/serializable-closure/issues", "issues": "https://github.com/laravel/serializable-closure/issues",
"source": "https://github.com/laravel/serializable-closure" "source": "https://github.com/laravel/serializable-closure"
}, },
"time": "2025-01-24T15:42:37+00:00" "time": "2025-02-11T15:03:05+00:00"
}, },
{ {
"name": "laravel/slack-notification-channel", "name": "laravel/slack-notification-channel",
@@ -3076,16 +3076,16 @@
}, },
{ {
"name": "league/fractal", "name": "league/fractal",
"version": "0.20.1", "version": "0.20.2",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/thephpleague/fractal.git", "url": "https://github.com/thephpleague/fractal.git",
"reference": "8b9d39b67624db9195c06f9c1ffd0355151eaf62" "reference": "573ca2e0e348a7fe573a3e8fbc29a6588ece8c4e"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/thephpleague/fractal/zipball/8b9d39b67624db9195c06f9c1ffd0355151eaf62", "url": "https://api.github.com/repos/thephpleague/fractal/zipball/573ca2e0e348a7fe573a3e8fbc29a6588ece8c4e",
"reference": "8b9d39b67624db9195c06f9c1ffd0355151eaf62", "reference": "573ca2e0e348a7fe573a3e8fbc29a6588ece8c4e",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -3094,18 +3094,18 @@
"require-dev": { "require-dev": {
"doctrine/orm": "^2.5", "doctrine/orm": "^2.5",
"illuminate/contracts": "~5.0", "illuminate/contracts": "~5.0",
"laminas/laminas-paginator": "~2.12",
"mockery/mockery": "^1.3", "mockery/mockery": "^1.3",
"pagerfanta/pagerfanta": "~1.0.0", "pagerfanta/pagerfanta": "~1.0.0|~4.0.0",
"phpstan/phpstan": "^1.4", "phpstan/phpstan": "^1.4",
"phpunit/phpunit": "^9.5", "phpunit/phpunit": "^9.5",
"squizlabs/php_codesniffer": "~3.4", "squizlabs/php_codesniffer": "~3.4",
"vimeo/psalm": "^4.22", "vimeo/psalm": "^4.30"
"zendframework/zend-paginator": "~2.3"
}, },
"suggest": { "suggest": {
"illuminate/pagination": "The Illuminate Pagination component.", "illuminate/pagination": "The Illuminate Pagination component.",
"pagerfanta/pagerfanta": "Pagerfanta Paginator", "laminas/laminas-paginator": "Laminas Framework Paginator",
"zendframework/zend-paginator": "Zend Framework Paginator" "pagerfanta/pagerfanta": "Pagerfanta Paginator"
}, },
"type": "library", "type": "library",
"extra": { "extra": {
@@ -3140,9 +3140,9 @@
], ],
"support": { "support": {
"issues": "https://github.com/thephpleague/fractal/issues", "issues": "https://github.com/thephpleague/fractal/issues",
"source": "https://github.com/thephpleague/fractal/tree/0.20.1" "source": "https://github.com/thephpleague/fractal/tree/0.20.2"
}, },
"time": "2022-04-11T12:47:17+00:00" "time": "2025-02-14T21:33:14+00:00"
}, },
{ {
"name": "league/mime-type-detection", "name": "league/mime-type-detection",
@@ -3703,16 +3703,16 @@
}, },
{ {
"name": "nesbot/carbon", "name": "nesbot/carbon",
"version": "3.8.4", "version": "3.8.5",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/CarbonPHP/carbon.git", "url": "https://github.com/CarbonPHP/carbon.git",
"reference": "129700ed449b1f02d70272d2ac802357c8c30c58" "reference": "b1a53a27898639579a67de42e8ced5d5386aa9a4"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/CarbonPHP/carbon/zipball/129700ed449b1f02d70272d2ac802357c8c30c58", "url": "https://api.github.com/repos/CarbonPHP/carbon/zipball/b1a53a27898639579a67de42e8ced5d5386aa9a4",
"reference": "129700ed449b1f02d70272d2ac802357c8c30c58", "reference": "b1a53a27898639579a67de42e8ced5d5386aa9a4",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -3788,8 +3788,8 @@
], ],
"support": { "support": {
"docs": "https://carbon.nesbot.com/docs", "docs": "https://carbon.nesbot.com/docs",
"issues": "https://github.com/briannesbitt/Carbon/issues", "issues": "https://github.com/CarbonPHP/carbon/issues",
"source": "https://github.com/briannesbitt/Carbon" "source": "https://github.com/CarbonPHP/carbon"
}, },
"funding": [ "funding": [
{ {
@@ -3805,7 +3805,7 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2024-12-27T09:25:35+00:00" "time": "2025-02-11T16:28:45+00:00"
}, },
{ {
"name": "nette/schema", "name": "nette/schema",
@@ -5970,30 +5970,30 @@
}, },
{ {
"name": "spatie/error-solutions", "name": "spatie/error-solutions",
"version": "1.1.2", "version": "1.1.3",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/spatie/error-solutions.git", "url": "https://github.com/spatie/error-solutions.git",
"reference": "d239a65235a1eb128dfa0a4e4c4ef032ea11b541" "reference": "e495d7178ca524f2dd0fe6a1d99a1e608e1c9936"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/spatie/error-solutions/zipball/d239a65235a1eb128dfa0a4e4c4ef032ea11b541", "url": "https://api.github.com/repos/spatie/error-solutions/zipball/e495d7178ca524f2dd0fe6a1d99a1e608e1c9936",
"reference": "d239a65235a1eb128dfa0a4e4c4ef032ea11b541", "reference": "e495d7178ca524f2dd0fe6a1d99a1e608e1c9936",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"php": "^8.0" "php": "^8.0"
}, },
"require-dev": { "require-dev": {
"illuminate/broadcasting": "^10.0|^11.0", "illuminate/broadcasting": "^10.0|^11.0|^12.0",
"illuminate/cache": "^10.0|^11.0", "illuminate/cache": "^10.0|^11.0|^12.0",
"illuminate/support": "^10.0|^11.0", "illuminate/support": "^10.0|^11.0|^12.0",
"livewire/livewire": "^2.11|^3.3.5", "livewire/livewire": "^2.11|^3.5.20",
"openai-php/client": "^0.10.1", "openai-php/client": "^0.10.1",
"orchestra/testbench": "^7.0|8.22.3|^9.0", "orchestra/testbench": "8.22.3|^9.0|^10.0",
"pestphp/pest": "^2.20", "pestphp/pest": "^2.20|^3.0",
"phpstan/phpstan": "^1.11", "phpstan/phpstan": "^2.1",
"psr/simple-cache": "^3.0", "psr/simple-cache": "^3.0",
"psr/simple-cache-implementation": "^3.0", "psr/simple-cache-implementation": "^3.0",
"spatie/ray": "^1.28", "spatie/ray": "^1.28",
@@ -6032,7 +6032,7 @@
], ],
"support": { "support": {
"issues": "https://github.com/spatie/error-solutions/issues", "issues": "https://github.com/spatie/error-solutions/issues",
"source": "https://github.com/spatie/error-solutions/tree/1.1.2" "source": "https://github.com/spatie/error-solutions/tree/1.1.3"
}, },
"funding": [ "funding": [
{ {
@@ -6040,24 +6040,24 @@
"type": "github" "type": "github"
} }
], ],
"time": "2024-12-11T09:51:56+00:00" "time": "2025-02-14T12:29:50+00:00"
}, },
{ {
"name": "spatie/flare-client-php", "name": "spatie/flare-client-php",
"version": "1.10.0", "version": "1.10.1",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/spatie/flare-client-php.git", "url": "https://github.com/spatie/flare-client-php.git",
"reference": "140a42b2c5d59ac4ecf8f5b493386a4f2eb28272" "reference": "bf1716eb98bd689451b071548ae9e70738dce62f"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/spatie/flare-client-php/zipball/140a42b2c5d59ac4ecf8f5b493386a4f2eb28272", "url": "https://api.github.com/repos/spatie/flare-client-php/zipball/bf1716eb98bd689451b071548ae9e70738dce62f",
"reference": "140a42b2c5d59ac4ecf8f5b493386a4f2eb28272", "reference": "bf1716eb98bd689451b071548ae9e70738dce62f",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"illuminate/pipeline": "^8.0|^9.0|^10.0|^11.0", "illuminate/pipeline": "^8.0|^9.0|^10.0|^11.0|^12.0",
"php": "^8.0", "php": "^8.0",
"spatie/backtrace": "^1.6.1", "spatie/backtrace": "^1.6.1",
"symfony/http-foundation": "^5.2|^6.0|^7.0", "symfony/http-foundation": "^5.2|^6.0|^7.0",
@@ -6101,7 +6101,7 @@
], ],
"support": { "support": {
"issues": "https://github.com/spatie/flare-client-php/issues", "issues": "https://github.com/spatie/flare-client-php/issues",
"source": "https://github.com/spatie/flare-client-php/tree/1.10.0" "source": "https://github.com/spatie/flare-client-php/tree/1.10.1"
}, },
"funding": [ "funding": [
{ {
@@ -6109,7 +6109,7 @@
"type": "github" "type": "github"
} }
], ],
"time": "2024-12-02T14:30:06+00:00" "time": "2025-02-14T13:42:06+00:00"
}, },
{ {
"name": "spatie/ignition", "name": "spatie/ignition",
@@ -6196,27 +6196,27 @@
}, },
{ {
"name": "spatie/laravel-html", "name": "spatie/laravel-html",
"version": "3.11.2", "version": "3.11.3",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/spatie/laravel-html.git", "url": "https://github.com/spatie/laravel-html.git",
"reference": "248508f3ed50e6538707fc54a4b3b23fb53e8045" "reference": "b1bb159bd9845b1ff02b8f945ecd583d93353d06"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/spatie/laravel-html/zipball/248508f3ed50e6538707fc54a4b3b23fb53e8045", "url": "https://api.github.com/repos/spatie/laravel-html/zipball/b1bb159bd9845b1ff02b8f945ecd583d93353d06",
"reference": "248508f3ed50e6538707fc54a4b3b23fb53e8045", "reference": "b1bb159bd9845b1ff02b8f945ecd583d93353d06",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"illuminate/http": "^10.0|^11.0", "illuminate/http": "^10.0|^11.0|^12.0",
"illuminate/support": "^10.0|^11.0", "illuminate/support": "^10.0|^11.0|^12.0",
"php": "^8.2" "php": "^8.2"
}, },
"require-dev": { "require-dev": {
"mockery/mockery": "^1.3", "mockery/mockery": "^1.3",
"orchestra/testbench": "^8.0|^9.0", "orchestra/testbench": "^8.0|^9.0|^10.0",
"pestphp/pest": "^2.34" "pestphp/pest": "^2.34|^3.7"
}, },
"type": "library", "type": "library",
"extra": { "extra": {
@@ -6262,7 +6262,7 @@
"spatie" "spatie"
], ],
"support": { "support": {
"source": "https://github.com/spatie/laravel-html/tree/3.11.2" "source": "https://github.com/spatie/laravel-html/tree/3.11.3"
}, },
"funding": [ "funding": [
{ {
@@ -6270,7 +6270,7 @@
"type": "custom" "type": "custom"
} }
], ],
"time": "2025-02-05T08:27:24+00:00" "time": "2025-02-17T09:59:20+00:00"
}, },
{ {
"name": "spatie/laravel-ignition", "name": "spatie/laravel-ignition",
@@ -8455,82 +8455,6 @@
], ],
"time": "2024-09-09T11:45:10+00:00" "time": "2024-09-09T11:45:10+00:00"
}, },
{
"name": "symfony/polyfill-php81",
"version": "v1.31.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-php81.git",
"reference": "4a4cfc2d253c21a5ad0e53071df248ed48c6ce5c"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-php81/zipball/4a4cfc2d253c21a5ad0e53071df248ed48c6ce5c",
"reference": "4a4cfc2d253c21a5ad0e53071df248ed48c6ce5c",
"shasum": ""
},
"require": {
"php": ">=7.2"
},
"type": "library",
"extra": {
"thanks": {
"url": "https://github.com/symfony/polyfill",
"name": "symfony/polyfill"
}
},
"autoload": {
"files": [
"bootstrap.php"
],
"psr-4": {
"Symfony\\Polyfill\\Php81\\": ""
},
"classmap": [
"Resources/stubs"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Nicolas Grekas",
"email": "p@tchwork.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony polyfill backporting some PHP 8.1+ features to lower PHP versions",
"homepage": "https://symfony.com",
"keywords": [
"compatibility",
"polyfill",
"portable",
"shim"
],
"support": {
"source": "https://github.com/symfony/polyfill-php81/tree/v1.31.0"
},
"funding": [
{
"url": "https://symfony.com/sponsor",
"type": "custom"
},
{
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
"time": "2024-09-09T11:45:10+00:00"
},
{ {
"name": "symfony/polyfill-php83", "name": "symfony/polyfill-php83",
"version": "v1.31.0", "version": "v1.31.0",
@@ -9683,24 +9607,23 @@
}, },
{ {
"name": "twig/twig", "name": "twig/twig",
"version": "v3.19.0", "version": "v3.20.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/twigphp/Twig.git", "url": "https://github.com/twigphp/Twig.git",
"reference": "d4f8c2b86374f08efc859323dbcd95c590f7124e" "reference": "3468920399451a384bef53cf7996965f7cd40183"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/twigphp/Twig/zipball/d4f8c2b86374f08efc859323dbcd95c590f7124e", "url": "https://api.github.com/repos/twigphp/Twig/zipball/3468920399451a384bef53cf7996965f7cd40183",
"reference": "d4f8c2b86374f08efc859323dbcd95c590f7124e", "reference": "3468920399451a384bef53cf7996965f7cd40183",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"php": ">=8.0.2", "php": ">=8.1.0",
"symfony/deprecation-contracts": "^2.5|^3", "symfony/deprecation-contracts": "^2.5|^3",
"symfony/polyfill-ctype": "^1.8", "symfony/polyfill-ctype": "^1.8",
"symfony/polyfill-mbstring": "^1.3", "symfony/polyfill-mbstring": "^1.3"
"symfony/polyfill-php81": "^1.29"
}, },
"require-dev": { "require-dev": {
"phpstan/phpstan": "^2.0", "phpstan/phpstan": "^2.0",
@@ -9747,7 +9670,7 @@
], ],
"support": { "support": {
"issues": "https://github.com/twigphp/Twig/issues", "issues": "https://github.com/twigphp/Twig/issues",
"source": "https://github.com/twigphp/Twig/tree/v3.19.0" "source": "https://github.com/twigphp/Twig/tree/v3.20.0"
}, },
"funding": [ "funding": [
{ {
@@ -9759,7 +9682,7 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2025-01-29T07:06:14+00:00" "time": "2025-02-13T08:34:43+00:00"
}, },
{ {
"name": "verifiedjoseph/ntfy-php-library", "name": "verifiedjoseph/ntfy-php-library",
@@ -10822,16 +10745,16 @@
}, },
{ {
"name": "maximebf/debugbar", "name": "maximebf/debugbar",
"version": "v1.23.5", "version": "v1.23.6",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/php-debugbar/php-debugbar.git", "url": "https://github.com/php-debugbar/php-debugbar.git",
"reference": "eeabd61a1f19ba5dcd5ac4585a477130ee03ce25" "reference": "4b3d5f1afe09a7db5a9d3282890f49f6176d6542"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/php-debugbar/php-debugbar/zipball/eeabd61a1f19ba5dcd5ac4585a477130ee03ce25", "url": "https://api.github.com/repos/php-debugbar/php-debugbar/zipball/4b3d5f1afe09a7db5a9d3282890f49f6176d6542",
"reference": "eeabd61a1f19ba5dcd5ac4585a477130ee03ce25", "reference": "4b3d5f1afe09a7db5a9d3282890f49f6176d6542",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -10884,9 +10807,9 @@
], ],
"support": { "support": {
"issues": "https://github.com/php-debugbar/php-debugbar/issues", "issues": "https://github.com/php-debugbar/php-debugbar/issues",
"source": "https://github.com/php-debugbar/php-debugbar/tree/v1.23.5" "source": "https://github.com/php-debugbar/php-debugbar/tree/v1.23.6"
}, },
"time": "2024-12-15T19:20:42+00:00" "time": "2025-02-13T12:22:36+00:00"
}, },
{ {
"name": "mockery/mockery", "name": "mockery/mockery",
@@ -10973,16 +10896,16 @@
}, },
{ {
"name": "myclabs/deep-copy", "name": "myclabs/deep-copy",
"version": "1.12.1", "version": "1.13.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/myclabs/DeepCopy.git", "url": "https://github.com/myclabs/DeepCopy.git",
"reference": "123267b2c49fbf30d78a7b2d333f6be754b94845" "reference": "024473a478be9df5fdaca2c793f2232fe788e414"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/123267b2c49fbf30d78a7b2d333f6be754b94845", "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/024473a478be9df5fdaca2c793f2232fe788e414",
"reference": "123267b2c49fbf30d78a7b2d333f6be754b94845", "reference": "024473a478be9df5fdaca2c793f2232fe788e414",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -11021,7 +10944,7 @@
], ],
"support": { "support": {
"issues": "https://github.com/myclabs/DeepCopy/issues", "issues": "https://github.com/myclabs/DeepCopy/issues",
"source": "https://github.com/myclabs/DeepCopy/tree/1.12.1" "source": "https://github.com/myclabs/DeepCopy/tree/1.13.0"
}, },
"funding": [ "funding": [
{ {
@@ -11029,7 +10952,7 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2024-11-08T17:47:46+00:00" "time": "2025-02-12T12:17:51+00:00"
}, },
{ {
"name": "nikic/php-parser", "name": "nikic/php-parser",
@@ -11344,16 +11267,16 @@
}, },
{ {
"name": "phpstan/phpstan", "name": "phpstan/phpstan",
"version": "2.1.4", "version": "2.1.5",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/phpstan/phpstan.git", "url": "https://github.com/phpstan/phpstan.git",
"reference": "8f99e18eb775dbaf6460c95fa0b65312da9c746a" "reference": "451b17f9665481ee502adc39be987cb71067ece2"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/8f99e18eb775dbaf6460c95fa0b65312da9c746a", "url": "https://api.github.com/repos/phpstan/phpstan/zipball/451b17f9665481ee502adc39be987cb71067ece2",
"reference": "8f99e18eb775dbaf6460c95fa0b65312da9c746a", "reference": "451b17f9665481ee502adc39be987cb71067ece2",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -11398,7 +11321,7 @@
"type": "github" "type": "github"
} }
], ],
"time": "2025-02-10T08:25:21+00:00" "time": "2025-02-13T12:49:56+00:00"
}, },
{ {
"name": "phpstan/phpstan-deprecation-rules", "name": "phpstan/phpstan-deprecation-rules",
@@ -11820,16 +11743,16 @@
}, },
{ {
"name": "phpunit/phpunit", "name": "phpunit/phpunit",
"version": "11.5.7", "version": "11.5.8",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/sebastianbergmann/phpunit.git", "url": "https://github.com/sebastianbergmann/phpunit.git",
"reference": "e1cb706f019e2547039ca2c839898cd5f557ee5d" "reference": "c9bd61aab12f0fc5e82ecfe621ff518a1d1f1049"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/e1cb706f019e2547039ca2c839898cd5f557ee5d", "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/c9bd61aab12f0fc5e82ecfe621ff518a1d1f1049",
"reference": "e1cb706f019e2547039ca2c839898cd5f557ee5d", "reference": "c9bd61aab12f0fc5e82ecfe621ff518a1d1f1049",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -11901,7 +11824,7 @@
"support": { "support": {
"issues": "https://github.com/sebastianbergmann/phpunit/issues", "issues": "https://github.com/sebastianbergmann/phpunit/issues",
"security": "https://github.com/sebastianbergmann/phpunit/security/policy", "security": "https://github.com/sebastianbergmann/phpunit/security/policy",
"source": "https://github.com/sebastianbergmann/phpunit/tree/11.5.7" "source": "https://github.com/sebastianbergmann/phpunit/tree/11.5.8"
}, },
"funding": [ "funding": [
{ {
@@ -11917,7 +11840,7 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2025-02-06T16:10:05+00:00" "time": "2025-02-18T06:26:59+00:00"
}, },
{ {
"name": "sebastian/cli-parser", "name": "sebastian/cli-parser",

View File

@@ -81,7 +81,7 @@ return [
'running_balance_column' => env('USE_RUNNING_BALANCE', false), 'running_balance_column' => env('USE_RUNNING_BALANCE', false),
// see cer.php for exchange rates feature flag. // see cer.php for exchange rates feature flag.
], ],
'version' => 'develop/2025-02-11', 'version' => 'develop/2025-02-19',
'api_version' => '2.1.0', // field is no longer used. 'api_version' => '2.1.0', // field is no longer used.
'db_version' => 25, 'db_version' => 25,
@@ -176,7 +176,7 @@ return [
], ],
// administration specific preferences // administration specific preferences
'admin_specific_prefs' => ['frontpageAccounts', 'lastActivity'], 'admin_specific_prefs' => [],
// default user-related values // default user-related values
'darkMode' => 'browser', 'darkMode' => 'browser',

441
package-lock.json generated
View File

@@ -89,23 +89,22 @@
} }
}, },
"node_modules/@babel/core": { "node_modules/@babel/core": {
"version": "7.26.8", "version": "7.26.9",
"resolved": "https://registry.npmjs.org/@babel/core/-/core-7.26.8.tgz", "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.26.9.tgz",
"integrity": "sha512-l+lkXCHS6tQEc5oUpK28xBOZ6+HwaH7YwoYQbLFiYb4nS2/l1tKnZEtEWkD0GuiYdvArf9qBS0XlQGXzPMsNqQ==", "integrity": "sha512-lWBYIrF7qK5+GjY5Uy+/hEgp8OJWOD/rpy74GplYRhEauvbHDeFB8t5hPOZxCZ0Oxf4Cc36tK51/l3ymJysrKw==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@ampproject/remapping": "^2.2.0", "@ampproject/remapping": "^2.2.0",
"@babel/code-frame": "^7.26.2", "@babel/code-frame": "^7.26.2",
"@babel/generator": "^7.26.8", "@babel/generator": "^7.26.9",
"@babel/helper-compilation-targets": "^7.26.5", "@babel/helper-compilation-targets": "^7.26.5",
"@babel/helper-module-transforms": "^7.26.0", "@babel/helper-module-transforms": "^7.26.0",
"@babel/helpers": "^7.26.7", "@babel/helpers": "^7.26.9",
"@babel/parser": "^7.26.8", "@babel/parser": "^7.26.9",
"@babel/template": "^7.26.8", "@babel/template": "^7.26.9",
"@babel/traverse": "^7.26.8", "@babel/traverse": "^7.26.9",
"@babel/types": "^7.26.8", "@babel/types": "^7.26.9",
"@types/gensync": "^1.0.0",
"convert-source-map": "^2.0.0", "convert-source-map": "^2.0.0",
"debug": "^4.1.0", "debug": "^4.1.0",
"gensync": "^1.0.0-beta.2", "gensync": "^1.0.0-beta.2",
@@ -131,14 +130,14 @@
} }
}, },
"node_modules/@babel/generator": { "node_modules/@babel/generator": {
"version": "7.26.8", "version": "7.26.9",
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.26.8.tgz", "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.26.9.tgz",
"integrity": "sha512-ef383X5++iZHWAXX0SXQR6ZyQhw/0KtTkrTz61WXRhFM6dhpHulO/RJz79L8S6ugZHJkOOkUrUdxgdF2YiPFnA==", "integrity": "sha512-kEWdzjOAUMW4hAyrzJ0ZaTOu9OmpyDIQicIh0zg0EEcEkYXZb2TjtBhnHi2ViX7PKwZqF4xwqfAm299/QMP3lg==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@babel/parser": "^7.26.8", "@babel/parser": "^7.26.9",
"@babel/types": "^7.26.8", "@babel/types": "^7.26.9",
"@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/gen-mapping": "^0.3.5",
"@jridgewell/trace-mapping": "^0.3.25", "@jridgewell/trace-mapping": "^0.3.25",
"jsesc": "^3.0.2" "jsesc": "^3.0.2"
@@ -188,18 +187,18 @@
} }
}, },
"node_modules/@babel/helper-create-class-features-plugin": { "node_modules/@babel/helper-create-class-features-plugin": {
"version": "7.25.9", "version": "7.26.9",
"resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.25.9.tgz", "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.26.9.tgz",
"integrity": "sha512-UTZQMvt0d/rSz6KI+qdu7GQze5TIajwTS++GUozlw8VBJDEOAqSXwm1WvmYEZwqdqSGQshRocPDqrt4HBZB3fQ==", "integrity": "sha512-ubbUqCofvxPRurw5L8WTsCLSkQiVpov4Qx0WMA+jUN+nXBK8ADPlJO1grkFw5CWKC5+sZSOfuGMdX1aI1iT9Sg==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@babel/helper-annotate-as-pure": "^7.25.9", "@babel/helper-annotate-as-pure": "^7.25.9",
"@babel/helper-member-expression-to-functions": "^7.25.9", "@babel/helper-member-expression-to-functions": "^7.25.9",
"@babel/helper-optimise-call-expression": "^7.25.9", "@babel/helper-optimise-call-expression": "^7.25.9",
"@babel/helper-replace-supers": "^7.25.9", "@babel/helper-replace-supers": "^7.26.5",
"@babel/helper-skip-transparent-expression-wrappers": "^7.25.9", "@babel/helper-skip-transparent-expression-wrappers": "^7.25.9",
"@babel/traverse": "^7.25.9", "@babel/traverse": "^7.26.9",
"semver": "^6.3.1" "semver": "^6.3.1"
}, },
"engines": { "engines": {
@@ -429,27 +428,27 @@
} }
}, },
"node_modules/@babel/helpers": { "node_modules/@babel/helpers": {
"version": "7.26.7", "version": "7.26.9",
"resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.26.7.tgz", "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.26.9.tgz",
"integrity": "sha512-8NHiL98vsi0mbPQmYAGWwfcFaOy4j2HY49fXJCfuDcdE7fMIsH9a7GdaeXpIBsbT7307WU8KCMp5pUVDNL4f9A==", "integrity": "sha512-Mz/4+y8udxBKdmzt/UjPACs4G3j5SshJJEFFKxlCGPydG4JAHXxjWjAwjd09tf6oINvl1VfMJo+nB7H2YKQ0dA==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@babel/template": "^7.25.9", "@babel/template": "^7.26.9",
"@babel/types": "^7.26.7" "@babel/types": "^7.26.9"
}, },
"engines": { "engines": {
"node": ">=6.9.0" "node": ">=6.9.0"
} }
}, },
"node_modules/@babel/parser": { "node_modules/@babel/parser": {
"version": "7.26.8", "version": "7.26.9",
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.26.8.tgz", "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.26.9.tgz",
"integrity": "sha512-TZIQ25pkSoaKEYYaHbbxkfL36GNsQ6iFiBbeuzAkLnXayKR1yP1zFe+NxuZWWsUyvt8icPU9CCq0sgWGXR1GEw==", "integrity": "sha512-81NWa1njQblgZbQHxWHpxxCzNsa3ZwvFqpUg7P+NNUU6f3UU2jBEg4OlF/J6rl8+PQGh1q6/zWScd001YwcA5A==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@babel/types": "^7.26.8" "@babel/types": "^7.26.9"
}, },
"bin": { "bin": {
"parser": "bin/babel-parser.js" "parser": "bin/babel-parser.js"
@@ -922,13 +921,13 @@
} }
}, },
"node_modules/@babel/plugin-transform-for-of": { "node_modules/@babel/plugin-transform-for-of": {
"version": "7.25.9", "version": "7.26.9",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.25.9.tgz", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.26.9.tgz",
"integrity": "sha512-LqHxduHoaGELJl2uhImHwRQudhCM50pT46rIBNvtT/Oql3nqiS3wOwP+5ten7NpYSXrrVLgtZU3DZmPtWZo16A==", "integrity": "sha512-Hry8AusVm8LW5BVFgiyUReuoGzPUpdHQQqJY5bZnbbf+ngOHWuCuYFKw/BqaaWlvEUrF91HMhDtEaI1hZzNbLg==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@babel/helper-plugin-utils": "^7.25.9", "@babel/helper-plugin-utils": "^7.26.5",
"@babel/helper-skip-transparent-expression-wrappers": "^7.25.9" "@babel/helper-skip-transparent-expression-wrappers": "^7.25.9"
}, },
"engines": { "engines": {
@@ -1341,9 +1340,9 @@
} }
}, },
"node_modules/@babel/plugin-transform-runtime": { "node_modules/@babel/plugin-transform-runtime": {
"version": "7.26.8", "version": "7.26.9",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.26.8.tgz", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.26.9.tgz",
"integrity": "sha512-H0jlQxFMI0Q8SyGPsj9pO3ygVQRxPkIGytsL3m1Zqca8KrCPpMlvh+e2dxknqdfS8LFwBw+PpiYPD9qy/FPQpA==", "integrity": "sha512-Jf+8y9wXQbbxvVYTM8gO5oEF2POdNji0NMltEkG7FtmzD9PVz7/lxpqSdTvwsjTMU5HIHuDVNf2SOxLkWi+wPQ==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
@@ -1520,9 +1519,9 @@
} }
}, },
"node_modules/@babel/preset-env": { "node_modules/@babel/preset-env": {
"version": "7.26.8", "version": "7.26.9",
"resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.26.8.tgz", "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.26.9.tgz",
"integrity": "sha512-um7Sy+2THd697S4zJEfv/U5MHGJzkN2xhtsR3T/SWRbVSic62nbISh51VVfU9JiO/L/Z97QczHTaFVkOU8IzNg==", "integrity": "sha512-vX3qPGE8sEKEAZCWk05k3cpTAE3/nOYca++JA+Rd0z2NCNzabmYvEiSShKzm10zdquOIAVXsy2Ei/DTW34KlKQ==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
@@ -1555,7 +1554,7 @@
"@babel/plugin-transform-dynamic-import": "^7.25.9", "@babel/plugin-transform-dynamic-import": "^7.25.9",
"@babel/plugin-transform-exponentiation-operator": "^7.26.3", "@babel/plugin-transform-exponentiation-operator": "^7.26.3",
"@babel/plugin-transform-export-namespace-from": "^7.25.9", "@babel/plugin-transform-export-namespace-from": "^7.25.9",
"@babel/plugin-transform-for-of": "^7.25.9", "@babel/plugin-transform-for-of": "^7.26.9",
"@babel/plugin-transform-function-name": "^7.25.9", "@babel/plugin-transform-function-name": "^7.25.9",
"@babel/plugin-transform-json-strings": "^7.25.9", "@babel/plugin-transform-json-strings": "^7.25.9",
"@babel/plugin-transform-literals": "^7.25.9", "@babel/plugin-transform-literals": "^7.25.9",
@@ -1643,9 +1642,9 @@
} }
}, },
"node_modules/@babel/runtime": { "node_modules/@babel/runtime": {
"version": "7.26.7", "version": "7.26.9",
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.26.7.tgz", "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.26.9.tgz",
"integrity": "sha512-AOPI3D+a8dXnja+iwsUqGRjr1BbZIe771sXdapOtYI531gSqpi92vXivKcq2asu/DFpdl1ceFAKZyRzK2PCVcQ==", "integrity": "sha512-aA63XwOkcl4xxQa3HjPMqOP6LiK0ZDv3mUPYEFXkpHbaFjtGggE1A61FjFzJnB+p7/oy2gA8E+rcBNl/zC1tMg==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"regenerator-runtime": "^0.14.0" "regenerator-runtime": "^0.14.0"
@@ -1655,32 +1654,32 @@
} }
}, },
"node_modules/@babel/template": { "node_modules/@babel/template": {
"version": "7.26.8", "version": "7.26.9",
"resolved": "https://registry.npmjs.org/@babel/template/-/template-7.26.8.tgz", "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.26.9.tgz",
"integrity": "sha512-iNKaX3ZebKIsCvJ+0jd6embf+Aulaa3vNBqZ41kM7iTWjx5qzWKXGHiJUW3+nTpQ18SG11hdF8OAzKrpXkb96Q==", "integrity": "sha512-qyRplbeIpNZhmzOysF/wFMuP9sctmh2cFzRAZOn1YapxBsE1i9bJIY586R/WBLfLcmcBlM8ROBiQURnnNy+zfA==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@babel/code-frame": "^7.26.2", "@babel/code-frame": "^7.26.2",
"@babel/parser": "^7.26.8", "@babel/parser": "^7.26.9",
"@babel/types": "^7.26.8" "@babel/types": "^7.26.9"
}, },
"engines": { "engines": {
"node": ">=6.9.0" "node": ">=6.9.0"
} }
}, },
"node_modules/@babel/traverse": { "node_modules/@babel/traverse": {
"version": "7.26.8", "version": "7.26.9",
"resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.26.8.tgz", "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.26.9.tgz",
"integrity": "sha512-nic9tRkjYH0oB2dzr/JoGIm+4Q6SuYeLEiIiZDwBscRMYFJ+tMAz98fuel9ZnbXViA2I0HVSSRRK8DW5fjXStA==", "integrity": "sha512-ZYW7L+pL8ahU5fXmNbPF+iZFHCv5scFak7MZ9bwaRPLUhHh7QQEMjZUg0HevihoqCM5iSYHN61EyCoZvqC+bxg==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@babel/code-frame": "^7.26.2", "@babel/code-frame": "^7.26.2",
"@babel/generator": "^7.26.8", "@babel/generator": "^7.26.9",
"@babel/parser": "^7.26.8", "@babel/parser": "^7.26.9",
"@babel/template": "^7.26.8", "@babel/template": "^7.26.9",
"@babel/types": "^7.26.8", "@babel/types": "^7.26.9",
"debug": "^4.3.1", "debug": "^4.3.1",
"globals": "^11.1.0" "globals": "^11.1.0"
}, },
@@ -1689,9 +1688,9 @@
} }
}, },
"node_modules/@babel/types": { "node_modules/@babel/types": {
"version": "7.26.8", "version": "7.26.9",
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.26.8.tgz", "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.26.9.tgz",
"integrity": "sha512-eUuWapzEGWFEpHFxgEaBG8e3n6S8L3MSu0oda755rOfabWPnh0Our1AozNFVUxGFIhbKgd1ksprsoDGMinTOTA==", "integrity": "sha512-Y3IR1cRnOxOCDvMmNiym7XpXQ93iGDDPHx+Zj+NM+rg0fBaShfQLkg+hKPaZCEvg5N/LeCo4+Rj/i3FuJsIQaw==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
@@ -2606,9 +2605,9 @@
} }
}, },
"node_modules/@rollup/rollup-android-arm-eabi": { "node_modules/@rollup/rollup-android-arm-eabi": {
"version": "4.34.6", "version": "4.34.8",
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.34.6.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.34.8.tgz",
"integrity": "sha512-+GcCXtOQoWuC7hhX1P00LqjjIiS/iOouHXhMdiDSnq/1DGTox4SpUvO52Xm+div6+106r+TcvOeo/cxvyEyTgg==", "integrity": "sha512-q217OSE8DTp8AFHuNHXo0Y86e1wtlfVrXiAlwkIvGRQv9zbc6mE3sjIVfwI8sYUyNxwOg0j/Vm1RKM04JcWLJw==",
"cpu": [ "cpu": [
"arm" "arm"
], ],
@@ -2620,9 +2619,9 @@
] ]
}, },
"node_modules/@rollup/rollup-android-arm64": { "node_modules/@rollup/rollup-android-arm64": {
"version": "4.34.6", "version": "4.34.8",
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.34.6.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.34.8.tgz",
"integrity": "sha512-E8+2qCIjciYUnCa1AiVF1BkRgqIGW9KzJeesQqVfyRITGQN+dFuoivO0hnro1DjT74wXLRZ7QF8MIbz+luGaJA==", "integrity": "sha512-Gigjz7mNWaOL9wCggvoK3jEIUUbGul656opstjaUSGC3eT0BM7PofdAJaBfPFWWkXNVAXbaQtC99OCg4sJv70Q==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
@@ -2634,9 +2633,9 @@
] ]
}, },
"node_modules/@rollup/rollup-darwin-arm64": { "node_modules/@rollup/rollup-darwin-arm64": {
"version": "4.34.6", "version": "4.34.8",
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.34.6.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.34.8.tgz",
"integrity": "sha512-z9Ib+OzqN3DZEjX7PDQMHEhtF+t6Mi2z/ueChQPLS/qUMKY7Ybn5A2ggFoKRNRh1q1T03YTQfBTQCJZiepESAg==", "integrity": "sha512-02rVdZ5tgdUNRxIUrFdcMBZQoaPMrxtwSb+/hOfBdqkatYHR3lZ2A2EGyHq2sGOd0Owk80oV3snlDASC24He3Q==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
@@ -2648,9 +2647,9 @@
] ]
}, },
"node_modules/@rollup/rollup-darwin-x64": { "node_modules/@rollup/rollup-darwin-x64": {
"version": "4.34.6", "version": "4.34.8",
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.34.6.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.34.8.tgz",
"integrity": "sha512-PShKVY4u0FDAR7jskyFIYVyHEPCPnIQY8s5OcXkdU8mz3Y7eXDJPdyM/ZWjkYdR2m0izD9HHWA8sGcXn+Qrsyg==", "integrity": "sha512-qIP/elwR/tq/dYRx3lgwK31jkZvMiD6qUtOycLhTzCvrjbZ3LjQnEM9rNhSGpbLXVJYQ3rq39A6Re0h9tU2ynw==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
@@ -2662,9 +2661,9 @@
] ]
}, },
"node_modules/@rollup/rollup-freebsd-arm64": { "node_modules/@rollup/rollup-freebsd-arm64": {
"version": "4.34.6", "version": "4.34.8",
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.34.6.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.34.8.tgz",
"integrity": "sha512-YSwyOqlDAdKqs0iKuqvRHLN4SrD2TiswfoLfvYXseKbL47ht1grQpq46MSiQAx6rQEN8o8URtpXARCpqabqxGQ==", "integrity": "sha512-IQNVXL9iY6NniYbTaOKdrlVP3XIqazBgJOVkddzJlqnCpRi/yAeSOa8PLcECFSQochzqApIOE1GHNu3pCz+BDA==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
@@ -2676,9 +2675,9 @@
] ]
}, },
"node_modules/@rollup/rollup-freebsd-x64": { "node_modules/@rollup/rollup-freebsd-x64": {
"version": "4.34.6", "version": "4.34.8",
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.34.6.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.34.8.tgz",
"integrity": "sha512-HEP4CgPAY1RxXwwL5sPFv6BBM3tVeLnshF03HMhJYCNc6kvSqBgTMmsEjb72RkZBAWIqiPUyF1JpEBv5XT9wKQ==", "integrity": "sha512-TYXcHghgnCqYFiE3FT5QwXtOZqDj5GmaFNTNt3jNC+vh22dc/ukG2cG+pi75QO4kACohZzidsq7yKTKwq/Jq7Q==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
@@ -2690,9 +2689,9 @@
] ]
}, },
"node_modules/@rollup/rollup-linux-arm-gnueabihf": { "node_modules/@rollup/rollup-linux-arm-gnueabihf": {
"version": "4.34.6", "version": "4.34.8",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.34.6.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.34.8.tgz",
"integrity": "sha512-88fSzjC5xeH9S2Vg3rPgXJULkHcLYMkh8faix8DX4h4TIAL65ekwuQMA/g2CXq8W+NJC43V6fUpYZNjaX3+IIg==", "integrity": "sha512-A4iphFGNkWRd+5m3VIGuqHnG3MVnqKe7Al57u9mwgbyZ2/xF9Jio72MaY7xxh+Y87VAHmGQr73qoKL9HPbXj1g==",
"cpu": [ "cpu": [
"arm" "arm"
], ],
@@ -2704,9 +2703,9 @@
] ]
}, },
"node_modules/@rollup/rollup-linux-arm-musleabihf": { "node_modules/@rollup/rollup-linux-arm-musleabihf": {
"version": "4.34.6", "version": "4.34.8",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.34.6.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.34.8.tgz",
"integrity": "sha512-wM4ztnutBqYFyvNeR7Av+reWI/enK9tDOTKNF+6Kk2Q96k9bwhDDOlnCUNRPvromlVXo04riSliMBs/Z7RteEg==", "integrity": "sha512-S0lqKLfTm5u+QTxlFiAnb2J/2dgQqRy/XvziPtDd1rKZFXHTyYLoVL58M/XFwDI01AQCDIevGLbQrMAtdyanpA==",
"cpu": [ "cpu": [
"arm" "arm"
], ],
@@ -2718,9 +2717,9 @@
] ]
}, },
"node_modules/@rollup/rollup-linux-arm64-gnu": { "node_modules/@rollup/rollup-linux-arm64-gnu": {
"version": "4.34.6", "version": "4.34.8",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.34.6.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.34.8.tgz",
"integrity": "sha512-9RyprECbRa9zEjXLtvvshhw4CMrRa3K+0wcp3KME0zmBe1ILmvcVHnypZ/aIDXpRyfhSYSuN4EPdCCj5Du8FIA==", "integrity": "sha512-jpz9YOuPiSkL4G4pqKrus0pn9aYwpImGkosRKwNi+sJSkz+WU3anZe6hi73StLOQdfXYXC7hUfsQlTnjMd3s1A==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
@@ -2732,9 +2731,9 @@
] ]
}, },
"node_modules/@rollup/rollup-linux-arm64-musl": { "node_modules/@rollup/rollup-linux-arm64-musl": {
"version": "4.34.6", "version": "4.34.8",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.34.6.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.34.8.tgz",
"integrity": "sha512-qTmklhCTyaJSB05S+iSovfo++EwnIEZxHkzv5dep4qoszUMX5Ca4WM4zAVUMbfdviLgCSQOu5oU8YoGk1s6M9Q==", "integrity": "sha512-KdSfaROOUJXgTVxJNAZ3KwkRc5nggDk+06P6lgi1HLv1hskgvxHUKZ4xtwHkVYJ1Rep4GNo+uEfycCRRxht7+Q==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
@@ -2746,9 +2745,9 @@
] ]
}, },
"node_modules/@rollup/rollup-linux-loongarch64-gnu": { "node_modules/@rollup/rollup-linux-loongarch64-gnu": {
"version": "4.34.6", "version": "4.34.8",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.34.6.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.34.8.tgz",
"integrity": "sha512-4Qmkaps9yqmpjY5pvpkfOerYgKNUGzQpFxV6rnS7c/JfYbDSU0y6WpbbredB5cCpLFGJEqYX40WUmxMkwhWCjw==", "integrity": "sha512-NyF4gcxwkMFRjgXBM6g2lkT58OWztZvw5KkV2K0qqSnUEqCVcqdh2jN4gQrTn/YUpAcNKyFHfoOZEer9nwo6uQ==",
"cpu": [ "cpu": [
"loong64" "loong64"
], ],
@@ -2760,9 +2759,9 @@
] ]
}, },
"node_modules/@rollup/rollup-linux-powerpc64le-gnu": { "node_modules/@rollup/rollup-linux-powerpc64le-gnu": {
"version": "4.34.6", "version": "4.34.8",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.34.6.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.34.8.tgz",
"integrity": "sha512-Zsrtux3PuaxuBTX/zHdLaFmcofWGzaWW1scwLU3ZbW/X+hSsFbz9wDIp6XvnT7pzYRl9MezWqEqKy7ssmDEnuQ==", "integrity": "sha512-LMJc999GkhGvktHU85zNTDImZVUCJ1z/MbAJTnviiWmmjyckP5aQsHtcujMjpNdMZPT2rQEDBlJfubhs3jsMfw==",
"cpu": [ "cpu": [
"ppc64" "ppc64"
], ],
@@ -2774,9 +2773,9 @@
] ]
}, },
"node_modules/@rollup/rollup-linux-riscv64-gnu": { "node_modules/@rollup/rollup-linux-riscv64-gnu": {
"version": "4.34.6", "version": "4.34.8",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.34.6.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.34.8.tgz",
"integrity": "sha512-aK+Zp+CRM55iPrlyKiU3/zyhgzWBxLVrw2mwiQSYJRobCURb781+XstzvA8Gkjg/hbdQFuDw44aUOxVQFycrAg==", "integrity": "sha512-xAQCAHPj8nJq1PI3z8CIZzXuXCstquz7cIOL73HHdXiRcKk8Ywwqtx2wrIy23EcTn4aZ2fLJNBB8d0tQENPCmw==",
"cpu": [ "cpu": [
"riscv64" "riscv64"
], ],
@@ -2788,9 +2787,9 @@
] ]
}, },
"node_modules/@rollup/rollup-linux-s390x-gnu": { "node_modules/@rollup/rollup-linux-s390x-gnu": {
"version": "4.34.6", "version": "4.34.8",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.34.6.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.34.8.tgz",
"integrity": "sha512-WoKLVrY9ogmaYPXwTH326+ErlCIgMmsoRSx6bO+l68YgJnlOXhygDYSZe/qbUJCSiCiZAQ+tKm88NcWuUXqOzw==", "integrity": "sha512-DdePVk1NDEuc3fOe3dPPTb+rjMtuFw89gw6gVWxQFAuEqqSdDKnrwzZHrUYdac7A7dXl9Q2Vflxpme15gUWQFA==",
"cpu": [ "cpu": [
"s390x" "s390x"
], ],
@@ -2802,9 +2801,9 @@
] ]
}, },
"node_modules/@rollup/rollup-linux-x64-gnu": { "node_modules/@rollup/rollup-linux-x64-gnu": {
"version": "4.34.6", "version": "4.34.8",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.34.6.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.34.8.tgz",
"integrity": "sha512-Sht4aFvmA4ToHd2vFzwMFaQCiYm2lDFho5rPcvPBT5pCdC+GwHG6CMch4GQfmWTQ1SwRKS0dhDYb54khSrjDWw==", "integrity": "sha512-8y7ED8gjxITUltTUEJLQdgpbPh1sUQ0kMTmufRF/Ns5tI9TNMNlhWtmPKKHCU0SilX+3MJkZ0zERYYGIVBYHIA==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
@@ -2816,9 +2815,9 @@
] ]
}, },
"node_modules/@rollup/rollup-linux-x64-musl": { "node_modules/@rollup/rollup-linux-x64-musl": {
"version": "4.34.6", "version": "4.34.8",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.34.6.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.34.8.tgz",
"integrity": "sha512-zmmpOQh8vXc2QITsnCiODCDGXFC8LMi64+/oPpPx5qz3pqv0s6x46ps4xoycfUiVZps5PFn1gksZzo4RGTKT+A==", "integrity": "sha512-SCXcP0ZpGFIe7Ge+McxY5zKxiEI5ra+GT3QRxL0pMMtxPfpyLAKleZODi1zdRHkz5/BhueUrYtYVgubqe9JBNQ==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
@@ -2830,9 +2829,9 @@
] ]
}, },
"node_modules/@rollup/rollup-win32-arm64-msvc": { "node_modules/@rollup/rollup-win32-arm64-msvc": {
"version": "4.34.6", "version": "4.34.8",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.34.6.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.34.8.tgz",
"integrity": "sha512-3/q1qUsO/tLqGBaD4uXsB6coVGB3usxw3qyeVb59aArCgedSF66MPdgRStUd7vbZOsko/CgVaY5fo2vkvPLWiA==", "integrity": "sha512-YHYsgzZgFJzTRbth4h7Or0m5O74Yda+hLin0irAIobkLQFRQd1qWmnoVfwmKm9TXIZVAD0nZ+GEb2ICicLyCnQ==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
@@ -2844,9 +2843,9 @@
] ]
}, },
"node_modules/@rollup/rollup-win32-ia32-msvc": { "node_modules/@rollup/rollup-win32-ia32-msvc": {
"version": "4.34.6", "version": "4.34.8",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.34.6.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.34.8.tgz",
"integrity": "sha512-oLHxuyywc6efdKVTxvc0135zPrRdtYVjtVD5GUm55I3ODxhU/PwkQFD97z16Xzxa1Fz0AEe4W/2hzRtd+IfpOA==", "integrity": "sha512-r3NRQrXkHr4uWy5TOjTpTYojR9XmF0j/RYgKCef+Ag46FWUTltm5ziticv8LdNsDMehjJ543x/+TJAek/xBA2w==",
"cpu": [ "cpu": [
"ia32" "ia32"
], ],
@@ -2858,9 +2857,9 @@
] ]
}, },
"node_modules/@rollup/rollup-win32-x64-msvc": { "node_modules/@rollup/rollup-win32-x64-msvc": {
"version": "4.34.6", "version": "4.34.8",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.34.6.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.34.8.tgz",
"integrity": "sha512-0PVwmgzZ8+TZ9oGBmdZoQVXflbvuwzN/HRclujpl4N/q3i+y0lqLw8n1bXA8ru3sApDjlmONaNAuYr38y1Kr9w==", "integrity": "sha512-U0FaE5O1BCpZSeE6gBl3c5ObhePQSfk9vDRToMmTkbhCOgW4jqvtS5LGyQ76L1fH8sM0keRp4uDTsbjiUyjk0g==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
@@ -3047,13 +3046,6 @@
"@types/send": "*" "@types/send": "*"
} }
}, },
"node_modules/@types/gensync": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/@types/gensync/-/gensync-1.0.4.tgz",
"integrity": "sha512-C3YYeRQWp2fmq9OryX+FoDy8nXS6scQ7dPptD8LnFDAUNcKWJjXQKDNJD3HVm+kOUsXhTOkpi69vI4EuAr95bA==",
"dev": true,
"license": "MIT"
},
"node_modules/@types/glob": { "node_modules/@types/glob": {
"version": "7.2.0", "version": "7.2.0",
"resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.2.0.tgz", "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.2.0.tgz",
@@ -3155,9 +3147,9 @@
"license": "MIT" "license": "MIT"
}, },
"node_modules/@types/node": { "node_modules/@types/node": {
"version": "22.13.1", "version": "22.13.4",
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.13.1.tgz", "resolved": "https://registry.npmjs.org/@types/node/-/node-22.13.4.tgz",
"integrity": "sha512-jK8uzQlrvXqEU91UxiK5J7pKHyzgnI1Qnl0QDHIgVGuolJhRb9EEl28Cj9b3rGR8B2lhFCtvIm5os8lFnO/1Ew==", "integrity": "sha512-ywP2X0DYtX3y08eFVx5fNIw7/uIv8hYUKgXoK8oayJlLnKcRfEYCxWMVE1XagUdVtCJlZT1AU4LXEABW+L1Peg==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
@@ -4180,15 +4172,15 @@
"license": "MIT" "license": "MIT"
}, },
"node_modules/bootstrap5-autocomplete": { "node_modules/bootstrap5-autocomplete": {
"version": "1.1.35", "version": "1.1.36",
"resolved": "https://registry.npmjs.org/bootstrap5-autocomplete/-/bootstrap5-autocomplete-1.1.35.tgz", "resolved": "https://registry.npmjs.org/bootstrap5-autocomplete/-/bootstrap5-autocomplete-1.1.36.tgz",
"integrity": "sha512-vZAOef3lGrpGGnnIKTJlqiqv6wsx0Wr31/mc010mJmHF1eXJd28jzfGn7ol8eOI/7FiDcm3wd/1VTWku40vLbQ==", "integrity": "sha512-fZpklymmrwAls3n6YDMua2msnBB4pwmJgJgqMayHLfnvvc2dhKWwp/qu0pGJI99S8TwC+ZDjYtEsfl+4/FEZhg==",
"license": "MIT" "license": "MIT"
}, },
"node_modules/bootstrap5-tags": { "node_modules/bootstrap5-tags": {
"version": "1.7.6", "version": "1.7.7",
"resolved": "https://registry.npmjs.org/bootstrap5-tags/-/bootstrap5-tags-1.7.6.tgz", "resolved": "https://registry.npmjs.org/bootstrap5-tags/-/bootstrap5-tags-1.7.7.tgz",
"integrity": "sha512-5bUMUN4I11n/MtrfmYOF41ebkMmy2s4AZZfp6C1oWm2dXZS3UUZqb7J9Qj9OJ1r053hix0pKtg3mNJcQvqa1EQ==", "integrity": "sha512-1rgN2OLM9PQlQxeKUFUN9Tay246Zn7rK0p6p+ZaG2Q2VXPkZaZ+3EDYh3LOofvlHS50mL/Uthk9AoOxtdz6drA==",
"license": "MIT" "license": "MIT"
}, },
"node_modules/brace-expansion": { "node_modules/brace-expansion": {
@@ -4405,9 +4397,9 @@
} }
}, },
"node_modules/call-bind-apply-helpers": { "node_modules/call-bind-apply-helpers": {
"version": "1.0.1", "version": "1.0.2",
"resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.1.tgz", "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz",
"integrity": "sha512-BhYE+WDaywFg2TBWYNXAE+8B1ATnThNBqXHP5nQu0jWJdVvY2hvkpyB3qOmtmDePiS5/BDQ8wASEWGMWRG148g==", "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
@@ -4470,9 +4462,9 @@
} }
}, },
"node_modules/caniuse-lite": { "node_modules/caniuse-lite": {
"version": "1.0.30001699", "version": "1.0.30001700",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001699.tgz", "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001700.tgz",
"integrity": "sha512-b+uH5BakXZ9Do9iK+CkDmctUSEqZl+SP056vc5usa0PL+ev5OHw003rZXcnjNDv3L8P5j6rwT6C0BPKSikW08w==", "integrity": "sha512-2S6XIXwaE7K7erT8dY+kLQcpa5ms63XlRkMkReXjle+kf6c5g38vyMl+Z5y8dSxOFDhcFe+nxnn261PLxBSQsQ==",
"dev": true, "dev": true,
"funding": [ "funding": [
{ {
@@ -5685,9 +5677,9 @@
"license": "MIT" "license": "MIT"
}, },
"node_modules/electron-to-chromium": { "node_modules/electron-to-chromium": {
"version": "1.5.97", "version": "1.5.102",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.97.tgz", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.102.tgz",
"integrity": "sha512-HKLtaH02augM7ZOdYRuO19rWDeY+QSJ1VxnXFa/XDFLf07HvM90pALIJFgrO+UVaajI3+aJMMpojoUTLZyQ7JQ==", "integrity": "sha512-eHhqaja8tE/FNpIiBrvBjFV/SSKpyWHLvxuR9dPTdo+3V9ppdLmFB7ZZQ98qNovcngPLYIz0oOBF9P0FfZef5Q==",
"dev": true, "dev": true,
"license": "ISC" "license": "ISC"
}, },
@@ -5831,6 +5823,22 @@
"node": ">= 0.4" "node": ">= 0.4"
} }
}, },
"node_modules/es-set-tostringtag": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz",
"integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==",
"dev": true,
"license": "MIT",
"dependencies": {
"es-errors": "^1.3.0",
"get-intrinsic": "^1.2.6",
"has-tostringtag": "^1.0.2",
"hasown": "^2.0.2"
},
"engines": {
"node": ">= 0.4"
}
},
"node_modules/esbuild": { "node_modules/esbuild": {
"version": "0.24.2", "version": "0.24.2",
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.24.2.tgz", "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.24.2.tgz",
@@ -6359,14 +6367,15 @@
} }
}, },
"node_modules/form-data": { "node_modules/form-data": {
"version": "4.0.1", "version": "4.0.2",
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.1.tgz", "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.2.tgz",
"integrity": "sha512-tzN8e4TX8+kkxGPK8D5u0FNmjPUjw3lwC9lSLxxoB/+GtsJG91CO8bSWy73APlgAZzZbXEYZJuxjkHH2w+Ezhw==", "integrity": "sha512-hGfm/slu0ZabnNt4oaRZ6uREyfCj6P4fT/n6A1rGV+Z0VdGXjfOhVUpkn6qVQONHGIFwmveGXyDs75+nr6FM8w==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"asynckit": "^0.4.0", "asynckit": "^0.4.0",
"combined-stream": "^1.0.8", "combined-stream": "^1.0.8",
"es-set-tostringtag": "^2.1.0",
"mime-types": "^2.1.12" "mime-types": "^2.1.12"
}, },
"engines": { "engines": {
@@ -6675,6 +6684,22 @@
"url": "https://github.com/sponsors/ljharb" "url": "https://github.com/sponsors/ljharb"
} }
}, },
"node_modules/has-tostringtag": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz",
"integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==",
"dev": true,
"license": "MIT",
"dependencies": {
"has-symbols": "^1.0.3"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/hash-base": { "node_modules/hash-base": {
"version": "3.0.5", "version": "3.0.5",
"resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.0.5.tgz", "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.0.5.tgz",
@@ -7753,9 +7778,9 @@
} }
}, },
"node_modules/launch-editor": { "node_modules/launch-editor": {
"version": "2.9.1", "version": "2.10.0",
"resolved": "https://registry.npmjs.org/launch-editor/-/launch-editor-2.9.1.tgz", "resolved": "https://registry.npmjs.org/launch-editor/-/launch-editor-2.10.0.tgz",
"integrity": "sha512-Gcnl4Bd+hRO9P9icCP/RVVT2o8SFlPXofuCxvA2SaZuH45whSvf5p8x5oih5ftLiVhEI4sp5xDY+R+b3zJBh5w==", "integrity": "sha512-D7dBRJo/qcGX9xlvt/6wUYzQxjh5G1RvZPgPv8vi4KRU99DVQL/oW7tnVOCCTm2HGeo3C5HvGE5Yrh6UBoZ0vA==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
@@ -10009,9 +10034,9 @@
} }
}, },
"node_modules/rollup": { "node_modules/rollup": {
"version": "4.34.6", "version": "4.34.8",
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.34.6.tgz", "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.34.8.tgz",
"integrity": "sha512-wc2cBWqJgkU3Iz5oztRkQbfVkbxoz5EhnCGOrnJvnLnQ7O0WhQUYyv18qQI79O8L7DdHrrlJNeCHd4VGpnaXKQ==", "integrity": "sha512-489gTVMzAYdiZHFVA/ig/iYFllCcWFHMvUHI1rpFmkoUtRlQxqh6/yiNqnYibjMZ2b/+FUQwldG+aLsEt6bglQ==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
@@ -10025,25 +10050,25 @@
"npm": ">=8.0.0" "npm": ">=8.0.0"
}, },
"optionalDependencies": { "optionalDependencies": {
"@rollup/rollup-android-arm-eabi": "4.34.6", "@rollup/rollup-android-arm-eabi": "4.34.8",
"@rollup/rollup-android-arm64": "4.34.6", "@rollup/rollup-android-arm64": "4.34.8",
"@rollup/rollup-darwin-arm64": "4.34.6", "@rollup/rollup-darwin-arm64": "4.34.8",
"@rollup/rollup-darwin-x64": "4.34.6", "@rollup/rollup-darwin-x64": "4.34.8",
"@rollup/rollup-freebsd-arm64": "4.34.6", "@rollup/rollup-freebsd-arm64": "4.34.8",
"@rollup/rollup-freebsd-x64": "4.34.6", "@rollup/rollup-freebsd-x64": "4.34.8",
"@rollup/rollup-linux-arm-gnueabihf": "4.34.6", "@rollup/rollup-linux-arm-gnueabihf": "4.34.8",
"@rollup/rollup-linux-arm-musleabihf": "4.34.6", "@rollup/rollup-linux-arm-musleabihf": "4.34.8",
"@rollup/rollup-linux-arm64-gnu": "4.34.6", "@rollup/rollup-linux-arm64-gnu": "4.34.8",
"@rollup/rollup-linux-arm64-musl": "4.34.6", "@rollup/rollup-linux-arm64-musl": "4.34.8",
"@rollup/rollup-linux-loongarch64-gnu": "4.34.6", "@rollup/rollup-linux-loongarch64-gnu": "4.34.8",
"@rollup/rollup-linux-powerpc64le-gnu": "4.34.6", "@rollup/rollup-linux-powerpc64le-gnu": "4.34.8",
"@rollup/rollup-linux-riscv64-gnu": "4.34.6", "@rollup/rollup-linux-riscv64-gnu": "4.34.8",
"@rollup/rollup-linux-s390x-gnu": "4.34.6", "@rollup/rollup-linux-s390x-gnu": "4.34.8",
"@rollup/rollup-linux-x64-gnu": "4.34.6", "@rollup/rollup-linux-x64-gnu": "4.34.8",
"@rollup/rollup-linux-x64-musl": "4.34.6", "@rollup/rollup-linux-x64-musl": "4.34.8",
"@rollup/rollup-win32-arm64-msvc": "4.34.6", "@rollup/rollup-win32-arm64-msvc": "4.34.8",
"@rollup/rollup-win32-ia32-msvc": "4.34.6", "@rollup/rollup-win32-ia32-msvc": "4.34.8",
"@rollup/rollup-win32-x64-msvc": "4.34.6", "@rollup/rollup-win32-x64-msvc": "4.34.8",
"fsevents": "~2.3.2" "fsevents": "~2.3.2"
} }
}, },
@@ -10099,9 +10124,9 @@
"license": "MIT" "license": "MIT"
}, },
"node_modules/sass": { "node_modules/sass": {
"version": "1.84.0", "version": "1.85.0",
"resolved": "https://registry.npmjs.org/sass/-/sass-1.84.0.tgz", "resolved": "https://registry.npmjs.org/sass/-/sass-1.85.0.tgz",
"integrity": "sha512-XDAbhEPJRxi7H0SxrnOpiXFQoUJHwkR2u3Zc4el+fK/Tt5Hpzw5kkQ59qVDfvdaUq6gCrEZIbySFBM2T9DNKHg==", "integrity": "sha512-3ToiC1xZ1Y8aU7+CkgCI/tqyuPXEmYGJXO7H4uqp0xkLXUqp88rQQ4j1HmP37xSJLbCJPaIiv+cT1y+grssrww==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
@@ -10136,9 +10161,9 @@
} }
}, },
"node_modules/sass/node_modules/readdirp": { "node_modules/sass/node_modules/readdirp": {
"version": "4.1.1", "version": "4.1.2",
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.1.tgz", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz",
"integrity": "sha512-h80JrZu/MHUZCyHu5ciuoI0+WxsCxzxJTILn6Fs8rxSnFPh+UVHYfeIxK1nVGugMqkfC4vJcBOYbkfkwYK0+gw==", "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"engines": { "engines": {
@@ -10893,9 +10918,9 @@
} }
}, },
"node_modules/terser": { "node_modules/terser": {
"version": "5.38.1", "version": "5.39.0",
"resolved": "https://registry.npmjs.org/terser/-/terser-5.38.1.tgz", "resolved": "https://registry.npmjs.org/terser/-/terser-5.39.0.tgz",
"integrity": "sha512-GWANVlPM/ZfYzuPHjq0nxT+EbOEDDN3Jwhwdg1D8TU8oSkktp8w64Uq4auuGLxFSoNTRDncTq2hQHX1Ld9KHkA==", "integrity": "sha512-LBAhFyLho16harJoWMg/nZsQYgTrg5jXOn2nCYjRUcZZEdE3qa2zb8QEDRUGVZBW4rlazf2fxkg8tztybTaqWw==",
"dev": true, "dev": true,
"license": "BSD-2-Clause", "license": "BSD-2-Clause",
"dependencies": { "dependencies": {
@@ -11607,9 +11632,9 @@
"license": "BSD-2-Clause" "license": "BSD-2-Clause"
}, },
"node_modules/webpack": { "node_modules/webpack": {
"version": "5.97.1", "version": "5.98.0",
"resolved": "https://registry.npmjs.org/webpack/-/webpack-5.97.1.tgz", "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.98.0.tgz",
"integrity": "sha512-EksG6gFY3L1eFMROS/7Wzgrii5mBAFe4rIr3r2BTfo7bcc+DWwFZ4OJ/miOuHJO/A85HwyI4eQ0F6IKXesO7Fg==", "integrity": "sha512-UFynvx+gM44Gv9qFgj0acCQK2VE1CtdfwFdimkapco3hlPCJ/zeq73n2yVKimVbtm+TnApIugGhLJnkU6gjYXA==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
@@ -11631,9 +11656,9 @@
"loader-runner": "^4.2.0", "loader-runner": "^4.2.0",
"mime-types": "^2.1.27", "mime-types": "^2.1.27",
"neo-async": "^2.6.2", "neo-async": "^2.6.2",
"schema-utils": "^3.2.0", "schema-utils": "^4.3.0",
"tapable": "^2.1.1", "tapable": "^2.1.1",
"terser-webpack-plugin": "^5.3.10", "terser-webpack-plugin": "^5.3.11",
"watchpack": "^2.4.1", "watchpack": "^2.4.1",
"webpack-sources": "^3.2.3" "webpack-sources": "^3.2.3"
}, },
@@ -11979,16 +12004,54 @@
"source-map": "~0.6.1" "source-map": "~0.6.1"
} }
}, },
"node_modules/webpack/node_modules/schema-utils": { "node_modules/webpack/node_modules/ajv": {
"version": "3.3.0", "version": "8.17.1",
"resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz",
"integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@types/json-schema": "^7.0.8", "fast-deep-equal": "^3.1.3",
"ajv": "^6.12.5", "fast-uri": "^3.0.1",
"ajv-keywords": "^3.5.2" "json-schema-traverse": "^1.0.0",
"require-from-string": "^2.0.2"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/epoberezkin"
}
},
"node_modules/webpack/node_modules/ajv-keywords": {
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz",
"integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==",
"dev": true,
"license": "MIT",
"dependencies": {
"fast-deep-equal": "^3.1.3"
},
"peerDependencies": {
"ajv": "^8.8.2"
}
},
"node_modules/webpack/node_modules/json-schema-traverse": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
"integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==",
"dev": true,
"license": "MIT"
},
"node_modules/webpack/node_modules/schema-utils": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.3.0.tgz",
"integrity": "sha512-Gf9qqc58SpCA/xdziiHz35F4GNIWYWZrEshUc/G/r5BnLph6xpKuLeoJoQuj5WfBIx/eQLf+hmVPYHaxJu7V2g==",
"dev": true,
"license": "MIT",
"dependencies": {
"@types/json-schema": "^7.0.9",
"ajv": "^8.9.0",
"ajv-formats": "^2.1.1",
"ajv-keywords": "^5.1.0"
}, },
"engines": { "engines": {
"node": ">= 10.13.0" "node": ">= 10.13.0"

View File

@@ -30,8 +30,16 @@ function parseToLocalDates() {
"use strict"; "use strict";
$('span.date-time').each(function () { $('span.date-time').each(function () {
var date = $(this).data('date'); var date = $(this).data('date');
var obj = moment.utc(date).local();
var timeZone = Intl.DateTimeFormat().resolvedOptions().timeZone; var timeZone = Intl.DateTimeFormat().resolvedOptions().timeZone;
console.log('raw date is "' + date + '"');
console.log('parse to utc() is "' + moment.utc(date).format() + '"');
console.log('parse to zone(Z) "' + moment.parseZone(date).format() + '" (should be the same)');
console.log('browser timezone is ' + timeZone);
var obj = moment.utc(date).local();
console.log('auto convert to timezone is: "' + obj.format() + '"');
console.log('moment.js format is: "'+date_time_js+'"');
$(this).text(obj.format(date_time_js) + ' ('+ timeZone +')'); $(this).text(obj.format(date_time_js) + ' ('+ timeZone +')');
}); });
} }

View File

@@ -39,6 +39,7 @@ function drawChart() {
columnChart(accountExpenseUrl, 'expense-accounts-chart'); columnChart(accountExpenseUrl, 'expense-accounts-chart');
columnChart(accountRevenueUrl, 'revenue-accounts-chart'); columnChart(accountRevenueUrl, 'revenue-accounts-chart');
getPiggyBanks(); getPiggyBanks();
console.log('Get all boxes');
getAllBoxes(); getAllBoxes();
function getAllBoxes() { function getAllBoxes() {
@@ -60,7 +61,7 @@ function drawChart() {
// net worth // net worth
var net_worth = []; var net_worth = [];
var keepGreen = false;
for (key in data) { for (key in data) {
// balance // balance
@@ -81,8 +82,8 @@ function drawChart() {
if (key.substring(0, 17) === 'left-to-spend-in-') { if (key.substring(0, 17) === 'left-to-spend-in-') {
left_to_spend_top.push(data[key].value_parsed); left_to_spend_top.push(data[key].value_parsed);
left_to_spend_bottom.push(data[key].sub_title); left_to_spend_bottom.push(data[key].sub_title);
if(parseFloat(data[key].monetary_value) < 0) { if (parseFloat(data[key].monetary_value) > 0) {
$('#box-left-to-spend-box').removeClass('bg-green-gradient').addClass('bg-red-gradient'); keepGreen = true;
} }
} }
@@ -91,6 +92,9 @@ function drawChart() {
net_worth.push(data[key].value_parsed); net_worth.push(data[key].value_parsed);
} }
} }
if(!keepGreen) {
$('#box-left-to-spend-box').removeClass('bg-green-gradient').addClass('bg-red-gradient')
}
// balance // balance
$('#box-balance-sums').html(balance_top.join(', ')); $('#box-balance-sums').html(balance_top.join(', '));

View File

@@ -28,6 +28,10 @@ $(document).ready(function () {
}); });
} }
$('.submit-test').click(submitTest); $('.submit-test').click(submitTest);
$.get('./api/v1/accounts?type=asset&page=1&limit=100', function (data) {
console.log('OK');
});
}); });
function submitTest(e) { function submitTest(e) {

View File

@@ -30,7 +30,7 @@
"apply_rules_checkbox": "Applica le regole", "apply_rules_checkbox": "Applica le regole",
"fire_webhooks_checkbox": "Esegui webhook", "fire_webhooks_checkbox": "Esegui webhook",
"no_budget_pointer": "Sembra che tu non abbia ancora dei budget. Dovresti crearne alcuni nella pagina dei <a href=\"budgets\">budget<\/a>. I budget possono aiutarti a tenere traccia delle spese.", "no_budget_pointer": "Sembra che tu non abbia ancora dei budget. Dovresti crearne alcuni nella pagina dei <a href=\"budgets\">budget<\/a>. I budget possono aiutarti a tenere traccia delle spese.",
"no_bill_pointer": "You seem to have no subscription yet. You should create some on the <a href=\"subscriptions\">subscription<\/a>-page. Subscriptions can help you keep track of expenses.", "no_bill_pointer": "Sembra che tu non abbia ancora un abbonamento. Dovresti crearne alcuni sulla pagina <a href=\"subscriptions\">abbonamento<\/a>. Gli abbonamenti possono aiutarti a tenere traccia delle spese.",
"source_account": "Conto di origine", "source_account": "Conto di origine",
"hidden_fields_preferences": "Puoi abilitare maggiori opzioni per le transazioni nelle tue <a href=\"preferences\">impostazioni<\/a>.", "hidden_fields_preferences": "Puoi abilitare maggiori opzioni per le transazioni nelle tue <a href=\"preferences\">impostazioni<\/a>.",
"destination_account": "Conto destinazione", "destination_account": "Conto destinazione",

View File

@@ -18,8 +18,8 @@
"is_reconciled": "Is afgestemd", "is_reconciled": "Is afgestemd",
"split": "Splitsen", "split": "Splitsen",
"single_split": "Split", "single_split": "Split",
"not_enough_currencies": "Not enough currencies", "not_enough_currencies": "Niet genoeg valuta's",
"not_enough_currencies_enabled": "If you have just one currency enabled, there is no need to add exchange rates.", "not_enough_currencies_enabled": "Als je slechts \u00e9\u00e9n valuta ingeschakeld hebt, gaan we geen wisselkoersen invoeren natuurlijk.",
"transaction_stored_link": "<a href=\"transactions\/show\/{ID}\">Transactie #{ID} (\"{title}\")<\/a> is opgeslagen.", "transaction_stored_link": "<a href=\"transactions\/show\/{ID}\">Transactie #{ID} (\"{title}\")<\/a> is opgeslagen.",
"webhook_stored_link": "<a href=\"webhooks\/show\/{ID}\">Webhook #{ID} ({title})<\/a> is opgeslagen.", "webhook_stored_link": "<a href=\"webhooks\/show\/{ID}\">Webhook #{ID} ({title})<\/a> is opgeslagen.",
"webhook_updated_link": "<a href=\"webhooks\/show\/{ID}\">Webhook #{ID} ({title})<\/a> is ge\u00fcpdatet.", "webhook_updated_link": "<a href=\"webhooks\/show\/{ID}\">Webhook #{ID} ({title})<\/a> is ge\u00fcpdatet.",
@@ -140,7 +140,7 @@
"visit_webhook_url": "Bezoek URL van webhook", "visit_webhook_url": "Bezoek URL van webhook",
"reset_webhook_secret": "Reset webhook-geheim", "reset_webhook_secret": "Reset webhook-geheim",
"header_exchange_rates": "Wisselkoersen", "header_exchange_rates": "Wisselkoersen",
"exchange_rates_intro": "Firefly III supports downloading and using exchange rates. Read more about this in <a href=\"https:\/\/docs.firefly-iii.org\/explanation\/financial-concepts\/exchange-rates\/\">the documentation<\/a>.", "exchange_rates_intro": "Firefly III kan wisselkoersen downloaden en gebruiken. Lees hier meer over in <a href=\"https:\/\/docs.firefly-iii.org\/explanation\/financial-concepts\/exchange-rates\/\">de documentatie<\/a>.",
"exchange_rates_from_to": "Tussen {from} en {to} (en andersom)", "exchange_rates_from_to": "Tussen {from} en {to} (en andersom)",
"exchange_rates_intro_rates": "Firefly III gebruikt de volgende wisselkoersen. De inverse berekent zichzelf als deze niet is opgegeven. Als er geen wisselkoers bestaat voor de datum van de transactie, gaat Firefly III terug in de tijd om er een te vinden. Als er geen aanwezig is, zal de koers \"1\" gebruikt worden.", "exchange_rates_intro_rates": "Firefly III gebruikt de volgende wisselkoersen. De inverse berekent zichzelf als deze niet is opgegeven. Als er geen wisselkoers bestaat voor de datum van de transactie, gaat Firefly III terug in de tijd om er een te vinden. Als er geen aanwezig is, zal de koers \"1\" gebruikt worden.",
"header_exchange_rates_rates": "Wisselkoersen", "header_exchange_rates_rates": "Wisselkoersen",

View File

@@ -1,25 +1,25 @@
{ {
"firefly": { "firefly": {
"administrations_page_title": "Financial administrations", "administrations_page_title": "Ustawienia finansowe",
"administrations_index_menu": "Financial administrations", "administrations_index_menu": "Ustawienia finansowe",
"temp_administrations_introduction": "Firefly III will soon get the ability to manage multiple financial administrations. Right now, you only have the one. You can set the title of this administration and its native currency. This replaces the previous setting where you would set your \"default currency\". This setting is now tied to the financial administration and can be different per administration.", "temp_administrations_introduction": "Firefly III wkr\u00f3tce uzyska mo\u017cliwo\u015b\u0107 zarz\u0105dzania wieloma ustawieniami finansowymi. W tej chwili jest tylko jedno domy\u015blne ustawienie. Mo\u017cesz ustawi\u0107 jego tytu\u0142 i natywn\u0105 walut\u0119. To zast\u0119puje poprzednie ustawienia, w kt\u00f3rym mo\u017cna by\u0142o ustawi\u0107 \"domy\u015bln\u0105 walut\u0119\". Jest ona obecnie powi\u0105zana z wybranym ustawieniem finansowym i mo\u017ce by\u0107 zmienione w tej zak\u0142adce.",
"administration_currency_form_help": "It may take a long time for the page to load if you change the native currency because transaction may need to be converted to your (new) native currency.", "administration_currency_form_help": "Wczytywanie strony mo\u017ce zaj\u0105\u0107 du\u017co czasu, je\u015bli zmienisz natywn\u0105 walut\u0119, poniewa\u017c transakcja mo\u017ce wymaga\u0107 przewalutowania na (now\u0105) natywn\u0105 walut\u0119.",
"administrations_page_edit_sub_title_js": "Edit financial administration \"{title}\"", "administrations_page_edit_sub_title_js": "Edytuj ustawienia finansowe \"{title}\"",
"table": "Tabela", "table": "Tabela",
"welcome_back": "Co jest grane?", "welcome_back": "Co jest grane?",
"flash_error": "B\u0142\u0105d!", "flash_error": "B\u0142\u0105d!",
"flash_warning": "Ostrze\u017cenie!", "flash_warning": "Ostrze\u017cenie!",
"flash_success": "Sukces!", "flash_success": "Sukces!",
"close": "Zamknij", "close": "Zamknij",
"select_dest_account": "Please select or type a valid destination account name", "select_dest_account": "Wybierz lub wpisz prawid\u0142ow\u0105 nazw\u0119 konta docelowego",
"select_source_account": "Wybierz lub wpisz prawid\u0142ow\u0105 nazw\u0119 konta \u017ar\u00f3d\u0142owego", "select_source_account": "Wybierz lub wpisz prawid\u0142ow\u0105 nazw\u0119 konta \u017ar\u00f3d\u0142owego",
"split_transaction_title": "Opis podzielonej transakcji", "split_transaction_title": "Opis podzielonej transakcji",
"errors_submission": "Co\u015b posz\u0142o nie tak w czasie zapisu. Prosz\u0119, sprawd\u017a b\u0142\u0119dy poni\u017cej.", "errors_submission": "Co\u015b posz\u0142o nie tak w czasie zapisu. Prosz\u0119, sprawd\u017a b\u0142\u0119dy poni\u017cej.",
"is_reconciled": "Is reconciled", "is_reconciled": "Jest uzgodniona",
"split": "Podziel", "split": "Podziel",
"single_split": "Podzia\u0142", "single_split": "Podzia\u0142",
"not_enough_currencies": "Not enough currencies", "not_enough_currencies": "Za ma\u0142o walut",
"not_enough_currencies_enabled": "If you have just one currency enabled, there is no need to add exchange rates.", "not_enough_currencies_enabled": "Je\u015bli masz w\u0142\u0105czon\u0105 tylko jedn\u0105 walut\u0119, nie ma potrzeby dodawania kurs\u00f3w wymiany.",
"transaction_stored_link": "<a href=\"transactions\/show\/{ID}\">Transakcja #{ID} (\"{title}\")<\/a> zosta\u0142a zapisana.", "transaction_stored_link": "<a href=\"transactions\/show\/{ID}\">Transakcja #{ID} (\"{title}\")<\/a> zosta\u0142a zapisana.",
"webhook_stored_link": "<a href=\"webhooks\/show\/{ID}\">Webhook #{ID} (\"{title}\")<\/a> zosta\u0142 zapisany.", "webhook_stored_link": "<a href=\"webhooks\/show\/{ID}\">Webhook #{ID} (\"{title}\")<\/a> zosta\u0142 zapisany.",
"webhook_updated_link": "<a href=\"webhooks\/show\/{ID}\">Webhook #{ID}<\/a> (\"{title}\") zosta\u0142 zaktualizowany.", "webhook_updated_link": "<a href=\"webhooks\/show\/{ID}\">Webhook #{ID}<\/a> (\"{title}\") zosta\u0142 zaktualizowany.",
@@ -42,10 +42,10 @@
"submit": "Prze\u015blij", "submit": "Prze\u015blij",
"amount": "Kwota", "amount": "Kwota",
"date": "Data", "date": "Data",
"is_reconciled_fields_dropped": "Because this transaction is reconciled, you will not be able to update the accounts, nor the amount(s) unless you remove the reconciliation flag.", "is_reconciled_fields_dropped": "Poniewa\u017c ta transakcja jest uzgodniona, nie b\u0119dziesz w stanie zaktualizowa\u0107 kont, ani kwot(y), chyba \u017ce usuniesz flag\u0119 uzgodnienia.",
"tags": "Tagi", "tags": "Tagi",
"no_budget": "(brak bud\u017cetu)", "no_budget": "(brak bud\u017cetu)",
"no_bill": "(no subscription)", "no_bill": "(brak subskrypcji)",
"category": "Kategoria", "category": "Kategoria",
"attachments": "Za\u0142\u0105czniki", "attachments": "Za\u0142\u0105czniki",
"notes": "Notatki", "notes": "Notatki",
@@ -61,7 +61,7 @@
"destination_account_reconciliation": "Nie mo\u017cesz edytowa\u0107 konta docelowego transakcji uzgadniania.", "destination_account_reconciliation": "Nie mo\u017cesz edytowa\u0107 konta docelowego transakcji uzgadniania.",
"source_account_reconciliation": "Nie mo\u017cesz edytowa\u0107 konta \u017ar\u00f3d\u0142owego transakcji uzgadniania.", "source_account_reconciliation": "Nie mo\u017cesz edytowa\u0107 konta \u017ar\u00f3d\u0142owego transakcji uzgadniania.",
"budget": "Bud\u017cet", "budget": "Bud\u017cet",
"bill": "Subscription", "bill": "Subskrypcja",
"you_create_withdrawal": "Tworzysz wydatek.", "you_create_withdrawal": "Tworzysz wydatek.",
"you_create_transfer": "Tworzysz przelew.", "you_create_transfer": "Tworzysz przelew.",
"you_create_deposit": "Tworzysz wp\u0142at\u0119.", "you_create_deposit": "Tworzysz wp\u0142at\u0119.",
@@ -139,15 +139,15 @@
"response": "Odpowied\u017a", "response": "Odpowied\u017a",
"visit_webhook_url": "Odwied\u017a adres URL webhooka", "visit_webhook_url": "Odwied\u017a adres URL webhooka",
"reset_webhook_secret": "Resetuj sekret webhooka", "reset_webhook_secret": "Resetuj sekret webhooka",
"header_exchange_rates": "Exchange rates", "header_exchange_rates": "Kursy walutowe",
"exchange_rates_intro": "Firefly III supports downloading and using exchange rates. Read more about this in <a href=\"https:\/\/docs.firefly-iii.org\/explanation\/financial-concepts\/exchange-rates\/\">the documentation<\/a>.", "exchange_rates_intro": "Firefly III obs\u0142uguje pobieranie i korzystanie z kurs\u00f3w wymiany walut. Wi\u0119cej informacji na ten temat w <a href=\"https:\/\/docs.firefly-iii.org\/explanation\/financial-concepts\/exchange-rates\/\">dokumentacji<\/a>.",
"exchange_rates_from_to": "Between {from} and {to} (and the other way around)", "exchange_rates_from_to": "Pomi\u0119dzy {from} i {to} (i odwrotnie)",
"exchange_rates_intro_rates": "Firefly III uses the following exchange rates. The inverse is automatically calculated when it is not provided. If no exchange rate exists for the date of the transaction, Firefly III will go back in time to find one. If none are present, the rate \"1\" will be used.", "exchange_rates_intro_rates": "Firefly III u\u017cywa nast\u0119puj\u0105cych kurs\u00f3w wymiany. Odwrotny jest obliczany automatycznie, w przypadku gdy nie jest dostarczony. Je\u015bli dla daty transakcji nie istnieje kurs wymiany, Firefly III skorzysta z kursu z przesz\u0142o\u015bci. Je\u015bli \u017caden nie istnieje, zostanie zastosowany kurs \"1\".",
"header_exchange_rates_rates": "Exchange rates", "header_exchange_rates_rates": "Kursy walutowe",
"header_exchange_rates_table": "Table with exchange rates", "header_exchange_rates_table": "Tabela z kursami wymiany walut",
"help_rate_form": "On this day, how many {to} will you get for one {from}?", "help_rate_form": "Tego dnia, ile {to} otrzymasz za jeden {from}?",
"add_new_rate": "Add a new exchange rate", "add_new_rate": "Dodaj nowy kurs wymiany",
"save_new_rate": "Save new rate" "save_new_rate": "Zapisz nowy kurs"
}, },
"form": { "form": {
"url": "URL", "url": "URL",

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