Compare commits

...

68 Commits

Author SHA1 Message Date
github-actions
d41f5b1090 Auto commit for release 'v6.2.9' on 2025-02-22 2025-02-22 17:20:52 +01:00
James Cole
40322813c9 Also include user group 2025-02-22 17:17:28 +01:00
James Cole
4a98927e32 Update changelog. 2025-02-22 17:16:30 +01:00
James Cole
193e529803 Fix #9887 2025-02-22 17:16:20 +01:00
github-actions
fbf20ef2c2 Auto commit for release 'v6.2.8' on 2025-02-22 2025-02-22 12:30:53 +01:00
github-actions
54de829c8a Merge branch 'develop' 2025-02-22 11:28:39 +00:00
James Cole
131b987561 Remove TZ 2025-02-22 12:27:22 +01:00
James Cole
dce6754c62 Merge branch 'main' into develop 2025-02-22 10:27:58 +01:00
James Cole
f4bca90080 Add time and time zone perhaps? 2025-02-22 10:25:31 +01:00
James Cole
b2960b1ed9 Remove docker ignore, not useful in this context. 2025-02-22 10:20:55 +01:00
James Cole
33f87bce23 Merge branch 'main' into develop 2025-02-22 10:20:31 +01:00
James Cole
23aa45609b Remove files from zip. 2025-02-22 10:20:23 +01:00
github-actions
b098952f82 Auto commit for release 'develop' on 2025-02-22 2025-02-22 10:16:15 +01:00
James Cole
68c3e14b0c Update changelog. 2025-02-22 10:12:30 +01:00
James Cole
19d08137a5 Fix #9887 2025-02-22 10:06:59 +01:00
James Cole
73776e7869 Fix #9887 2025-02-22 10:05:44 +01:00
github-actions
bf04ca12c1 Auto commit for release 'develop' on 2025-02-22 2025-02-22 08:18:27 +01:00
James Cole
a4637debe9 Update changelog, fix log reference. 2025-02-22 08:07:52 +01:00
James Cole
48c1b525be Fix #9874 2025-02-22 08:03:42 +01:00
github-actions
56470bfbba Auto commit for release 'develop' on 2025-02-21 2025-02-21 08:32:55 +01:00
James Cole
0f732ca874 Merge pull request #9880 from josegonzalez/patch-1
fix: ignore the Procfile when building the docker image
2025-02-21 08:06:04 +01:00
James Cole
e452ba938d Update changelog. 2025-02-21 06:20:17 +01:00
James Cole
9921c5a925 Fix #9882 2025-02-21 06:18:11 +01:00
Jose Diaz-Gonzalez
58fab75681 fix: ignore the Procfile when building the docker image
The Procfile is heroku-specific, causing issues on platforms which respect it when specifying processes to run for docker image or dockerfile based deploys.

Closes #9833

Signed-off-by: Jose Diaz-Gonzalez <email@josediazgonzalez.com>
2025-02-20 14:51:04 -05:00
Sander Dorigo
54990308f6 fix type error 2025-02-20 12:58:38 +01:00
github-actions
f95758ff47 Auto commit for release 'develop' on 2025-02-20 2025-02-20 08:11:36 +01:00
James Cole
8d830e178f Merge branch 'develop' of github.com:firefly-iii/firefly-iii into develop 2025-02-20 08:08:18 +01:00
James Cole
334a521ca1 Better fix for nullpointer. 2025-02-20 08:08:07 +01:00
github-actions
12629a1955 Auto commit for release 'develop' on 2025-02-20 2025-02-20 08:00:12 +01:00
James Cole
2e3669a32f Fix #9871 2025-02-20 07:43:32 +01:00
James Cole
ea337607c4 Fix #9868 2025-02-20 07:30:30 +01:00
James Cole
f7f317a3b2 Fix #9863 2025-02-20 07:28:24 +01:00
James Cole
adbf6defe5 Catch nullpointer. 2025-02-20 06:21:29 +01:00
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
108 changed files with 2098 additions and 1402 deletions

View File

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

View File

@@ -19,7 +19,7 @@ SITE_OWNER=mail@example.com
APP_KEY=SomeRandomStringOf32CharsExactly
# Firefly III will launch using this language (for new users and unauthenticated visitors)
# For a list of available languages: https://github.com/firefly-iii/firefly-iii/tree/main/resources/lang
# For a list of available languages: https://github.com/firefly-iii/firefly-iii/blob/main/config/firefly.php#L123
#
# If text is still in English, remember that not everything may have been translated.
DEFAULT_LANGUAGE=en_US

View File

@@ -204,9 +204,9 @@ jobs:
# zip and tar everything
echo 'Zip and tar...'
zip -rq $zipName . -x "*.git*" "*.ci*" "*.github*" "*node_modules*" "*output.txt*"
zip -rq $zipName . -x "*.git*" "*.ci*" "*.github*" "*node_modules*" "*output.txt*" "*Procfile*" "*crowdin.yml*" "*sonar-project.properties*"
touch $tarName
tar --exclude=$tarName --exclude=$zipName --exclude='./.git' --exclude='./.ci' --exclude='./.github' --exclude='./node_modules' --exclude='./output.txt' -czf $tarName .
tar --exclude=$tarName --exclude=$zipName --exclude='./.git' --exclude='./.ci' --exclude='./.github' --exclude='./node_modules' --exclude='./output.txt' --exclude='./Procfile' --exclude='../crowdin.yml' --exclude='./sonar-project.properties' -czf $tarName .
# add sha256 sum
echo 'Sha sum ...'
@@ -225,7 +225,7 @@ jobs:
sudo chown -R runner:docker output.txt
echo "Weekly development release of Firefly III with the latest fixes, translations and features. Docker users can find this release under the \`develop\` tag." >> output.txt
echo "" >> output.txt
echo "This release was created on **$(date +'%Y-%m-%d')** and may contain unexpected bugs. Data loss is rare but is not impossible. The releases are signed, and you can verify them using the [Firefly III releases PGP key](https://docs.firefly-iii.org/explanation/more-information/signatures/)." >> output.txt
echo "This release was created on **$(date +'%Y-%m-%d %H:%M')** and may contain unexpected bugs. Data loss is rare but is not impossible. The releases are signed, and you can verify them using the [Firefly III releases PGP key](https://docs.firefly-iii.org/explanation/more-information/signatures/)." >> output.txt
echo "" >> output.txt
echo "* Please read the installation instructions for [Docker](https://docs.firefly-iii.org/how-to/firefly-iii/installation/docker/), [Portainer](https://docs.firefly-iii.org/how-to/firefly-iii/installation/portainer/), [Kubernetes](https://docs.firefly-iii.org/how-to/firefly-iii/installation/kubernetes/) or [self-managed servers](https://docs.firefly-iii.org/how-to/firefly-iii/installation/self-managed/)" >> output.txt
echo "* Or read the upgrade instructions for [Docker](https://docs.firefly-iii.org/how-to/firefly-iii/upgrade/docker/), [Kubernetes](https://docs.firefly-iii.org/how-to/firefly-iii/upgrade/kubernetes/) or [self-managed servers](https://docs.firefly-iii.org/how-to/firefly-iii/upgrade/self-managed/)" >> output.txt
@@ -240,7 +240,7 @@ jobs:
sudo chown -R runner:docker output.txt
echo "Irregular BRANCH release of Firefly III. This release contains specific features or changes. Docker users can find this release under the \`$version\` tag." >> output.txt
echo "" >> output.txt
echo "This release was created on **$(date +'%Y-%m-%d')** and may contain unexpected bugs. Data loss is rare but is not impossible. The releases are signed, and you can verify them using the [Firefly III releases PGP key](https://docs.firefly-iii.org/explanation/more-information/signatures/)." >> output.txt
echo "This release was created on **$(date +'%Y-%m-%d %H:%M')** and may contain unexpected bugs. Data loss is rare but is not impossible. The releases are signed, and you can verify them using the [Firefly III releases PGP key](https://docs.firefly-iii.org/explanation/more-information/signatures/)." >> output.txt
echo "" >> output.txt
echo "* Please read the installation instructions for [Docker](https://docs.firefly-iii.org/how-to/firefly-iii/installation/docker/), [Portainer](https://docs.firefly-iii.org/how-to/firefly-iii/installation/portainer/), [Kubernetes](https://docs.firefly-iii.org/how-to/firefly-iii/installation/kubernetes/) or [self-managed servers](https://docs.firefly-iii.org/how-to/firefly-iii/installation/self-managed/)" >> output.txt
echo "* Or read the upgrade instructions for [Docker](https://docs.firefly-iii.org/how-to/firefly-iii/upgrade/docker/), [Kubernetes](https://docs.firefly-iii.org/how-to/firefly-iii/upgrade/kubernetes/) or [self-managed servers](https://docs.firefly-iii.org/how-to/firefly-iii/upgrade/self-managed/)" >> output.txt
@@ -268,7 +268,7 @@ jobs:
sudo chown -R runner:docker output.txt
echo "Very early ALPHA release of Firefly III. This release contains specific features or changes. Docker users can find this release under the \`$version\` tag." >> output.txt
echo '' >> output.txt
echo "This release was created on **$(date +'%Y-%m-%d')** and may contain unexpected bugs. Data loss is rare but is not impossible. The releases are signed, and you can verify them using the [Firefly III releases PGP key](https://docs.firefly-iii.org/explanation/more-information/signatures/)." >> output.txt
echo "This release was created on **$(date +'%Y-%m-%d %H:%M')** and may contain unexpected bugs. Data loss is rare but is not impossible. The releases are signed, and you can verify them using the [Firefly III releases PGP key](https://docs.firefly-iii.org/explanation/more-information/signatures/)." >> output.txt
echo '' >> output.txt
echo '### Instructions' >> output.txt
echo '' >> output.txt
@@ -286,7 +286,7 @@ jobs:
sudo chown -R runner:docker output.txt
echo "Very early BETA release of Firefly III. This release contains specific features or changes. Docker users can find this release under the \`$version\` tag." >> output.txt
echo '' >> output.txt
echo "This release was created on **$(date +'%Y-%m-%d')** and may contain unexpected bugs. Data loss is rare but is not impossible. The releases are signed, and you can verify them using the [Firefly III releases PGP key](https://docs.firefly-iii.org/explanation/more-information/signatures/)." >> output.txt
echo "This release was created on **$(date +'%Y-%m-%d %H:%M')** and may contain unexpected bugs. Data loss is rare but is not impossible. The releases are signed, and you can verify them using the [Firefly III releases PGP key](https://docs.firefly-iii.org/explanation/more-information/signatures/)." >> output.txt
echo '' >> output.txt
echo '### Instructions' >> output.txt
echo '' >> output.txt

9
.gitignore vendored
View File

@@ -14,7 +14,16 @@ public/build
# ignore v1 build files
resources/assets/v1/node_modules
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
resources/assets/v2/node_modules
resources/assets/v2/build
public/v2/i18n

View File

@@ -4,6 +4,7 @@ Over time, many people have contributed to Firefly III. Their efforts are not al
Please find below all the people who contributed to the Firefly III code. Their names are mentioned in the year of their first contribution.
## 2025
- Jose Diaz-Gonzalez
- SoftBrix
## 2024

View File

@@ -30,6 +30,7 @@ use FireflyIII\Helpers\Collector\GroupCollectorInterface;
use FireflyIII\Models\Account;
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use FireflyIII\Support\Http\Api\TransactionFilter;
use FireflyIII\Support\JsonApi\Enrichments\TransactionGroupEnrichment;
use FireflyIII\Transformers\AttachmentTransformer;
use FireflyIII\Transformers\PiggyBankTransformer;
use FireflyIII\Transformers\TransactionGroupTransformer;
@@ -140,18 +141,18 @@ class ListController extends Controller
*/
public function transactions(Request $request, Account $account): JsonResponse
{
$pageSize = $this->parameters->get('limit');
$type = $request->get('type') ?? 'default';
$pageSize = $this->parameters->get('limit');
$type = $request->get('type') ?? 'default';
$this->parameters->set('type', $type);
$types = $this->mapTransactionTypes($this->parameters->get('type'));
$manager = $this->getManager();
$types = $this->mapTransactionTypes($this->parameters->get('type'));
$manager = $this->getManager();
/** @var User $admin */
$admin = auth()->user();
$admin = auth()->user();
// use new group collector:
/** @var GroupCollectorInterface $collector */
$collector = app(GroupCollectorInterface::class);
$collector = app(GroupCollectorInterface::class);
$collector->setUser($admin)->setAccounts(new Collection([$account]))
->withAPIInformation()->setLimit($pageSize)->setPage($this->parameters->get('page'))->setTypes($types)
;
@@ -163,15 +164,19 @@ class ListController extends Controller
$collector->setEnd($this->parameters->get('end'));
}
$paginator = $collector->getPaginatedGroups();
$paginator = $collector->getPaginatedGroups();
$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 */
$transformer = app(TransactionGroupTransformer::class);
$transformer = app(TransactionGroupTransformer::class);
$transformer->setParameters($this->parameters);
$resource = new FractalCollection($groups, $transformer, 'transactions');
$resource = new FractalCollection($transactions, $transformer, 'transactions');
$resource->setPaginator(new IlluminatePaginatorAdapter($paginator));
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\Repositories\Account\AccountRepositoryInterface;
use FireflyIII\Support\Http\Api\AccountFilter;
use FireflyIII\Support\JsonApi\Enrichments\AccountEnrichment;
use FireflyIII\Transformers\AccountTransformer;
use FireflyIII\User;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Pagination\LengthAwarePaginator;
@@ -88,9 +90,17 @@ class ShowController extends Controller
$count = $collection->count();
// continue sort:
$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:
$paginator = new LengthAwarePaginator($accounts, $count, $pageSize, $this->parameters->get('page'));
$paginator->setPath(route('api.v1.accounts.index').$this->buildParams());
@@ -118,6 +128,16 @@ class ShowController extends Controller
$account->refresh();
$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 */
$transformer = app(AccountTransformer::class);
$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\Requests\Models\Account\StoreRequest;
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use FireflyIII\Support\JsonApi\Enrichments\AccountEnrichment;
use FireflyIII\Transformers\AccountTransformer;
use FireflyIII\User;
use Illuminate\Http\JsonResponse;
use League\Fractal\Resource\Item;
@@ -69,6 +71,15 @@ class StoreController extends Controller
$account = $this->repository->store($data);
$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 */
$transformer = app(AccountTransformer::class);
$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\Models\Account;
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use FireflyIII\Support\JsonApi\Enrichments\AccountEnrichment;
use FireflyIII\Transformers\AccountTransformer;
use FireflyIII\User;
use Illuminate\Http\JsonResponse;
use League\Fractal\Resource\Item;
@@ -73,6 +75,15 @@ class UpdateController extends Controller
$account->refresh();
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 */
$transformer = app(AccountTransformer::class);
$transformer->setParameters($this->parameters);

View File

@@ -30,6 +30,7 @@ use FireflyIII\Helpers\Collector\GroupCollectorInterface;
use FireflyIII\Models\Bill;
use FireflyIII\Repositories\Bill\BillRepositoryInterface;
use FireflyIII\Support\Http\Api\TransactionFilter;
use FireflyIII\Support\JsonApi\Enrichments\TransactionGroupEnrichment;
use FireflyIII\Transformers\AttachmentTransformer;
use FireflyIII\Transformers\RuleTransformer;
use FireflyIII\Transformers\TransactionGroupTransformer;
@@ -176,7 +177,11 @@ class ListController extends Controller
// get paginator.
$paginator = $collector->getPaginatedGroups();
$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 */
$transformer = app(TransactionGroupTransformer::class);

View File

@@ -32,6 +32,7 @@ use FireflyIII\Models\Budget;
use FireflyIII\Repositories\Budget\BudgetLimitRepositoryInterface;
use FireflyIII\Repositories\Budget\BudgetRepositoryInterface;
use FireflyIII\Support\Http\Api\TransactionFilter;
use FireflyIII\Support\JsonApi\Enrichments\TransactionGroupEnrichment;
use FireflyIII\Transformers\AttachmentTransformer;
use FireflyIII\Transformers\BudgetLimitTransformer;
use FireflyIII\Transformers\TransactionGroupTransformer;
@@ -172,7 +173,11 @@ class ListController extends Controller
$paginator = $collector->getPaginatedGroups();
$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 */
$transformer = app(TransactionGroupTransformer::class);
@@ -232,7 +237,11 @@ class ListController extends Controller
$paginator = $collector->getPaginatedGroups();
$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 */
$transformer = app(TransactionGroupTransformer::class);

View File

@@ -30,6 +30,7 @@ use FireflyIII\Helpers\Collector\GroupCollectorInterface;
use FireflyIII\Models\Budget;
use FireflyIII\Models\BudgetLimit;
use FireflyIII\Support\Http\Api\TransactionFilter;
use FireflyIII\Support\JsonApi\Enrichments\TransactionGroupEnrichment;
use FireflyIII\Transformers\TransactionGroupTransformer;
use FireflyIII\User;
use Illuminate\Http\JsonResponse;
@@ -84,7 +85,11 @@ class ListController extends Controller
$collector->setTypes($types);
$paginator = $collector->getPaginatedGroups();
$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 */
$transformer = app(TransactionGroupTransformer::class);

View File

@@ -30,6 +30,7 @@ use FireflyIII\Helpers\Collector\GroupCollectorInterface;
use FireflyIII\Models\Category;
use FireflyIII\Repositories\Category\CategoryRepositoryInterface;
use FireflyIII\Support\Http\Api\TransactionFilter;
use FireflyIII\Support\JsonApi\Enrichments\TransactionGroupEnrichment;
use FireflyIII\Transformers\AttachmentTransformer;
use FireflyIII\Transformers\TransactionGroupTransformer;
use FireflyIII\User;
@@ -139,7 +140,11 @@ class ListController extends Controller
$paginator = $collector->getPaginatedGroups();
$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 */
$transformer = app(TransactionGroupTransformer::class);

View File

@@ -28,9 +28,11 @@ use FireflyIII\Api\V1\Controllers\Controller;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Models\PiggyBank;
use FireflyIII\Repositories\PiggyBank\PiggyBankRepositoryInterface;
use FireflyIII\Support\JsonApi\Enrichments\AccountEnrichment;
use FireflyIII\Transformers\AccountTransformer;
use FireflyIII\Transformers\AttachmentTransformer;
use FireflyIII\Transformers\PiggyBankEventTransformer;
use FireflyIII\User;
use Illuminate\Http\JsonResponse;
use Illuminate\Pagination\LengthAwarePaginator;
use League\Fractal\Pagination\IlluminatePaginatorAdapter;
@@ -75,17 +77,26 @@ class ListController extends Controller
$collection = $piggyBank->accounts;
$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:
$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());
/** @var AccountTransformer $transformer */
$transformer = app(AccountTransformer::class);
$transformer->setParameters($this->parameters);
$resource = new FractalCollection($events, $transformer, 'accounts');
$resource = new FractalCollection($accounts, $transformer, 'accounts');
$resource->setPaginator(new IlluminatePaginatorAdapter($paginator));
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\Repositories\Recurring\RecurringRepositoryInterface;
use FireflyIII\Support\Http\Api\TransactionFilter;
use FireflyIII\Support\JsonApi\Enrichments\TransactionGroupEnrichment;
use FireflyIII\Transformers\TransactionGroupTransformer;
use FireflyIII\User;
use Illuminate\Http\JsonResponse;
@@ -110,7 +111,11 @@ class ListController extends Controller
$paginator = $collector->getPaginatedGroups();
$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 */
$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\Models\Rule;
use FireflyIII\Repositories\Rule\RuleRepositoryInterface;
use FireflyIII\Support\JsonApi\Enrichments\TransactionGroupEnrichment;
use FireflyIII\TransactionRules\Engine\RuleEngineInterface;
use FireflyIII\Transformers\TransactionGroupTransformer;
use FireflyIII\User;
@@ -94,6 +95,11 @@ class TriggerController extends Controller
$transactions = $ruleEngine->find();
$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->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\Models\RuleGroup;
use FireflyIII\Repositories\RuleGroup\RuleGroupRepositoryInterface;
use FireflyIII\Support\JsonApi\Enrichments\TransactionGroupEnrichment;
use FireflyIII\TransactionRules\Engine\RuleEngineInterface;
use FireflyIII\Transformers\TransactionGroupTransformer;
use FireflyIII\User;
@@ -100,6 +101,11 @@ class TriggerController extends Controller
$transactions = $ruleEngine->find();
$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->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\Repositories\Tag\TagRepositoryInterface;
use FireflyIII\Support\Http\Api\TransactionFilter;
use FireflyIII\Support\JsonApi\Enrichments\TransactionGroupEnrichment;
use FireflyIII\Transformers\AttachmentTransformer;
use FireflyIII\Transformers\TransactionGroupTransformer;
use FireflyIII\User;
@@ -141,7 +142,12 @@ class ListController extends Controller
}
$paginator = $collector->getPaginatedGroups();
$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 */
$transformer = app(TransactionGroupTransformer::class);

View File

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

View File

@@ -34,6 +34,7 @@ use FireflyIII\Helpers\Collector\GroupCollectorInterface;
use FireflyIII\Repositories\TransactionGroup\TransactionGroupRepositoryInterface;
use FireflyIII\Rules\IsDuplicateTransaction;
use FireflyIII\Support\Http\Api\TransactionFilter;
use FireflyIII\Support\JsonApi\Enrichments\TransactionGroupEnrichment;
use FireflyIII\Transformers\TransactionGroupTransformer;
use FireflyIII\User;
use Illuminate\Http\JsonResponse;
@@ -89,6 +90,7 @@ class StoreController extends Controller
$data['user'] = auth()->user();
$data['user_group'] = $this->userGroup;
Log::channel('audit')->info('Store new transaction over API.', $data);
try {
@@ -133,6 +135,11 @@ class StoreController extends Controller
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 */
$transformer = app(TransactionGroupTransformer::class);
$transformer->setParameters($this->parameters);

View File

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

View File

@@ -42,6 +42,8 @@ use FireflyIII\Repositories\Recurring\RecurringRepositoryInterface;
use FireflyIII\Repositories\Rule\RuleRepositoryInterface;
use FireflyIII\Support\Http\Api\AccountFilter;
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\AvailableBudgetTransformer;
use FireflyIII\Transformers\BillTransformer;
@@ -100,6 +102,15 @@ class ListController extends Controller
$count = $collection->count();
$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:
$paginator = new LengthAwarePaginator($accounts, $count, $pageSize, $this->parameters->get('page'));
$paginator->setPath(route('api.v1.currencies.accounts', [$currency->code]).$this->buildParams());
@@ -360,7 +371,11 @@ class ListController extends Controller
}
$paginator = $collector->getPaginatedGroups();
$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 */
$transformer = app(TransactionGroupTransformer::class);

View File

@@ -30,6 +30,7 @@ use FireflyIII\Helpers\Collector\GroupCollectorInterface;
use FireflyIII\Models\LinkType;
use FireflyIII\Repositories\LinkType\LinkTypeRepositoryInterface;
use FireflyIII\Support\Http\Api\TransactionFilter;
use FireflyIII\Support\JsonApi\Enrichments\TransactionGroupEnrichment;
use FireflyIII\Transformers\TransactionGroupTransformer;
use FireflyIII\User;
use Illuminate\Http\JsonResponse;
@@ -109,7 +110,11 @@ class ListController extends Controller
}
$paginator = $collector->getPaginatedGroups();
$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 */
$transformer = app(TransactionGroupTransformer::class);

View File

@@ -26,8 +26,10 @@ namespace FireflyIII\Api\V1\Controllers\Search;
use FireflyIII\Api\V1\Controllers\Controller;
use FireflyIII\Support\Http\Api\AccountFilter;
use FireflyIII\Support\JsonApi\Enrichments\AccountEnrichment;
use FireflyIII\Support\Search\AccountSearch;
use FireflyIII\Transformers\AccountTransformer;
use FireflyIII\User;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
@@ -81,6 +83,15 @@ class AccountController extends Controller
$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 */
$transformer = app(AccountTransformer::class);
$transformer->setParameters($this->parameters);

View File

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

View File

@@ -102,7 +102,7 @@ class BasicController extends Controller
$balanceData = $this->getBalanceInformation($start, $end);
$billData = $this->getBillInformation($start, $end);
$spentData = $this->getLeftToSpendInfo($start, $end);
$netWorthData = $this->getNetWorthInfo($start, $end);
$netWorthData = $this->getNetWorthInfo($end);
// $balanceData = [];
// $billData = [];
// $spentData = [];
@@ -319,18 +319,13 @@ class BasicController extends Controller
return $return;
}
private function getNetWorthInfo(Carbon $start, Carbon $end): array
private function getNetWorthInfo(Carbon $end): array
{
Log::debug('getNetWorthInfo');
$end->endOfDay();
/** @var User $user */
$user = auth()->user();
$date = now(config('app.timezone'));
// 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());
}
Log::debug(sprintf('getNetWorthInfo up until "%s".', $end->format('Y-m-d H:i:s')));
/** @var NetWorthInterface $netWorthHelper */
$netWorthHelper = app(NetWorthInterface::class);
@@ -346,7 +341,7 @@ class BasicController extends Controller
}
);
$netWorthSet = $netWorthHelper->byAccounts($filtered, $date);
$netWorthSet = $netWorthHelper->byAccounts($filtered, $end);
$return = [];
foreach ($netWorthSet as $key => $data) {
if ('native' === $key) {
@@ -370,6 +365,22 @@ class BasicController extends Controller
'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');
return $return;

View File

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

View File

@@ -65,25 +65,6 @@ class StoreRequest extends FormRequest
return $data;
}
private function parseAccounts(mixed $array): array
{
if (!is_array($array)) {
return [];
}
$return = [];
foreach ($array as $entry) {
if (!is_array($entry)) {
continue;
}
$return[] = [
'account_id' => $this->integerFromValue((string) ($entry['account_id'] ?? '0')),
'current_amount' => $this->clearString((string) ($entry['current_amount'] ?? '0')),
];
}
return $return;
}
/**
* The rules that the incoming request must be matched against.
*/

View File

@@ -25,8 +25,8 @@ declare(strict_types=1);
namespace FireflyIII\Api\V1\Requests\Models\PiggyBank;
use FireflyIII\Models\PiggyBank;
use FireflyIII\Rules\IsAssetAccountId;
use FireflyIII\Rules\IsValidPositiveAmount;
use FireflyIII\Rules\IsValidZeroOrMoreAmount;
use FireflyIII\Rules\LessThanPiggyTarget;
use FireflyIII\Support\Request\ChecksLogin;
use FireflyIII\Support\Request\ConvertsDataTypes;
@@ -45,20 +45,23 @@ class UpdateRequest extends FormRequest
*/
public function getAll(): array
{
$fields = [
'name' => ['name', 'convertString'],
'account_id' => ['account_id', 'convertInteger'],
'targetamount' => ['target_amount', 'convertString'],
'current_amount' => ['current_amount', 'convertString'],
'startdate' => ['start_date', 'convertDateTime'],
'targetdate' => ['target_date', 'convertDateTime'],
'notes' => ['notes', 'stringWithNewlines'],
'order' => ['order', 'convertInteger'],
'object_group_title' => ['object_group_title', 'convertString'],
'object_group_id' => ['object_group_id', 'convertInteger'],
$fields = [
'name' => ['name', 'convertString'],
'target_amount' => ['target_amount', 'convertString'],
'start_date' => ['start_date', 'convertDateTime'],
'target_date' => ['target_date', 'convertDateTime'],
'notes' => ['notes', 'stringWithNewlines'],
'order' => ['order', 'convertInteger'],
'object_group_title' => ['object_group_title', 'convertString'],
'object_group_id' => ['object_group_id', 'convertInteger'],
'transaction_currency_code' => ['transaction_currency_code', 'convertString'],
'transaction_currency_id' => ['transaction_currency_id', 'convertInteger'],
];
return $this->getAllData($fields);
$result = $this->getAllData($fields);
$result['accounts'] = $this->parseAccounts($this->get('accounts'));
return $result;
}
/**
@@ -70,13 +73,20 @@ class UpdateRequest extends FormRequest
$piggyBank = $this->route()->parameter('piggyBank');
return [
'name' => 'min:1|max:255|uniquePiggyBankForUser:'.$piggyBank->id,
'current_amount' => ['nullable', new LessThanPiggyTarget(), new IsValidPositiveAmount()],
'target_amount' => ['nullable', new IsValidPositiveAmount()],
'start_date' => 'date|nullable',
'target_date' => 'date|nullable|after:start_date',
'notes' => 'max:65000',
'account_id' => ['belongsToUser:accounts', new IsAssetAccountId()],
'name' => 'min:1|max:255|uniquePiggyBankForUser:'.$piggyBank->id,
'current_amount' => ['nullable', new LessThanPiggyTarget(), new IsValidPositiveAmount()],
'target_amount' => ['nullable', new IsValidZeroOrMoreAmount()],
'start_date' => 'date|nullable',
'target_date' => 'date|nullable|after:start_date',
'notes' => 'max:65000',
'accounts' => 'required',
'accounts.*' => 'array|required',
'accounts.*.account_id' => ['required', 'numeric', 'belongsToUser:accounts,id'],
'accounts.*.current_amount' => ['numeric', new IsValidZeroOrMoreAmount()],
'object_group_id' => 'numeric|belongsToUser:object_groups,id',
'object_group_title' => ['min:1', 'max:255'],
'transaction_currency_id' => 'exists:transaction_currencies,id|nullable',
'transaction_currency_code' => 'exists:transaction_currencies,code|nullable',
];
}
}

View File

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

View File

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

View File

@@ -73,6 +73,7 @@ class StoreController extends Controller
$userGroup = $request->getUserGroup();
$data['user_group'] = $userGroup;
// overrule user group and see where we end up.
// what happens when we refer to a budget that is not in this user group?

View File

@@ -30,6 +30,7 @@ use FireflyIII\Handlers\Events\UpdatedGroupEventHandler;
use FireflyIII\Models\TransactionGroup;
use FireflyIII\Models\TransactionJournal;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\DB;
class CorrectsGroupAccounts extends Command
{
@@ -45,7 +46,7 @@ class CorrectsGroupAccounts extends Command
{
$groups = [];
$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 */

View File

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

View File

@@ -30,6 +30,7 @@ use FireflyIII\Models\Transaction;
use FireflyIII\Models\TransactionJournal;
use FireflyIII\Support\Models\AccountBalanceCalculator;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
class CorrectsUnevenAmount extends Command
@@ -118,10 +119,10 @@ class CorrectsUnevenAmount extends Command
private function fixUnevenAmounts(): void
{
$journals = \DB::table('transactions')
$journals = DB::table('transactions')
->groupBy('transaction_journal_id')
->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 */
@@ -262,7 +263,7 @@ class CorrectsUnevenAmount extends Command
private function matchCurrencies(): void
{
$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.*'])
;

View File

@@ -29,6 +29,7 @@ use FireflyIII\Models\Transaction;
use FireflyIII\Models\TransactionJournal;
use Illuminate\Console\Command;
use Illuminate\Database\QueryException;
use Illuminate\Support\Facades\DB;
class RemovesEmptyJournals extends Command
{
@@ -56,7 +57,7 @@ class RemovesEmptyJournals extends Command
{
$set = Transaction::whereNull('deleted_at')
->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;

View File

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

View File

@@ -31,6 +31,7 @@ use FireflyIII\Support\Cronjobs\AutoBudgetCronjob;
use FireflyIII\Support\Cronjobs\BillWarningCronjob;
use FireflyIII\Support\Cronjobs\ExchangeRatesCronjob;
use FireflyIII\Support\Cronjobs\RecurringCronjob;
use FireflyIII\Support\Cronjobs\UpdateCheckCronjob;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Log;
@@ -43,6 +44,7 @@ class Cron extends Command
protected $signature = 'firefly-iii:cron
{--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.}
{--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.}
{--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.}
@@ -51,7 +53,11 @@ class Cron extends Command
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;
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.
if ($doAll || $this->option('create-recurring')) {
try {
@@ -204,4 +221,21 @@ class Cron extends Command
$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 Illuminate\Console\Command;
use Illuminate\Contracts\Encryption\DecryptException;
use Illuminate\Support\Facades\DB;
class RemovesDatabaseDecryption extends Command
{
@@ -101,7 +102,7 @@ class RemovesDatabaseDecryption extends Command
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 */
foreach ($rows as $row) {
@@ -135,7 +136,7 @@ class RemovesDatabaseDecryption extends Command
}
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 Illuminate\Console\Command;
use Illuminate\Support\Facades\DB;
class RepairsPostgresSequences extends Command
{
@@ -40,7 +41,7 @@ class RepairsPostgresSequences extends Command
*/
public function handle(): int
{
if ('pgsql' !== \DB::connection()->getName()) {
if ('pgsql' !== DB::connection()->getName()) {
return 0;
}
$this->friendlyLine('Going to verify PostgreSQL table sequences.');
@@ -49,8 +50,8 @@ class RepairsPostgresSequences extends Command
foreach ($tablesToCheck as $tableToCheck) {
$this->friendlyLine(sprintf('Checking the next id sequence for table "%s".', $tableToCheck));
$highestId = \DB::table($tableToCheck)->select(\DB::raw('MAX(id)'))->first();
$nextId = \DB::table($tableToCheck)->select(\DB::raw(sprintf('nextval(\'%s_id_seq\')', $tableToCheck)))->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();
if (null === $nextId) {
$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
\DB::select(sprintf('SELECT setval(\'%s_id_seq\', %d)', $tableToCheck, $highestId->max));
$highestId = \DB::table($tableToCheck)->select(\DB::raw('MAX(id)'))->first();
$nextId = \DB::table($tableToCheck)->select(\DB::raw(sprintf('nextval(\'%s_id_seq\')', $tableToCheck)))->first();
DB::select(sprintf('SELECT setval(\'%s_id_seq\', %d)', $tableToCheck, $highestId->max));
$highestId = DB::table($tableToCheck)->select(DB::raw('MAX(id)'))->first();
$nextId = DB::table($tableToCheck)->select(DB::raw(sprintf('nextval(\'%s_id_seq\')', $tableToCheck)))->first();
if ($nextId->nextval > $highestId->max) { // @phpstan-ignore-line
$this->friendlyInfo(sprintf('Table "%s" autoincrement corrected.', $tableToCheck));
}

View File

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

View File

@@ -35,6 +35,7 @@ use FireflyIII\Repositories\Journal\JournalRepositoryInterface;
use FireflyIII\Services\Internal\Destroy\JournalDestroyService;
use Illuminate\Console\Command;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\DB;
class UpgradesToGroups extends Command
{
@@ -237,7 +238,8 @@ class UpgradesToGroups extends Command
return [
'type' => strtolower($journal->transactionType->type),
'date' => $journal->date,
'user' => $journal->user_id,
'user' => $journal->user,
'user_group' => $journal->user->userGroup,
'currency_id' => $transaction->transaction_currency_id,
'foreign_currency_id' => $transaction->foreign_currency_id,
'amount' => $transaction->amount,
@@ -364,7 +366,7 @@ class UpgradesToGroups extends Command
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'),
'updated_at' => date('Y-m-d H:i:s'),
@@ -372,7 +374,7 @@ class UpgradesToGroups extends Command
'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;
}

View File

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

View File

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

View File

@@ -28,6 +28,7 @@ use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Helpers\Update\UpdateTrait;
use FireflyIII\Models\Configuration;
use FireflyIII\Repositories\User\UserRepositoryInterface;
use Illuminate\Support\Facades\Log;
/**
* Class VersionCheckEventHandler
@@ -45,13 +46,13 @@ class VersionCheckEventHandler
*/
public function checkForUpdates(RequestedVersionCheckStatus $event): void
{
app('log')->debug('Now in checkForUpdates()');
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) {
app('log')->debug('Update check is not enabled.');
Log::debug('Update check is not enabled.');
$this->warnToCheckForUpdates($event);
return;
@@ -61,7 +62,7 @@ class VersionCheckEventHandler
$repository = app(UserRepositoryInterface::class);
$user = $event->user;
if (!$repository->hasRole($user, 'owner')) {
app('log')->debug('User is not admin, done.');
Log::debug('User is not admin, done.');
return;
}
@@ -70,14 +71,14 @@ class VersionCheckEventHandler
$lastCheckTime = app('fireflyconfig')->get('last_update_check', time());
$now = time();
$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) {
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;
}
// 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();
session()->flash($release['level'], $release['message']);
@@ -93,7 +94,7 @@ class VersionCheckEventHandler
$repository = app(UserRepositoryInterface::class);
$user = $event->user;
if (!$repository->hasRole($user, 'owner')) {
app('log')->debug('User is not admin, done.');
Log::debug('User is not admin, done.');
return;
}
@@ -102,14 +103,14 @@ class VersionCheckEventHandler
$lastCheckTime = app('fireflyconfig')->get('last_update_warning', time());
$now = time();
$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) {
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;
}
// 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'));
app('fireflyconfig')->set('last_update_warning', time());

View File

@@ -26,11 +26,14 @@ namespace FireflyIII\Handlers\Observer;
use FireflyIII\Models\Account;
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\UserGroups\Account\AccountRepositoryInterface;
use FireflyIII\Support\Facades\Amount;
use FireflyIII\Support\Http\Api\ExchangeRateConverter;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
/**
@@ -72,24 +75,31 @@ class AccountObserver
*/
public function deleting(Account $account): void
{
// app('log')->debug('Observe "deleting" of an account.');
$account->accountMeta()->delete();
app('log')->debug('Observe "deleting" of an account.');
$repository = app(AttachmentRepositoryInterface::class);
$repository->setUser($account->user);
/** @var PiggyBank $piggy */
foreach ($account->piggyBanks()->get() as $piggy) {
$piggy->accounts()->detach($account);
}
DB::table('account_piggy_bank')->where('account_id', $account->id)->delete();
/** @var Attachment $attachment */
foreach ($account->attachments()->get() as $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->locations()->delete();
}

View File

@@ -225,11 +225,13 @@ class ReconcileController extends Controller
]
);
$submission = [
'user' => auth()->user()->id,
'group_title' => null,
'transactions' => [
'user' => auth()->user(),
'user_group' => auth()->user()->userGroup,
'group_title' => null,
'transactions' => [
[
'user' => auth()->user()->id,
'user' => auth()->user(),
'user_group' => auth()->user()->userGroup,
'type' => strtolower(TransactionTypeEnum::RECONCILIATION->value),
'date' => $end,
'order' => 0,

View File

@@ -29,6 +29,7 @@ use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Helpers\Collector\GroupCollectorInterface;
use FireflyIII\Http\Controllers\Controller;
use FireflyIII\Models\Account;
use FireflyIII\Models\Transaction;
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use FireflyIII\Support\Facades\Steam;
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)
{
$objectType = config(sprintf('firefly.shortNamesByFullName.%s', $account->accountType->type));
if (!$this->isEditableAccount($account)) {

View File

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

View File

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

View File

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

View File

@@ -42,6 +42,7 @@ use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Routing\Redirector;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\DB;
use Illuminate\View\View;
use Laravel\Passport\ClientRepository;
@@ -139,7 +140,7 @@ class ProfileController extends Controller
/** @var User $user */
$user = auth()->user();
$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;
$userId = $user->id;
$enabled2FA = null !== $user->mfa_secret;

View File

@@ -103,7 +103,7 @@ class ShowController extends Controller
foreach (array_keys($groupArray['transactions']) as $index) {
$groupArray['transactions'][$index]['tags'] = $this->repository->getTagObjects(
$groupArray['transactions'][$index]['transaction_journal_id']
(int) $groupArray['transactions'][$index]['transaction_journal_id']
);
}

View File

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

View File

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

View File

@@ -48,14 +48,15 @@ class Account extends Model
protected $casts
= [
'created_at' => 'datetime',
'updated_at' => 'datetime',
'user_id' => 'integer',
'deleted_at' => 'datetime',
'active' => 'boolean',
'encrypted' => 'boolean',
'virtual_balance' => 'string',
'native_virtual_balance' => 'string',
'created_at' => 'datetime',
'updated_at' => 'datetime',
'user_id' => 'integer',
'user_group_id' => 'integer',
'deleted_at' => 'datetime',
'active' => 'boolean',
'encrypted' => 'boolean',
'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'];

View File

@@ -42,13 +42,15 @@ class Attachment extends Model
protected $casts
= [
'created_at' => 'datetime',
'updated_at' => 'datetime',
'deleted_at' => 'datetime',
'uploaded' => 'boolean',
'created_at' => 'datetime',
'updated_at' => 'datetime',
'deleted_at' => 'datetime',
'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).

View File

@@ -41,14 +41,16 @@ class AvailableBudget extends Model
protected $casts
= [
'created_at' => 'datetime',
'updated_at' => 'datetime',
'deleted_at' => 'datetime',
'start_date' => 'date',
'end_date' => 'date',
'transaction_currency_id' => 'int',
'amount' => 'string',
'native_amount' => 'string',
'created_at' => 'datetime',
'updated_at' => 'datetime',
'deleted_at' => 'datetime',
'start_date' => 'date',
'end_date' => 'date',
'transaction_currency_id' => 'int',
'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'];

View File

@@ -43,14 +43,16 @@ class Budget extends Model
protected $casts
= [
'created_at' => 'datetime',
'updated_at' => 'datetime',
'deleted_at' => 'datetime',
'active' => 'boolean',
'encrypted' => 'boolean',
'created_at' => 'datetime',
'updated_at' => 'datetime',
'deleted_at' => 'datetime',
'active' => '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'];

View File

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

View File

@@ -40,14 +40,15 @@ class CurrencyExchangeRate extends Model
protected $casts
= [
'created_at' => 'datetime',
'updated_at' => 'datetime',
'user_id' => 'int',
'from_currency_id' => 'int',
'to_currency_id' => 'int',
'date' => SeparateTimezoneCaster::class,
'rate' => 'string',
'user_rate' => 'string',
'created_at' => 'datetime',
'updated_at' => 'datetime',
'user_id' => 'integer',
'user_group_id' => 'integer',
'from_currency_id' => 'integer',
'to_currency_id' => 'integer',
'date' => SeparateTimezoneCaster::class,
'rate' => 'string',
'user_rate' => 'string',
];
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 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'];
public function user(): BelongsTo

View File

@@ -39,10 +39,12 @@ class InvitedUser extends Model
protected $casts
= [
'expires' => SeparateTimezoneCaster::class,
'redeemed' => 'boolean',
'expires' => SeparateTimezoneCaster::class,
'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).

View File

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

View File

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

View File

@@ -44,22 +44,24 @@ class Recurrence extends Model
protected $casts
= [
'created_at' => 'datetime',
'updated_at' => 'datetime',
'deleted_at' => 'datetime',
'title' => 'string',
'id' => 'int',
'description' => 'string',
'first_date' => SeparateTimezoneCaster::class,
'repeat_until' => SeparateTimezoneCaster::class,
'latest_date' => SeparateTimezoneCaster::class,
'repetitions' => 'int',
'active' => 'bool',
'apply_rules' => 'bool',
'created_at' => 'datetime',
'updated_at' => 'datetime',
'deleted_at' => 'datetime',
'title' => 'string',
'id' => 'int',
'description' => 'string',
'first_date' => SeparateTimezoneCaster::class,
'repeat_until' => SeparateTimezoneCaster::class,
'latest_date' => SeparateTimezoneCaster::class,
'repetitions' => 'int',
'active' => 'bool',
'apply_rules' => 'bool',
'user_id' => 'integer',
'user_group_id' => 'integer',
];
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';

View File

@@ -41,17 +41,19 @@ class Rule extends Model
protected $casts
= [
'created_at' => 'datetime',
'updated_at' => 'datetime',
'deleted_at' => 'datetime',
'active' => 'boolean',
'order' => 'int',
'stop_processing' => 'boolean',
'id' => 'int',
'strict' => 'boolean',
'created_at' => 'datetime',
'updated_at' => 'datetime',
'deleted_at' => 'datetime',
'active' => 'boolean',
'order' => 'int',
'stop_processing' => 'boolean',
'id' => 'int',
'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).

View File

@@ -41,12 +41,14 @@ class RuleGroup extends Model
protected $casts
= [
'created_at' => 'datetime',
'updated_at' => 'datetime',
'deleted_at' => 'datetime',
'active' => 'boolean',
'stop_processing' => 'boolean',
'order' => 'int',
'created_at' => 'datetime',
'updated_at' => 'datetime',
'deleted_at' => 'datetime',
'active' => 'boolean',
'stop_processing' => 'boolean',
'order' => 'int',
'user_id' => 'integer',
'user_group_id' => 'integer',
];
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
= [
'created_at' => 'datetime',
'updated_at' => 'datetime',
'deleted_at' => 'datetime',
'date' => SeparateTimezoneCaster::class,
'zoomLevel' => 'int',
'latitude' => 'float',
'longitude' => 'float',
'created_at' => 'datetime',
'updated_at' => 'datetime',
'deleted_at' => 'datetime',
'date' => SeparateTimezoneCaster::class,
'zoomLevel' => 'int',
'latitude' => 'float',
'longitude' => 'float',
'user_id' => 'integer',
'user_group_id' => 'integer',
];
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
= [
'id' => 'integer',
'created_at' => 'datetime',
'updated_at' => 'datetime',
'deleted_at' => 'datetime',
'title' => 'string',
'date' => 'datetime',
'id' => 'integer',
'created_at' => 'datetime',
'updated_at' => 'datetime',
'deleted_at' => 'datetime',
'title' => 'string',
'date' => 'datetime',
'user_id' => 'integer',
'user_group_id' => 'integer',
];
protected $fillable = ['user_id', 'user_group_id', 'title'];

View File

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

View File

@@ -44,10 +44,12 @@ class Webhook extends Model
protected $casts
= [
'active' => 'boolean',
'trigger' => 'integer',
'response' => 'integer',
'delivery' => 'integer',
'active' => 'boolean',
'trigger' => 'integer',
'response' => 'integer',
'delivery' => 'integer',
'user_id' => 'integer',
'user_group_id' => 'integer',
];
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.name', 'ASC');
$query->orderBy('accounts.account_type_id', 'ASC');
$query->orderBy('accounts.id', 'ASC');
}
return $query->get(['accounts.*']);

View File

@@ -42,6 +42,7 @@ use FireflyIII\Support\Repositories\UserGroup\UserGroupTrait;
use Illuminate\Database\Query\JoinClause;
use Illuminate\Pagination\LengthAwarePaginator;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
/**
@@ -556,7 +557,7 @@ class BillRepository implements BillRepositoryInterface
return $this->user->bills()
->where('active', true)
->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

@@ -26,6 +26,7 @@ namespace FireflyIII\Repositories\Currency;
use Carbon\Carbon;
use FireflyIII\Models\CurrencyExchangeRate;
use FireflyIII\Models\TransactionCurrency;
use FireflyIII\Models\UserGroup;
use FireflyIII\User;
use Illuminate\Contracts\Auth\Authenticatable;
use Illuminate\Support\Collection;
@@ -36,6 +37,7 @@ use Illuminate\Support\Collection;
class CurrencyRepository implements CurrencyRepositoryInterface
{
private User $user;
private UserGroup $userGroup;
#[\Override]
public function find(int $currencyId): ?TransactionCurrency
@@ -109,7 +111,14 @@ class CurrencyRepository implements CurrencyRepositoryInterface
public function setUser(null|Authenticatable|User $user): void
{
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 FireflyIII\Models\CurrencyExchangeRate;
use FireflyIII\Models\TransactionCurrency;
use FireflyIII\Models\UserGroup;
use FireflyIII\User;
use Illuminate\Contracts\Auth\Authenticatable;
use Illuminate\Support\Collection;
@@ -67,4 +68,6 @@ interface CurrencyRepositoryInterface
public function setExchangeRate(TransactionCurrency $fromCurrency, TransactionCurrency $toCurrency, Carbon $date, float $rate): CurrencyExchangeRate;
public function setUser(null|Authenticatable|User $user): void;
public function setUserGroup(UserGroup $userGroup): void;
}

View File

@@ -222,7 +222,8 @@ trait ModifiesPiggyBanks
// update the accounts
$factory = new PiggyBankFactory();
$factory->user = $this->user;
$factory->linkToAccountIds($piggyBank, $data['accounts']);
$factory->linkToAccountIds($piggyBank, $data['accounts'] ?? []);
// if the piggy bank is now smaller than the sum of the money saved,
@@ -233,8 +234,8 @@ trait ModifiesPiggyBanks
$difference = bcsub($piggyBank->target_amount, $currentAmount);
// an amount will be removed, create "negative" event:
Log::debug(sprintf('ChangedAmount: is triggered with difference "%s"', $difference));
event(new ChangedAmount($piggyBank, $difference, null, null));
// Log::debug(sprintf('ChangedAmount: is triggered with difference "%s"', $difference));
// event(new ChangedAmount($piggyBank, $difference, null, null));
// 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.

View File

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

View File

@@ -37,7 +37,7 @@ class UpdateRequest implements UpdateRequestInterface
{
public function getUpdateInformation(string $channel): array
{
app('log')->debug(sprintf('Now in getUpdateInformation(%s)', $channel));
Log::debug(sprintf('Now in getUpdateInformation(%s)', $channel));
$information = [
'level' => 'error',
'message' => (string) trans('firefly.unknown_error'),
@@ -46,8 +46,8 @@ class UpdateRequest implements UpdateRequestInterface
// try to get array from update server:
$updateInfo = $this->contactServer($channel);
if ('error' === $updateInfo['level']) {
app('log')->error('Update information contains an error.');
app('log')->error($updateInfo['message']);
Log::error('Update information contains an error.');
Log::error($updateInfo['message']);
$information['message'] = $updateInfo['message'];
return $information;
@@ -59,7 +59,7 @@ class UpdateRequest implements UpdateRequestInterface
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:
$return = [
'version' => config('firefly.version'),
@@ -69,7 +69,7 @@ class UpdateRequest implements UpdateRequestInterface
];
$url = config('firefly.update_endpoint');
app('log')->debug(sprintf('Going to call %s', $url));
Log::debug(sprintf('Going to call %s', $url));
try {
$client = new Client();
@@ -81,17 +81,17 @@ class UpdateRequest implements UpdateRequestInterface
];
$res = $client->request('GET', $url, $options);
} catch (GuzzleException $e) {
app('log')->error('Ran into Guzzle error.');
app('log')->error($e->getMessage());
app('log')->error($e->getTraceAsString());
Log::error('Ran into Guzzle error.');
Log::error($e->getMessage());
Log::error($e->getTraceAsString());
$return['message'] = sprintf('Guzzle: %s', strip_tags($e->getMessage()));
return $return;
}
if (200 !== $res->getStatusCode()) {
app('log')->error(sprintf('Response status from server is %d.', $res->getStatusCode()));
app('log')->error((string) $res->getBody());
Log::error(sprintf('Response status from server is %d.', $res->getStatusCode()));
Log::error((string) $res->getBody());
$return['message'] = sprintf('Error: %d', $res->getStatusCode());
return $return;
@@ -101,16 +101,16 @@ class UpdateRequest implements UpdateRequestInterface
try {
$json = json_decode($body, true, 512, JSON_THROW_ON_ERROR);
} catch (\JsonException $e) {
app('log')->error('Body is not valid JSON');
app('log')->error($body);
Log::error('Body is not valid JSON');
Log::error($body);
$return['message'] = 'Invalid JSON :(';
return $return;
}
if (!array_key_exists($channel, $json['firefly_iii'])) {
app('log')->error(sprintf('No valid update channel "%s"', $channel));
app('log')->error($body);
Log::error(sprintf('No valid update channel "%s"', $channel));
Log::error($body);
$return['message'] = sprintf('Unknown update channel "%s" :(', $channel);
}
@@ -124,7 +124,7 @@ class UpdateRequest implements UpdateRequestInterface
$return['level'] = 'success';
$return['date'] = $date->startOfDay();
app('log')->info('Response from update server', $response);
Log::info('Response from update server', $response);
return $return;
}
@@ -134,7 +134,7 @@ class UpdateRequest implements UpdateRequestInterface
*/
private function parseResult(array $information): array
{
app('log')->debug('Now in parseResult()', $information);
Log::debug('Now in parseResult()', $information);
$current = (string) config('firefly.version');
$latest = (string) $information['version'];
@@ -148,7 +148,7 @@ class UpdateRequest implements UpdateRequestInterface
$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:
if (-1 === $compare) {
@@ -206,7 +206,7 @@ class UpdateRequest implements UpdateRequestInterface
'level' => 'info',
'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;
}
@@ -217,14 +217,14 @@ class UpdateRequest implements UpdateRequestInterface
'level' => 'info',
'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;
}
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(
'firefly.update_new_version_alert',
[
@@ -242,7 +242,7 @@ class UpdateRequest implements UpdateRequestInterface
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(
'firefly.update_new_version_alert',
[
@@ -260,7 +260,7 @@ class UpdateRequest implements UpdateRequestInterface
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(
'firefly.update_new_version_alert',
[
@@ -269,7 +269,7 @@ class UpdateRequest implements UpdateRequestInterface
'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));
return [

View File

@@ -31,6 +31,7 @@ use FireflyIII\Models\RecurrenceTransaction;
use FireflyIII\Models\Transaction;
use FireflyIII\Models\TransactionJournal;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Support\Facades\DB;
/**
* Class AccountDestroyService
@@ -46,8 +47,6 @@ class AccountDestroyService
$this->moveTransactions($account, $moveTo);
$this->updateRecurrences($account, $moveTo);
}
$this->destroyJournals($account);
// delete recurring transactions with this account:
if (null === $moveTo) {
$this->destroyRecurrences($account);
@@ -59,6 +58,7 @@ class AccountDestroyService
// delete account meta:
$account->accountMeta()->delete();
// delete account.
// at this point the account observer interferes and deletes most of the other stuff.
$account->delete();
}
@@ -134,28 +134,8 @@ class AccountDestroyService
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('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);
}
}
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]);
}
private function destroyRecurrences(Account $account): void

View File

@@ -239,7 +239,8 @@ trait AccountServiceTrait
// submit to factory:
$submission = [
'group_title' => null,
'user' => $account->user_id,
'user' => $account->user,
'user_group' => $account->user->userGroup,
'transactions' => [
[
'type' => 'Opening balance',
@@ -248,7 +249,8 @@ trait AccountServiceTrait
'source_name' => $sourceName,
'destination_id' => $destId,
'destination_name' => $destName,
'user' => $account->user_id,
'user' => $account->user,
'user_group' => $account->user->userGroup,
'currency_id' => $currency->id,
'order' => 0,
'amount' => $amount,
@@ -459,11 +461,11 @@ trait AccountServiceTrait
if (null === $currency) {
$currency = app('amount')->getNativeCurrencyByUserGroup($account->user->userGroup);
}
// submit to factory:
$submission = [
'group_title' => null,
'user' => $account->user_id,
'user' => $account->user,
'user_group' => $account->user->userGroup,
'transactions' => [
[
'type' => 'Liability credit',
@@ -472,7 +474,8 @@ trait AccountServiceTrait
'source_name' => $sourceName,
'destination_id' => $destId,
'destination_name' => $destName,
'user' => $account->user_id,
'user' => $account->user,
'user_group' => $account->user->userGroup,
'currency_id' => $currency->id,
'order' => 0,
'amount' => $amount,

View File

@@ -31,6 +31,7 @@ use Illuminate\Contracts\Auth\Guard;
use Illuminate\Contracts\Auth\UserProvider;
use Illuminate\Contracts\Foundation\Application;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;
/**
* Class RemoteUserGuard
@@ -48,7 +49,7 @@ class RemoteUserGuard implements Guard
{
/** @var null|Request $request */
$request = $app->get('request');
app('log')->debug(sprintf('Created RemoteUserGuard for %s "%s"', $request?->getMethod(), $request?->getRequestUri()));
Log::debug(sprintf('Created RemoteUserGuard for %s "%s"', $request?->getMethod(), $request?->getRequestUri()));
$this->application = $app;
$this->provider = $provider;
$this->user = null;
@@ -56,9 +57,9 @@ class RemoteUserGuard implements Guard
public function authenticate(): void
{
app('log')->debug(sprintf('Now at %s', __METHOD__));
Log::debug(sprintf('Now at %s', __METHOD__));
if (null !== $this->user) {
app('log')->debug(sprintf('%s is found: #%d, "%s".', get_class($this->user), $this->user->id, $this->user->email));
Log::debug(sprintf('%s is found: #%d, "%s".', get_class($this->user), $this->user->id, $this->user->email));
return;
}
@@ -67,17 +68,17 @@ class RemoteUserGuard implements Guard
$userID = request()->server($header) ?? null;
if (function_exists('apache_request_headers')) {
app('log')->debug('Use apache_request_headers to find user ID.');
Log::debug('Use apache_request_headers to find user ID.');
$userID = request()->server($header) ?? apache_request_headers()[$header] ?? null;
}
if (null === $userID || '' === $userID) {
app('log')->error(sprintf('No user in header "%s".', $header));
Log::error(sprintf('No user in header "%s".', $header));
throw new FireflyException('The guard header was unexpectedly empty. See the logs.');
}
app('log')->debug(sprintf('User ID found in header is "%s"', $userID));
Log::debug(sprintf('User ID found in header is "%s"', $userID));
/** @var User $retrievedUser */
$retrievedUser = $this->provider->retrieveById($userID);
@@ -98,30 +99,30 @@ class RemoteUserGuard implements Guard
}
}
app('log')->debug(sprintf('Result of getting user from provider: %s', $retrievedUser->email));
Log::debug(sprintf('Result of getting user from provider: %s', $retrievedUser->email));
$this->user = $retrievedUser;
}
public function guest(): bool
{
app('log')->debug(sprintf('Now at %s', __METHOD__));
Log::debug(sprintf('Now at %s', __METHOD__));
return !$this->check();
}
public function check(): bool
{
app('log')->debug(sprintf('Now at %s', __METHOD__));
Log::debug(sprintf('Now at %s', __METHOD__));
return null !== $this->user();
}
public function user(): ?User
{
app('log')->debug(sprintf('Now at %s', __METHOD__));
Log::debug(sprintf('Now at %s', __METHOD__));
$user = $this->user;
if (null === $user) {
app('log')->debug('User is NULL');
Log::debug('User is NULL');
return null;
}
@@ -131,7 +132,7 @@ class RemoteUserGuard implements Guard
public function hasUser(): bool
{
app('log')->debug(sprintf('Now at %s', __METHOD__));
Log::debug(sprintf('Now at %s', __METHOD__));
throw new FireflyException('Did not implement RemoteUserGuard::hasUser()');
}
@@ -141,20 +142,20 @@ class RemoteUserGuard implements Guard
*/
public function id(): null|int|string
{
app('log')->debug(sprintf('Now at %s', __METHOD__));
Log::debug(sprintf('Now at %s', __METHOD__));
return $this->user?->id;
}
public function setUser(null|Authenticatable|User $user): void // @phpstan-ignore-line
{
app('log')->debug(sprintf('Now at %s', __METHOD__));
Log::debug(sprintf('Now at %s', __METHOD__));
if ($user instanceof User) {
$this->user = $user;
return;
}
app('log')->error(sprintf('Did not set user at %s', __METHOD__));
Log::error(sprintf('Did not set user at %s', __METHOD__));
}
/**
@@ -164,14 +165,14 @@ class RemoteUserGuard implements Guard
*/
public function validate(array $credentials = []): bool
{
app('log')->debug(sprintf('Now at %s', __METHOD__));
Log::debug(sprintf('Now at %s', __METHOD__));
throw new FireflyException('Did not implement RemoteUserGuard::validate()');
}
public function viaRemember(): bool
{
app('log')->debug(sprintf('Now at %s', __METHOD__));
Log::debug(sprintf('Now at %s', __METHOD__));
return false;
}

View File

@@ -27,6 +27,7 @@ namespace FireflyIII\Support\Cronjobs;
use Carbon\Carbon;
use FireflyIII\Jobs\DownloadExchangeRates;
use FireflyIII\Models\Configuration;
use Illuminate\Support\Facades\Log;
/**
* Class ExchangeRatesCronjob
@@ -41,23 +42,23 @@ class ExchangeRatesCronjob extends AbstractCronjob
$diff = time() - $lastTime;
$diffForHumans = today(config('app.timezone'))->diffForHumans(Carbon::createFromTimestamp($lastTime), null, true);
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:
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) {
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);
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) {
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();
@@ -66,7 +67,7 @@ class ExchangeRatesCronjob extends AbstractCronjob
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 */
$job = app(DownloadExchangeRates::class);
@@ -80,6 +81,6 @@ class ExchangeRatesCronjob extends AbstractCronjob
$this->message = 'Exchange rates cron job fired successfully.';
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;
// amount_exactly:
$journalTriggers[$index] = 'amount_exactly';
$journalTriggers[$index] = 'amount_is';
$values[$index] = $destination->amount;
++$index;
@@ -244,7 +244,7 @@ trait ModelInformation
// notes (if)
$notes = $journal->notes()->first();
if (null !== $notes) {
$journalTriggers[$index] = 'notes_are';
$journalTriggers[$index] = 'notes_is';
$values[$index] = $notes->text;
}

View File

@@ -25,14 +25,19 @@ declare(strict_types=1);
namespace FireflyIII\Support\JsonApi\Enrichments;
use Carbon\Carbon;
use FireflyIII\Enums\TransactionTypeEnum;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Helpers\Collector\GroupCollectorInterface;
use FireflyIII\Models\Account;
use FireflyIII\Models\AccountMeta;
use FireflyIII\Models\AccountType;
use FireflyIII\Models\ObjectGroup;
use FireflyIII\Models\Location;
use FireflyIII\Models\Note;
use FireflyIII\Models\TransactionCurrency;
use FireflyIII\Repositories\UserGroups\Account\AccountRepositoryInterface;
use FireflyIII\Repositories\UserGroups\Currency\CurrencyRepositoryInterface;
use FireflyIII\Models\UserGroup;
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\Support\Collection;
use Illuminate\Support\Facades\Log;
@@ -44,27 +49,50 @@ use Illuminate\Support\Facades\Log;
*/
class AccountEnrichment implements EnrichmentInterface
{
private array $balances;
private Collection $collection;
private array $currencies;
private CurrencyRepositoryInterface $currencyRepository;
private TransactionCurrency $default;
private ?Carbon $end;
private array $grouped;
private array $objectGroups;
private AccountRepositoryInterface $repository;
private ?Carbon $start;
// private array $balances;
// private array $currencies;
// private CurrencyRepositoryInterface $currencyRepository;
// private TransactionCurrency $default;
// private ?Carbon $end;
// private array $grouped;
// private array $objectGroups;
// private AccountRepositoryInterface $repository;
// 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()
{
$this->repository = app(AccountRepositoryInterface::class);
$this->currencyRepository = app(CurrencyRepositoryInterface::class);
$this->start = null;
$this->end = null;
$this->convertToNative = false;
$this->accountIds = [];
$this->openingBalances = [];
$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]
public function enrichSingle(Model $model): Account
public function enrichSingle(array|Model $model): Account|array
{
Log::debug(__METHOD__);
$collection = new Collection([$model]);
@@ -80,202 +108,187 @@ class AccountEnrichment implements EnrichmentInterface
public function enrich(Collection $collection): Collection
{
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:
$this->getLastActivity();
$this->collectAccountTypes();
$this->collection = $collection;
$this->collectAccountIds();
$this->getAccountTypes();
$this->collectMetaData();
$this->getMetaBalances();
$this->getObjectGroups();
// $this->collection->transform(function (Account $account) {
// $account->user_array = ['id' => 1, 'bla bla' => 'bla'];
// $account->balances = collect([
// ['balance_id' => 1, 'balance' => 5],
// ['balance_id' => 2, 'balance' => 5],
// ['balance_id' => 3, 'balance' => 5],
// ]);
//
// return $account;
// });
$this->collectNotes();
$this->collectLocations();
$this->collectOpeningBalances();
$this->appendCollectedData();
return $this->collection;
}
/**
* TODO this method refers to a single-use method inside Steam that could be moved here.
*/
private function getLastActivity(): void
private function getAccountTypes(): void
{
$lastActivity = $this->repository->getLastActivity($this->collection);
foreach ($lastActivity as $row) {
$this->collection->where('id', $row['account_id'])->first()->last_activity = Carbon::parse($row['date_max'], config('app.timezone'));
$types = AccountType::whereIn('id', $this->accountTypeIds)->get();
/** @var AccountType $type */
foreach ($types as $type) {
$this->accountTypes[(int) $type->id] = $type->type;
}
}
/**
* TODO this method refers to a single-use method inside Steam that could be moved here.
*/
private function collectAccountTypes(): void
private function collectAccountIds(): void
{
$accountTypes = $this->repository->getAccountTypes($this->collection);
$types = [];
/** @var AccountType $row */
foreach ($accountTypes as $row) {
$types[$row->id] = $row->type;
/** @var Account $account */
foreach ($this->collection as $account) {
$this->accountIds[] = (int) $account->id;
$this->accountTypeIds[] = (int) $account->account_type_id;
}
$this->collection->transform(function (Account $account) use ($types) {
$account->account_type_string = $types[$account->id];
$this->accountIds = array_unique($this->accountIds);
$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
{
$metaFields = $this->repository->getMetaValues($this->collection, ['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();
$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'])
$set = AccountMeta::whereIn('name', ['is_multi_currency', 'include_net_worth', 'currency_id', 'account_role', 'account_number', 'liability_direction', 'interest', 'interest_period', 'current_debt'])
->whereIn('account_id', $this->accountIds)
->get(['account_meta.id', 'account_meta.account_id', 'account_meta.name', 'account_meta.data'])->toArray()
;
// get the groups:
$groupIds = $set->pluck('object_group_id')->toArray();
$groups = ObjectGroup::whereIn('id', $groupIds)->get();
/** @var ObjectGroup $group */
foreach ($groups as $group) {
$this->objectGroups[$group->id] = $group;
}
/** @var \stdClass $entry */
/** @var array $entry */
foreach ($set as $entry) {
$this->grouped[(int) $entry->object_groupable_id] = (int) $entry->object_group_id;
}
$this->collection->transform(function (Account $account) {
$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;
$this->meta[(int) $entry['account_id']][$entry['name']] = (string) $entry['data'];
if ('currency_id' === $entry['name']) {
$this->currencies[(int) $entry['data']] = true;
}
return $account;
});
}
$currencies = TransactionCurrency::whereIn('id', array_keys($this->currencies))->get();
foreach ($currencies as $currency) {
$this->currencies[(int) $currency->id] = $currency;
}
$this->currencies[0] = $this->native;
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;
use FireflyIII\Models\UserGroup;
use FireflyIII\User;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Collection;
@@ -31,5 +33,9 @@ interface EnrichmentInterface
{
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

@@ -72,20 +72,32 @@ class Preferences
public function getForUser(User $user, string $name, null|array|bool|int|string $default = null): ?Preference
{
Log::debug(sprintf('getForUser(#%d, "%s")', $user->id, $name));
// don't care about user group ID, except for some specific preferences.
$userGroupId = $this->getUserGroupId($user, $name);
$preference = Preference::where('user_group_id', $userGroupId)->where('user_id', $user->id)->where('name', $name)->first(['id', 'user_id', 'name', 'data', 'updated_at', 'created_at']);
$query = Preference::where('user_id', $user->id)->where('name', $name);
if (null !== $userGroupId) {
Log::debug('Include user group ID in query');
$query->where('user_group_id', $userGroupId);
}
$preference = $query->first(['id', 'user_id', 'user_group_id', 'name', 'data', 'updated_at', 'created_at']);
if (null !== $preference && null === $preference->data) {
$preference->delete();
$preference = null;
Log::debug('Removed empty preference.');
}
if (null !== $preference) {
Log::debug(sprintf('Found preference #%d for user #%d: %s', $preference->id, $user->id, $name));
return $preference;
}
// no preference found and default is null:
if (null === $default) {
Log::debug('Return NULL, create no preference.');
// return NULL
return null;
}
@@ -124,35 +136,40 @@ class Preferences
public function setForUser(User $user, string $name, null|array|bool|int|string $value): Preference
{
$fullName = sprintf('preference%s%s', $user->id, $name);
$groupId = $this->getUserGroupId($user, $name);
$groupId = 0 === (int) $groupId ? null : (int) $groupId;
$fullName = sprintf('preference%s%s', $user->id, $name);
$userGroupId = $this->getUserGroupId($user, $name);
$userGroupId = 0 === (int) $userGroupId ? null : (int) $userGroupId;
Cache::forget($fullName);
/** @var null|Preference $pref */
$pref = Preference::where('user_group_id', $groupId)->where('user_id', $user->id)->where('name', $name)->first(['id', 'name', 'data', 'updated_at', 'created_at']);
$query = Preference::where('user_id', $user->id)->where('name', $name);
if (null !== $userGroupId) {
Log::debug('Include user group ID in query');
$query->where('user_group_id', $userGroupId);
}
if (null !== $pref && null === $value) {
$pref->delete();
$preference = $query->first(['id', 'user_id', 'user_group_id', 'name', 'data', 'updated_at', 'created_at']);
if (null !== $preference && null === $value) {
$preference->delete();
return new Preference();
}
if (null === $value) {
return new Preference();
}
if (null === $pref) {
$pref = new Preference();
$pref->user_id = (int) $user->id;
$pref->user_group_id = $groupId;
$pref->name = $name;
if (null === $preference) {
$preference = new Preference();
$preference->user_id = (int) $user->id;
$preference->user_group_id = $userGroupId;
$preference->name = $name;
}
$pref->data = $value;
$pref->save();
Cache::forever($fullName, $pref);
$preference->data = $value;
$preference->save();
Cache::forever($fullName, $preference);
return $pref;
return $preference;
}
public function beginsWith(User $user, string $search): Collection

View File

@@ -54,17 +54,21 @@ class TransactionSummarizer
Log::debug(sprintf('Now in groupByCurrencyId(array, "%s")', $method));
$array = [];
foreach ($journals as $journal) {
$field = 'amount';
$field = 'amount';
// grab default currency information.
$currencyId = (int) $journal['currency_id'];
$currencyName = $journal['currency_name'];
$currencySymbol = $journal['currency_symbol'];
$currencyCode = $journal['currency_code'];
$currencyDecimalPlaces = $journal['currency_decimal_places'];
$currencyId = (int) $journal['currency_id'];
$currencyName = $journal['currency_name'];
$currencySymbol = $journal['currency_symbol'];
$currencyCode = $journal['currency_code'];
$currencyDecimalPlaces = $journal['currency_decimal_places'];
// prepare foreign currency info:
$foreignCurrencyId = 0;
$foreignCurrencyId = 0;
$foreignCurrencyName = null;
$foreignCurrencySymbol = null;
$foreignCurrencyCode = null;
$foreignCurrencyDecimalPlaces = null;
if ($this->convertToNative) {
// if convert to native, use the native amount yes or no?
@@ -102,7 +106,7 @@ class TransactionSummarizer
}
// first process normal amount
$amount = (string) ($journal[$field] ?? '0');
$amount = (string) ($journal[$field] ?? '0');
$array[$currencyId] ??= [
'sum' => '0',
'currency_id' => $currencyId,

View File

@@ -390,6 +390,25 @@ trait ConvertsDataTypes
return (int) $string;
}
protected function parseAccounts(mixed $array): array
{
if (!is_array($array)) {
return [];
}
$return = [];
foreach ($array as $entry) {
if (!is_array($entry)) {
continue;
}
$return[] = [
'account_id' => $this->integerFromValue((string) ($entry['account_id'] ?? '0')),
'current_amount' => $this->clearString((string) ($entry['current_amount'] ?? '0')),
];
}
return $return;
}
protected function floatFromValue(?string $string): ?float
{
if (null === $string) {

View File

@@ -48,7 +48,7 @@ class Steam
if (!in_array($type, $list, true)) {
return null;
}
$result = $account->accountMeta->where('name', 'currency_id')->first();
$result = $account->accountMeta()->where('name', 'currency_id')->first();
if (null === $result) {
return null;
}
@@ -288,21 +288,33 @@ class Steam
* --> "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)
*/
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->addProperty($account->id);
$cache->addProperty($date);
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();
}
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);
$convertToNative = Amount::convertToNative($account->user);
$accountCurrency = $this->getAccountCurrency($account);
$accountCurrency = $this->getAccountCurrency($account);
}
$hasCurrency = null !== $accountCurrency;
$currency = $hasCurrency ? $accountCurrency : $native;
$return = [

View File

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

View File

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

View File

@@ -3,6 +3,49 @@
All notable changes to this project will be documented in this file.
This project adheres to [Semantic Versioning](http://semver.org/).
## 6.2.9 - 2025-02-22
### Fixed
- [Issue 9861](https://github.com/firefly-iii/firefly-iii/issues/9861) (lower piggy amount when full creates double audit log entry) reported by @4e868df3
- [Issue 9862](https://github.com/firefly-iii/firefly-iii/issues/9862) (Can't retrieve all accounts with the same name via API) reported by @Toshik1978
- [Issue 9863](https://github.com/firefly-iii/firefly-iii/issues/9863) (User preferences reset after restart) reported by @mico28
- [Issue 9868](https://github.com/firefly-iii/firefly-iii/issues/9868) (API: `TransactionSplit` -> `transaction_journal_id` returns int, not String) reported by @dreautall
- [Issue 9871](https://github.com/firefly-iii/firefly-iii/issues/9871) (include net worth is ignored in the API - from PICO developer) reported by @fate8383
- [Issue 9882](https://github.com/firefly-iii/firefly-iii/issues/9882) (Reconciliation bug on Docker instance) reported by @benjaminteyssier
- [Issue 9884](https://github.com/firefly-iii/firefly-iii/issues/9884) (Data import, currency #0 not found) reported by @ragnarkarlsson
- [Issue 9885](https://github.com/firefly-iii/firefly-iii/issues/9885) (Invalid server configuration: missing required package) reported by @EricVanCaenenberghe
- [Issue 9887](https://github.com/firefly-iii/firefly-iii/issues/9887) (Creating a Liability Account Throws TypeError in TransactionJournalFactory::setUser()) reported by @mikeashi
## 6.2.8 - 2025-02-22
### Fixed
- [Issue 9861](https://github.com/firefly-iii/firefly-iii/issues/9861) (lower piggy amount when full creates double audit log entry) reported by @4e868df3
- [Issue 9862](https://github.com/firefly-iii/firefly-iii/issues/9862) (Can't retrieve all accounts with the same name via API) reported by @Toshik1978
- [Issue 9863](https://github.com/firefly-iii/firefly-iii/issues/9863) (User preferences reset after restart) reported by @mico28
- [Issue 9868](https://github.com/firefly-iii/firefly-iii/issues/9868) (API: `TransactionSplit` -> `transaction_journal_id` returns int, not String) reported by @dreautall
- [Issue 9871](https://github.com/firefly-iii/firefly-iii/issues/9871) (include net worth is ignored in the API - from PICO developer) reported by @fate8383
- [Issue 9882](https://github.com/firefly-iii/firefly-iii/issues/9882) (Reconciliation bug on Docker instance) reported by @benjaminteyssier
- [Issue 9884](https://github.com/firefly-iii/firefly-iii/issues/9884) (Data import, currency #0 not found) reported by @ragnarkarlsson
- [Issue 9885](https://github.com/firefly-iii/firefly-iii/issues/9885) (Invalid server configuration: missing required package) reported by @EricVanCaenenberghe
- [Issue 9887](https://github.com/firefly-iii/firefly-iii/issues/9887) (Creating a Liability Account Throws TypeError in TransactionJournalFactory::setUser()) reported by @mikeashi
## 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

484
composer.lock generated
View File

@@ -1874,16 +1874,16 @@
},
{
"name": "laravel/framework",
"version": "v11.42.0",
"version": "v11.43.2",
"source": {
"type": "git",
"url": "https://github.com/laravel/framework.git",
"reference": "006375ba67e830e87daa7b52ab65163ba3508d26"
"reference": "99d1573698abc42222f04d25fcd5b213d0eedf21"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/laravel/framework/zipball/006375ba67e830e87daa7b52ab65163ba3508d26",
"reference": "006375ba67e830e87daa7b52ab65163ba3508d26",
"url": "https://api.github.com/repos/laravel/framework/zipball/99d1573698abc42222f04d25fcd5b213d0eedf21",
"reference": "99d1573698abc42222f04d25fcd5b213d0eedf21",
"shasum": ""
},
"require": {
@@ -2085,7 +2085,7 @@
"issues": "https://github.com/laravel/framework/issues",
"source": "https://github.com/laravel/framework"
},
"time": "2025-02-11T17:17:56+00:00"
"time": "2025-02-19T21:53:48+00:00"
},
{
"name": "laravel/passport",
@@ -3076,16 +3076,16 @@
},
{
"name": "league/fractal",
"version": "0.20.1",
"version": "0.20.2",
"source": {
"type": "git",
"url": "https://github.com/thephpleague/fractal.git",
"reference": "8b9d39b67624db9195c06f9c1ffd0355151eaf62"
"reference": "573ca2e0e348a7fe573a3e8fbc29a6588ece8c4e"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/thephpleague/fractal/zipball/8b9d39b67624db9195c06f9c1ffd0355151eaf62",
"reference": "8b9d39b67624db9195c06f9c1ffd0355151eaf62",
"url": "https://api.github.com/repos/thephpleague/fractal/zipball/573ca2e0e348a7fe573a3e8fbc29a6588ece8c4e",
"reference": "573ca2e0e348a7fe573a3e8fbc29a6588ece8c4e",
"shasum": ""
},
"require": {
@@ -3094,18 +3094,18 @@
"require-dev": {
"doctrine/orm": "^2.5",
"illuminate/contracts": "~5.0",
"laminas/laminas-paginator": "~2.12",
"mockery/mockery": "^1.3",
"pagerfanta/pagerfanta": "~1.0.0",
"pagerfanta/pagerfanta": "~1.0.0|~4.0.0",
"phpstan/phpstan": "^1.4",
"phpunit/phpunit": "^9.5",
"squizlabs/php_codesniffer": "~3.4",
"vimeo/psalm": "^4.22",
"zendframework/zend-paginator": "~2.3"
"vimeo/psalm": "^4.30"
},
"suggest": {
"illuminate/pagination": "The Illuminate Pagination component.",
"pagerfanta/pagerfanta": "Pagerfanta Paginator",
"zendframework/zend-paginator": "Zend Framework Paginator"
"laminas/laminas-paginator": "Laminas Framework Paginator",
"pagerfanta/pagerfanta": "Pagerfanta Paginator"
},
"type": "library",
"extra": {
@@ -3140,9 +3140,9 @@
],
"support": {
"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",
@@ -3703,16 +3703,16 @@
},
{
"name": "nesbot/carbon",
"version": "3.8.5",
"version": "3.8.6",
"source": {
"type": "git",
"url": "https://github.com/CarbonPHP/carbon.git",
"reference": "b1a53a27898639579a67de42e8ced5d5386aa9a4"
"reference": "ff2f20cf83bd4d503720632ce8a426dc747bf7fd"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/CarbonPHP/carbon/zipball/b1a53a27898639579a67de42e8ced5d5386aa9a4",
"reference": "b1a53a27898639579a67de42e8ced5d5386aa9a4",
"url": "https://api.github.com/repos/CarbonPHP/carbon/zipball/ff2f20cf83bd4d503720632ce8a426dc747bf7fd",
"reference": "ff2f20cf83bd4d503720632ce8a426dc747bf7fd",
"shasum": ""
},
"require": {
@@ -3805,7 +3805,7 @@
"type": "tidelift"
}
],
"time": "2025-02-11T16:28:45+00:00"
"time": "2025-02-20T17:33:38+00:00"
},
{
"name": "nette/schema",
@@ -5970,30 +5970,30 @@
},
{
"name": "spatie/error-solutions",
"version": "1.1.2",
"version": "1.1.3",
"source": {
"type": "git",
"url": "https://github.com/spatie/error-solutions.git",
"reference": "d239a65235a1eb128dfa0a4e4c4ef032ea11b541"
"reference": "e495d7178ca524f2dd0fe6a1d99a1e608e1c9936"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/spatie/error-solutions/zipball/d239a65235a1eb128dfa0a4e4c4ef032ea11b541",
"reference": "d239a65235a1eb128dfa0a4e4c4ef032ea11b541",
"url": "https://api.github.com/repos/spatie/error-solutions/zipball/e495d7178ca524f2dd0fe6a1d99a1e608e1c9936",
"reference": "e495d7178ca524f2dd0fe6a1d99a1e608e1c9936",
"shasum": ""
},
"require": {
"php": "^8.0"
},
"require-dev": {
"illuminate/broadcasting": "^10.0|^11.0",
"illuminate/cache": "^10.0|^11.0",
"illuminate/support": "^10.0|^11.0",
"livewire/livewire": "^2.11|^3.3.5",
"illuminate/broadcasting": "^10.0|^11.0|^12.0",
"illuminate/cache": "^10.0|^11.0|^12.0",
"illuminate/support": "^10.0|^11.0|^12.0",
"livewire/livewire": "^2.11|^3.5.20",
"openai-php/client": "^0.10.1",
"orchestra/testbench": "^7.0|8.22.3|^9.0",
"pestphp/pest": "^2.20",
"phpstan/phpstan": "^1.11",
"orchestra/testbench": "8.22.3|^9.0|^10.0",
"pestphp/pest": "^2.20|^3.0",
"phpstan/phpstan": "^2.1",
"psr/simple-cache": "^3.0",
"psr/simple-cache-implementation": "^3.0",
"spatie/ray": "^1.28",
@@ -6032,7 +6032,7 @@
],
"support": {
"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": [
{
@@ -6040,24 +6040,24 @@
"type": "github"
}
],
"time": "2024-12-11T09:51:56+00:00"
"time": "2025-02-14T12:29:50+00:00"
},
{
"name": "spatie/flare-client-php",
"version": "1.10.0",
"version": "1.10.1",
"source": {
"type": "git",
"url": "https://github.com/spatie/flare-client-php.git",
"reference": "140a42b2c5d59ac4ecf8f5b493386a4f2eb28272"
"reference": "bf1716eb98bd689451b071548ae9e70738dce62f"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/spatie/flare-client-php/zipball/140a42b2c5d59ac4ecf8f5b493386a4f2eb28272",
"reference": "140a42b2c5d59ac4ecf8f5b493386a4f2eb28272",
"url": "https://api.github.com/repos/spatie/flare-client-php/zipball/bf1716eb98bd689451b071548ae9e70738dce62f",
"reference": "bf1716eb98bd689451b071548ae9e70738dce62f",
"shasum": ""
},
"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",
"spatie/backtrace": "^1.6.1",
"symfony/http-foundation": "^5.2|^6.0|^7.0",
@@ -6101,7 +6101,7 @@
],
"support": {
"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": [
{
@@ -6109,20 +6109,20 @@
"type": "github"
}
],
"time": "2024-12-02T14:30:06+00:00"
"time": "2025-02-14T13:42:06+00:00"
},
{
"name": "spatie/ignition",
"version": "1.15.0",
"version": "1.15.1",
"source": {
"type": "git",
"url": "https://github.com/spatie/ignition.git",
"reference": "e3a68e137371e1eb9edc7f78ffa733f3b98991d2"
"reference": "31f314153020aee5af3537e507fef892ffbf8c85"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/spatie/ignition/zipball/e3a68e137371e1eb9edc7f78ffa733f3b98991d2",
"reference": "e3a68e137371e1eb9edc7f78ffa733f3b98991d2",
"url": "https://api.github.com/repos/spatie/ignition/zipball/31f314153020aee5af3537e507fef892ffbf8c85",
"reference": "31f314153020aee5af3537e507fef892ffbf8c85",
"shasum": ""
},
"require": {
@@ -6135,7 +6135,7 @@
"symfony/var-dumper": "^5.4|^6.0|^7.0"
},
"require-dev": {
"illuminate/cache": "^9.52|^10.0|^11.0",
"illuminate/cache": "^9.52|^10.0|^11.0|^12.0",
"mockery/mockery": "^1.4",
"pestphp/pest": "^1.20|^2.0",
"phpstan/extension-installer": "^1.1",
@@ -6192,31 +6192,31 @@
"type": "github"
}
],
"time": "2024-06-12T14:55:22+00:00"
"time": "2025-02-21T14:31:39+00:00"
},
{
"name": "spatie/laravel-html",
"version": "3.11.2",
"version": "3.11.3",
"source": {
"type": "git",
"url": "https://github.com/spatie/laravel-html.git",
"reference": "248508f3ed50e6538707fc54a4b3b23fb53e8045"
"reference": "b1bb159bd9845b1ff02b8f945ecd583d93353d06"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/spatie/laravel-html/zipball/248508f3ed50e6538707fc54a4b3b23fb53e8045",
"reference": "248508f3ed50e6538707fc54a4b3b23fb53e8045",
"url": "https://api.github.com/repos/spatie/laravel-html/zipball/b1bb159bd9845b1ff02b8f945ecd583d93353d06",
"reference": "b1bb159bd9845b1ff02b8f945ecd583d93353d06",
"shasum": ""
},
"require": {
"illuminate/http": "^10.0|^11.0",
"illuminate/support": "^10.0|^11.0",
"illuminate/http": "^10.0|^11.0|^12.0",
"illuminate/support": "^10.0|^11.0|^12.0",
"php": "^8.2"
},
"require-dev": {
"mockery/mockery": "^1.3",
"orchestra/testbench": "^8.0|^9.0",
"pestphp/pest": "^2.34"
"orchestra/testbench": "^8.0|^9.0|^10.0",
"pestphp/pest": "^2.34|^3.7"
},
"type": "library",
"extra": {
@@ -6262,7 +6262,7 @@
"spatie"
],
"support": {
"source": "https://github.com/spatie/laravel-html/tree/3.11.2"
"source": "https://github.com/spatie/laravel-html/tree/3.11.3"
},
"funding": [
{
@@ -6270,27 +6270,27 @@
"type": "custom"
}
],
"time": "2025-02-05T08:27:24+00:00"
"time": "2025-02-17T09:59:20+00:00"
},
{
"name": "spatie/laravel-ignition",
"version": "2.9.0",
"version": "2.9.1",
"source": {
"type": "git",
"url": "https://github.com/spatie/laravel-ignition.git",
"reference": "62042df15314b829d0f26e02108f559018e2aad0"
"reference": "1baee07216d6748ebd3a65ba97381b051838707a"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/spatie/laravel-ignition/zipball/62042df15314b829d0f26e02108f559018e2aad0",
"reference": "62042df15314b829d0f26e02108f559018e2aad0",
"url": "https://api.github.com/repos/spatie/laravel-ignition/zipball/1baee07216d6748ebd3a65ba97381b051838707a",
"reference": "1baee07216d6748ebd3a65ba97381b051838707a",
"shasum": ""
},
"require": {
"ext-curl": "*",
"ext-json": "*",
"ext-mbstring": "*",
"illuminate/support": "^10.0|^11.0",
"illuminate/support": "^10.0|^11.0|^12.0",
"php": "^8.1",
"spatie/ignition": "^1.15",
"symfony/console": "^6.2.3|^7.0",
@@ -6299,12 +6299,12 @@
"require-dev": {
"livewire/livewire": "^2.11|^3.3.5",
"mockery/mockery": "^1.5.1",
"openai-php/client": "^0.8.1",
"orchestra/testbench": "8.22.3|^9.0",
"pestphp/pest": "^2.34",
"openai-php/client": "^0.8.1|^0.10",
"orchestra/testbench": "8.22.3|^9.0|^10.0",
"pestphp/pest": "^2.34|^3.7",
"phpstan/extension-installer": "^1.3.1",
"phpstan/phpstan-deprecation-rules": "^1.1.1",
"phpstan/phpstan-phpunit": "^1.3.16",
"phpstan/phpstan-deprecation-rules": "^1.1.1|^2.0",
"phpstan/phpstan-phpunit": "^1.3.16|^2.0",
"vlucas/phpdotenv": "^5.5"
},
"suggest": {
@@ -6361,7 +6361,7 @@
"type": "github"
}
],
"time": "2024-12-02T08:43:31+00:00"
"time": "2025-02-20T13:13:55+00:00"
},
{
"name": "spatie/laravel-package-tools",
@@ -8455,82 +8455,6 @@
],
"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",
"version": "v1.31.0",
@@ -9683,24 +9607,23 @@
},
{
"name": "twig/twig",
"version": "v3.19.0",
"version": "v3.20.0",
"source": {
"type": "git",
"url": "https://github.com/twigphp/Twig.git",
"reference": "d4f8c2b86374f08efc859323dbcd95c590f7124e"
"reference": "3468920399451a384bef53cf7996965f7cd40183"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/twigphp/Twig/zipball/d4f8c2b86374f08efc859323dbcd95c590f7124e",
"reference": "d4f8c2b86374f08efc859323dbcd95c590f7124e",
"url": "https://api.github.com/repos/twigphp/Twig/zipball/3468920399451a384bef53cf7996965f7cd40183",
"reference": "3468920399451a384bef53cf7996965f7cd40183",
"shasum": ""
},
"require": {
"php": ">=8.0.2",
"php": ">=8.1.0",
"symfony/deprecation-contracts": "^2.5|^3",
"symfony/polyfill-ctype": "^1.8",
"symfony/polyfill-mbstring": "^1.3",
"symfony/polyfill-php81": "^1.29"
"symfony/polyfill-mbstring": "^1.3"
},
"require-dev": {
"phpstan/phpstan": "^2.0",
@@ -9747,7 +9670,7 @@
],
"support": {
"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": [
{
@@ -9759,7 +9682,7 @@
"type": "tidelift"
}
],
"time": "2025-01-29T07:06:14+00:00"
"time": "2025-02-13T08:34:43+00:00"
},
{
"name": "verifiedjoseph/ntfy-php-library",
@@ -10110,30 +10033,30 @@
"packages-dev": [
{
"name": "barryvdh/laravel-debugbar",
"version": "v3.14.10",
"version": "v3.15.0",
"source": {
"type": "git",
"url": "https://github.com/barryvdh/laravel-debugbar.git",
"reference": "56b9bd235e3fe62e250124804009ce5bab97cc63"
"reference": "77cca4a1162d45e1fe64e7a71b4a3031656b6c86"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/barryvdh/laravel-debugbar/zipball/56b9bd235e3fe62e250124804009ce5bab97cc63",
"reference": "56b9bd235e3fe62e250124804009ce5bab97cc63",
"url": "https://api.github.com/repos/barryvdh/laravel-debugbar/zipball/77cca4a1162d45e1fe64e7a71b4a3031656b6c86",
"reference": "77cca4a1162d45e1fe64e7a71b4a3031656b6c86",
"shasum": ""
},
"require": {
"illuminate/routing": "^9|^10|^11",
"illuminate/session": "^9|^10|^11",
"illuminate/support": "^9|^10|^11",
"maximebf/debugbar": "~1.23.0",
"php": "^8.0",
"illuminate/routing": "^9|^10|^11|^12",
"illuminate/session": "^9|^10|^11|^12",
"illuminate/support": "^9|^10|^11|^12",
"php": "^8.1",
"php-debugbar/php-debugbar": "~2.1.1",
"symfony/finder": "^6|^7"
},
"require-dev": {
"mockery/mockery": "^1.3.3",
"orchestra/testbench-dusk": "^5|^6|^7|^8|^9",
"phpunit/phpunit": "^9.6|^10.5",
"orchestra/testbench-dusk": "^7|^8|^9|^10",
"phpunit/phpunit": "^9.5.10|^10|^11",
"squizlabs/php_codesniffer": "^3.5"
},
"type": "library",
@@ -10147,7 +10070,7 @@
]
},
"branch-alias": {
"dev-master": "3.14-dev"
"dev-master": "3.15-dev"
}
},
"autoload": {
@@ -10172,13 +10095,14 @@
"keywords": [
"debug",
"debugbar",
"dev",
"laravel",
"profiler",
"webprofiler"
],
"support": {
"issues": "https://github.com/barryvdh/laravel-debugbar/issues",
"source": "https://github.com/barryvdh/laravel-debugbar/tree/v3.14.10"
"source": "https://github.com/barryvdh/laravel-debugbar/tree/v3.15.0"
},
"funding": [
{
@@ -10190,40 +10114,40 @@
"type": "github"
}
],
"time": "2024-12-23T10:10:42+00:00"
"time": "2025-02-21T15:00:44+00:00"
},
{
"name": "barryvdh/laravel-ide-helper",
"version": "v3.5.4",
"version": "v3.5.5",
"source": {
"type": "git",
"url": "https://github.com/barryvdh/laravel-ide-helper.git",
"reference": "980a87e250fc2a7558bc46e07f61c7594500ea53"
"reference": "8d441ec99f8612b942b55f5183151d91591b618a"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/barryvdh/laravel-ide-helper/zipball/980a87e250fc2a7558bc46e07f61c7594500ea53",
"reference": "980a87e250fc2a7558bc46e07f61c7594500ea53",
"url": "https://api.github.com/repos/barryvdh/laravel-ide-helper/zipball/8d441ec99f8612b942b55f5183151d91591b618a",
"reference": "8d441ec99f8612b942b55f5183151d91591b618a",
"shasum": ""
},
"require": {
"barryvdh/reflection-docblock": "^2.3",
"composer/class-map-generator": "^1.0",
"ext-json": "*",
"illuminate/console": "^11.15",
"illuminate/database": "^11.15",
"illuminate/filesystem": "^11.15",
"illuminate/support": "^11.15",
"illuminate/console": "^11.15 || ^12",
"illuminate/database": "^11.15 || ^12",
"illuminate/filesystem": "^11.15 || ^12",
"illuminate/support": "^11.15 || ^12",
"php": "^8.2"
},
"require-dev": {
"ext-pdo_sqlite": "*",
"friendsofphp/php-cs-fixer": "^3",
"illuminate/config": "^11.15",
"illuminate/view": "^11.15",
"illuminate/config": "^11.15 || ^12",
"illuminate/view": "^11.15 || ^12",
"mockery/mockery": "^1.4",
"orchestra/testbench": "^9.2",
"phpunit/phpunit": "^10.5",
"orchestra/testbench": "^9.2 || ^10",
"phpunit/phpunit": "^10.5 || ^11.5.3",
"spatie/phpunit-snapshot-assertions": "^4 || ^5",
"vimeo/psalm": "^5.4",
"vlucas/phpdotenv": "^5"
@@ -10272,7 +10196,7 @@
],
"support": {
"issues": "https://github.com/barryvdh/laravel-ide-helper/issues",
"source": "https://github.com/barryvdh/laravel-ide-helper/tree/v3.5.4"
"source": "https://github.com/barryvdh/laravel-ide-helper/tree/v3.5.5"
},
"funding": [
{
@@ -10284,7 +10208,7 @@
"type": "github"
}
],
"time": "2025-01-14T09:07:00+00:00"
"time": "2025-02-11T13:59:46+00:00"
},
{
"name": "barryvdh/reflection-docblock",
@@ -10664,40 +10588,40 @@
},
{
"name": "larastan/larastan",
"version": "v3.0.4",
"version": "v3.1.0",
"source": {
"type": "git",
"url": "https://github.com/larastan/larastan.git",
"reference": "b394eba5805727423071fac9b53ea50dd7e920f4"
"reference": "dbb2dc20e5c8e1ed3ff289054e1955f269187312"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/larastan/larastan/zipball/b394eba5805727423071fac9b53ea50dd7e920f4",
"reference": "b394eba5805727423071fac9b53ea50dd7e920f4",
"url": "https://api.github.com/repos/larastan/larastan/zipball/dbb2dc20e5c8e1ed3ff289054e1955f269187312",
"reference": "dbb2dc20e5c8e1ed3ff289054e1955f269187312",
"shasum": ""
},
"require": {
"ext-json": "*",
"illuminate/console": "^11.15.0",
"illuminate/container": "^11.15.0",
"illuminate/contracts": "^11.15.0",
"illuminate/database": "^11.15.0",
"illuminate/http": "^11.15.0",
"illuminate/pipeline": "^11.15.0",
"illuminate/support": "^11.15.0",
"illuminate/console": "^11.15.0 || ^12.0",
"illuminate/container": "^11.15.0 || ^12.0",
"illuminate/contracts": "^11.15.0 || ^12.0",
"illuminate/database": "^11.15.0 || ^12.0",
"illuminate/http": "^11.15.0 || ^12.0",
"illuminate/pipeline": "^11.15.0 || ^12.0",
"illuminate/support": "^11.15.0 || ^12.0",
"php": "^8.2",
"phpmyadmin/sql-parser": "^5.9.0",
"phpstan/phpstan": "^2.1.3"
},
"require-dev": {
"doctrine/coding-standard": "^12.0",
"laravel/framework": "^11.15.0",
"laravel/framework": "^11.15.0 || ^12.0",
"mockery/mockery": "^1.6",
"nikic/php-parser": "^5.3",
"orchestra/canvas": "^v9.1.3",
"orchestra/testbench-core": "^9.5.2",
"orchestra/canvas": "^v9.1.3 || ^10.0",
"orchestra/testbench-core": "^9.5.2 || ^10.0",
"phpstan/phpstan-deprecation-rules": "^2.0.0",
"phpunit/phpunit": "^10.5.16"
"phpunit/phpunit": "^10.5.35 || ^11.3.6"
},
"suggest": {
"orchestra/testbench": "Using Larastan for analysing a package needs Testbench"
@@ -10710,7 +10634,7 @@
]
},
"branch-alias": {
"dev-master": "2.0-dev"
"dev-master": "3.0-dev"
}
},
"autoload": {
@@ -10745,7 +10669,7 @@
],
"support": {
"issues": "https://github.com/larastan/larastan/issues",
"source": "https://github.com/larastan/larastan/tree/v3.0.4"
"source": "https://github.com/larastan/larastan/tree/v3.1.0"
},
"funding": [
{
@@ -10753,7 +10677,7 @@
"type": "github"
}
],
"time": "2025-02-06T21:03:36+00:00"
"time": "2025-02-20T15:25:15+00:00"
},
{
"name": "laravel-json-api/testing",
@@ -10820,74 +10744,6 @@
},
"time": "2024-11-30T16:50:45+00:00"
},
{
"name": "maximebf/debugbar",
"version": "v1.23.5",
"source": {
"type": "git",
"url": "https://github.com/php-debugbar/php-debugbar.git",
"reference": "eeabd61a1f19ba5dcd5ac4585a477130ee03ce25"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/php-debugbar/php-debugbar/zipball/eeabd61a1f19ba5dcd5ac4585a477130ee03ce25",
"reference": "eeabd61a1f19ba5dcd5ac4585a477130ee03ce25",
"shasum": ""
},
"require": {
"php": "^7.2|^8",
"psr/log": "^1|^2|^3",
"symfony/var-dumper": "^4|^5|^6|^7"
},
"require-dev": {
"dbrekelmans/bdi": "^1",
"phpunit/phpunit": "^8|^9",
"symfony/panther": "^1|^2.1",
"twig/twig": "^1.38|^2.7|^3.0"
},
"suggest": {
"kriswallsmith/assetic": "The best way to manage assets",
"monolog/monolog": "Log using Monolog",
"predis/predis": "Redis storage"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.23-dev"
}
},
"autoload": {
"psr-4": {
"DebugBar\\": "src/DebugBar/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Maxime Bouroumeau-Fuseau",
"email": "maxime.bouroumeau@gmail.com",
"homepage": "http://maximebf.com"
},
{
"name": "Barry vd. Heuvel",
"email": "barryvdh@gmail.com"
}
],
"description": "Debug bar in the browser for php application",
"homepage": "https://github.com/maximebf/php-debugbar",
"keywords": [
"debug",
"debugbar"
],
"support": {
"issues": "https://github.com/php-debugbar/php-debugbar/issues",
"source": "https://github.com/php-debugbar/php-debugbar/tree/v1.23.5"
},
"time": "2024-12-15T19:20:42+00:00"
},
{
"name": "mockery/mockery",
"version": "1.6.12",
@@ -11207,6 +11063,76 @@
},
"time": "2022-02-21T01:04:05+00:00"
},
{
"name": "php-debugbar/php-debugbar",
"version": "v2.1.5",
"source": {
"type": "git",
"url": "https://github.com/php-debugbar/php-debugbar.git",
"reference": "3f589bbbaed53039d9699702c2908148647c27a1"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/php-debugbar/php-debugbar/zipball/3f589bbbaed53039d9699702c2908148647c27a1",
"reference": "3f589bbbaed53039d9699702c2908148647c27a1",
"shasum": ""
},
"require": {
"php": "^8",
"psr/log": "^1|^2|^3",
"symfony/var-dumper": "^4|^5|^6|^7"
},
"require-dev": {
"dbrekelmans/bdi": "^1",
"phpunit/phpunit": "^8|^9",
"symfony/panther": "^1|^2.1",
"twig/twig": "^1.38|^2.7|^3.0"
},
"suggest": {
"kriswallsmith/assetic": "The best way to manage assets",
"monolog/monolog": "Log using Monolog",
"predis/predis": "Redis storage"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.0-dev"
}
},
"autoload": {
"psr-4": {
"DebugBar\\": "src/DebugBar/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Maxime Bouroumeau-Fuseau",
"email": "maxime.bouroumeau@gmail.com",
"homepage": "http://maximebf.com"
},
{
"name": "Barry vd. Heuvel",
"email": "barryvdh@gmail.com"
}
],
"description": "Debug bar in the browser for php application",
"homepage": "https://github.com/php-debugbar/php-debugbar",
"keywords": [
"debug",
"debug bar",
"debugbar",
"dev"
],
"support": {
"issues": "https://github.com/php-debugbar/php-debugbar/issues",
"source": "https://github.com/php-debugbar/php-debugbar/tree/v2.1.5"
},
"time": "2025-02-21T13:02:05+00:00"
},
{
"name": "phpmyadmin/sql-parser",
"version": "5.10.3",
@@ -11344,16 +11270,16 @@
},
{
"name": "phpstan/phpstan",
"version": "2.1.4",
"version": "2.1.6",
"source": {
"type": "git",
"url": "https://github.com/phpstan/phpstan.git",
"reference": "8f99e18eb775dbaf6460c95fa0b65312da9c746a"
"reference": "6eaec7c6c9e90dcfe46ad1e1ffa5171e2dab641c"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/8f99e18eb775dbaf6460c95fa0b65312da9c746a",
"reference": "8f99e18eb775dbaf6460c95fa0b65312da9c746a",
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/6eaec7c6c9e90dcfe46ad1e1ffa5171e2dab641c",
"reference": "6eaec7c6c9e90dcfe46ad1e1ffa5171e2dab641c",
"shasum": ""
},
"require": {
@@ -11398,7 +11324,7 @@
"type": "github"
}
],
"time": "2025-02-10T08:25:21+00:00"
"time": "2025-02-19T15:46:42+00:00"
},
{
"name": "phpstan/phpstan-deprecation-rules",
@@ -11820,16 +11746,16 @@
},
{
"name": "phpunit/phpunit",
"version": "11.5.7",
"version": "11.5.9",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/phpunit.git",
"reference": "e1cb706f019e2547039ca2c839898cd5f557ee5d"
"reference": "c91c830e7108a81e5845aeb6ba8fe3c1a4351c0b"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/e1cb706f019e2547039ca2c839898cd5f557ee5d",
"reference": "e1cb706f019e2547039ca2c839898cd5f557ee5d",
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/c91c830e7108a81e5845aeb6ba8fe3c1a4351c0b",
"reference": "c91c830e7108a81e5845aeb6ba8fe3c1a4351c0b",
"shasum": ""
},
"require": {
@@ -11839,7 +11765,7 @@
"ext-mbstring": "*",
"ext-xml": "*",
"ext-xmlwriter": "*",
"myclabs/deep-copy": "^1.12.1",
"myclabs/deep-copy": "^1.13.0",
"phar-io/manifest": "^2.0.4",
"phar-io/version": "^3.2.1",
"php": ">=8.2",
@@ -11901,7 +11827,7 @@
"support": {
"issues": "https://github.com/sebastianbergmann/phpunit/issues",
"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.9"
},
"funding": [
{
@@ -11917,7 +11843,7 @@
"type": "tidelift"
}
],
"time": "2025-02-06T16:10:05+00:00"
"time": "2025-02-21T06:08:50+00:00"
},
{
"name": "sebastian/cli-parser",

View File

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

461
package-lock.json generated
View File

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

View File

@@ -30,8 +30,16 @@ function parseToLocalDates() {
"use strict";
$('span.date-time').each(function () {
var date = $(this).data('date');
var obj = moment.utc(date).local();
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 +')');
});
}

View File

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

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