Compare commits

..

83 Commits

Author SHA1 Message Date
github-actions[bot]
4d7eb27fd0 Merge pull request #10102 from firefly-iii/release-1743913710
🤖 Automatically merge the PR into the develop branch.
2025-04-06 06:28:37 +02:00
JC5
fe0b8d0128 🤖 Auto commit for release 'develop' on 2025-04-06 2025-04-06 06:28:30 +02:00
James Cole
04f0fcfbf7 Merge pull request #10101 from firefly-iii/fix-null-pointer
Fix nullpointer.
2025-04-06 06:24:02 +02:00
James Cole
7e182cf070 Fix nullpointer. 2025-04-06 06:22:32 +02:00
James Cole
ad78c302ef Merge branch 'main' into develop
# Conflicts:
#	package-lock.json
2025-04-06 06:22:04 +02:00
James Cole
36b4c69491 Merge pull request #10097 from firefly-iii/dependabot/npm_and_yarn/npm_and_yarn-2bd33993d4
Bump vite from 6.2.4 to 6.2.5 in the npm_and_yarn group across 1 directory
2025-04-05 07:23:09 +02:00
dependabot[bot]
30bd0711f4 Bump vite in the npm_and_yarn group across 1 directory
Bumps the npm_and_yarn group with 1 update in the / directory: [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite).


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

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-04-04 15:59:25 +00:00
github-actions[bot]
d847827584 Merge pull request #10095 from firefly-iii/release-1743669036
🤖 Automatically merge the PR into the develop branch.
2025-04-03 10:30:45 +02:00
JC5
786c1fcd58 🤖 Auto commit for release 'develop' on 2025-04-03 2025-04-03 10:30:36 +02:00
James Cole
90e7f0c0f7 Merge pull request #10094 from firefly-iii/fix-more
Fix lint errors
2025-04-03 10:26:17 +02:00
Sander Dorigo
63f334abe5 Fix lint errors 2025-04-03 10:25:24 +02:00
James Cole
2466cd942f Update release.yml
Signed-off-by: James Cole <james@firefly-iii.org>
2025-04-03 10:22:09 +02:00
James Cole
ea37db87f4 Merge pull request #10093 from firefly-iii/fix-php-error
Fix dumb error
2025-04-03 10:13:52 +02:00
Sander Dorigo
c168fb6960 Fix dumb error 2025-04-03 10:13:06 +02:00
github-actions[bot]
03fb707b93 Merge pull request #10092 from firefly-iii/release-1743665835
🤖 Automatically merge the PR into the develop branch.
2025-04-03 09:37:23 +02:00
JC5
db226c2584 🤖 Auto commit for release 'develop' on 2025-04-03 2025-04-03 09:37:15 +02:00
James Cole
1c6ec82c91 Merge pull request #10091 from firefly-iii/better-mute
Better mute
2025-04-03 09:33:26 +02:00
Sander Dorigo
40eb77ffde Better mute 2025-04-03 09:32:41 +02:00
github-actions[bot]
17ddb01cd1 Merge pull request #10089 from firefly-iii/release-1743601357
🤖 Automatically merge the PR into the develop branch.
2025-04-02 15:42:46 +02:00
JC5
ca56c7af70 🤖 Auto commit for release 'develop' on 2025-04-02 2025-04-02 15:42:37 +02:00
James Cole
55c428070f Merge pull request #10087 from firefly-iii/fix-10025
Fix #10025
2025-04-02 12:13:28 +02:00
Sander Dorigo
574eec1c08 Fix #10025 2025-04-02 12:12:18 +02:00
James Cole
15cde8173e Merge pull request #10081 from firefly-iii/debug-10068
Add debug for #10068
2025-04-01 11:29:23 +02:00
Sander Dorigo
ccb581b4ee Add debug for #10068 2025-04-01 11:28:12 +02:00
James Cole
c5f8db5b50 Merge pull request #10080 from firefly-iii/fix-10069-2
fix #10069
2025-04-01 10:54:54 +02:00
Sander Dorigo
611748fbaf fix #10069 2025-04-01 10:54:08 +02:00
James Cole
b57dfa9432 Merge pull request #10078 from firefly-iii/fix-10069
Fix #10069
2025-04-01 10:35:22 +02:00
Sander Dorigo
253982d579 Fix #10069 2025-04-01 10:33:58 +02:00
James Cole
94c7a19aa0 Merge pull request #10076 from firefly-iii/mute-notifications
Fix #10069
2025-04-01 07:27:31 +02:00
Sander Dorigo
e9b360a721 Fix #10069 2025-04-01 07:26:29 +02:00
github-actions[bot]
ebf7f5932a Merge pull request #10075 from firefly-iii/release-1743484026
🤖 Automatically merge the PR into the develop branch.
2025-04-01 07:07:14 +02:00
JC5
4427f2fb99 🤖 Auto commit for release 'develop' on 2025-04-01 2025-04-01 07:07:06 +02:00
James Cole
6626dfbac3 Merge pull request #10074 from firefly-iii/mute-notifications
Mute notifications for demo site.
2025-04-01 07:02:58 +02:00
Sander Dorigo
093a6387a2 Mute notifications for demo site. 2025-04-01 06:59:55 +02:00
James Cole
21ddde9e0d Merge pull request #10072 from firefly-iii/dependabot/npm_and_yarn/npm_and_yarn-8ec3883370 2025-03-31 21:07:21 +02:00
dependabot[bot]
44d4e4e6da Bump vite in the npm_and_yarn group across 1 directory
Bumps the npm_and_yarn group with 1 update in the / directory: [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite).


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

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-03-31 18:43:22 +00:00
James Cole
e34e53eeb3 Merge pull request #10055 from firefly-iii/dependabot/composer/develop/guzzlehttp/guzzle-7.9.3
Bump guzzlehttp/guzzle from 7.9.2 to 7.9.3
2025-03-31 11:04:47 +02:00
James Cole
07fb45bb34 Merge pull request #10056 from firefly-iii/dependabot/composer/develop/phpstan/phpstan-2.1.11
Bump phpstan/phpstan from 2.1.10 to 2.1.11
2025-03-31 11:04:34 +02:00
mergify[bot]
d381669733 Merge branch 'develop' into dependabot/composer/develop/guzzlehttp/guzzle-7.9.3 2025-03-31 07:20:41 +00:00
mergify[bot]
fb9eb15ae1 Merge branch 'develop' into dependabot/composer/develop/phpstan/phpstan-2.1.11 2025-03-31 07:20:36 +00:00
github-actions[bot]
a2127c382b Merge pull request #10061 from firefly-iii/release-1743405544
🤖 Automatically merge the PR into the develop branch.
2025-03-31 09:19:58 +02:00
JC5
e10d39c093 🤖 Auto commit for release 'develop' on 2025-03-31 2025-03-31 09:19:04 +02:00
mergify[bot]
a933b49e7c Merge branch 'develop' into dependabot/composer/develop/guzzlehttp/guzzle-7.9.3 2025-03-31 07:15:55 +00:00
mergify[bot]
38bcd610df Merge branch 'develop' into dependabot/composer/develop/phpstan/phpstan-2.1.11 2025-03-31 07:15:49 +00:00
James Cole
5beb476a28 Merge pull request #10060 from firefly-iii/add-missing-files
ok final one
2025-03-31 09:15:44 +02:00
Sander Dorigo
3a43ce6546 ok final one 2025-03-31 09:15:03 +02:00
mergify[bot]
c11fddb097 Merge branch 'develop' into dependabot/composer/develop/guzzlehttp/guzzle-7.9.3 2025-03-31 07:13:06 +00:00
mergify[bot]
98f79cd9bf Merge branch 'develop' into dependabot/composer/develop/phpstan/phpstan-2.1.11 2025-03-31 07:13:03 +00:00
James Cole
a3d3fe758b Merge pull request #10059 from firefly-iii/add-missing-files
add missing files
2025-03-31 09:12:25 +02:00
Sander Dorigo
93587cf1b6 add missing files 2025-03-31 09:11:17 +02:00
mergify[bot]
361e95f102 Merge branch 'develop' into dependabot/composer/develop/guzzlehttp/guzzle-7.9.3 2025-03-31 07:07:16 +00:00
mergify[bot]
be212e7d1d Merge branch 'develop' into dependabot/composer/develop/phpstan/phpstan-2.1.11 2025-03-31 07:07:13 +00:00
James Cole
003a30727f Merge pull request #10058 from firefly-iii/add-missing-files
Add new files
2025-03-31 09:06:39 +02:00
Sander Dorigo
27b662e2dc Add new files 2025-03-31 09:05:58 +02:00
mergify[bot]
0b4d7ad95e Merge branch 'develop' into dependabot/composer/develop/guzzlehttp/guzzle-7.9.3 2025-03-31 07:03:39 +00:00
mergify[bot]
7acbfb230a Merge branch 'develop' into dependabot/composer/develop/phpstan/phpstan-2.1.11 2025-03-31 07:03:36 +00:00
James Cole
b974310798 Merge pull request #10057 from firefly-iii/add-missing-files
Add missing files
2025-03-31 09:02:58 +02:00
Sander Dorigo
e391725eed Add missing files 2025-03-31 09:01:29 +02:00
dependabot[bot]
f505580b33 Bump phpstan/phpstan from 2.1.10 to 2.1.11
Bumps [phpstan/phpstan](https://github.com/phpstan/phpstan) from 2.1.10 to 2.1.11.
- [Release notes](https://github.com/phpstan/phpstan/releases)
- [Changelog](https://github.com/phpstan/phpstan/blob/2.1.x/CHANGELOG.md)
- [Commits](https://github.com/phpstan/phpstan/compare/2.1.10...2.1.11)

---
updated-dependencies:
- dependency-name: phpstan/phpstan
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-03-31 03:10:51 +00:00
dependabot[bot]
270f932a48 Bump guzzlehttp/guzzle from 7.9.2 to 7.9.3
Bumps [guzzlehttp/guzzle](https://github.com/guzzle/guzzle) from 7.9.2 to 7.9.3.
- [Release notes](https://github.com/guzzle/guzzle/releases)
- [Changelog](https://github.com/guzzle/guzzle/blob/7.9/CHANGELOG.md)
- [Commits](https://github.com/guzzle/guzzle/compare/7.9.2...7.9.3)

---
updated-dependencies:
- dependency-name: guzzlehttp/guzzle
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-03-31 03:10:43 +00:00
James Cole
b9afa908e3 Merge pull request #10045 from firefly-iii/v2-additions
Small additions
2025-03-29 07:58:56 +01:00
James Cole
6dcc78b9e5 Small additions 2025-03-29 07:58:45 +01:00
James Cole
7b0e7e8612 Merge pull request #10039 from ovv/ovv/cron-update-check
update check: consider cron succesfull when disabled or too frequent
2025-03-26 14:34:56 +01:00
=
1ece4abd9d update check: consider cron succesfull when disabled or too frequent
If the update check cron is disabled or run more often than once a week
consider the cron run succesfull.
2025-03-26 13:57:23 +01:00
James Cole
07c03b672b Merge pull request #10035 from firefly-iii/resurrect-v2
Resurrect v2
2025-03-25 17:31:50 +01:00
James Cole
27ea50ec16 Merge pull request #10034 from firefly-iii/main
Merge back into develop.
2025-03-25 17:29:52 +01:00
James Cole
e1195e6663 Fix JS views. 2025-03-25 17:28:12 +01:00
James Cole
faeb17f319 Recreate API endpoints. 2025-03-25 17:27:59 +01:00
James Cole
db91b1b127 Merge pull request #10033 from firefly-iii/dependabot/npm_and_yarn/npm_and_yarn-14f44f5325
Bump vite from 6.2.2 to 6.2.3 in the npm_and_yarn group across 1 directory
2025-03-25 16:35:57 +01:00
dependabot[bot]
b5b511c86b Bump vite in the npm_and_yarn group across 1 directory
Bumps the npm_and_yarn group with 1 update in the / directory: [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite).


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

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-03-25 14:58:51 +00:00
github-actions[bot]
8c805fe0c9 Merge pull request #10028 from firefly-iii/release-1742786410
🤖 Automatically merge the PR into the develop branch.
2025-03-24 04:20:16 +01:00
JC5
b0672eb294 🤖 Auto commit for release 'develop' on 2025-03-24 2025-03-24 04:20:10 +01:00
James Cole
750019808c Finalise boxes. 2025-03-23 15:19:40 +01:00
James Cole
7f4510467f Convert subscription information to native. 2025-03-23 15:14:20 +01:00
James Cole
a46f8430df Account for renamed variable. 2025-03-23 15:04:38 +01:00
James Cole
5e1ecb2b11 Make sure the balance box converts to native. 2025-03-23 15:04:29 +01:00
James Cole
4fff59f16b Merge pull request #10024 from firefly-iii/fix-release-flow
Expand releases.md and add extra text to release docs.
2025-03-23 09:06:05 +01:00
James Cole
eea8f5e07e Expand releases.md and add extra text to release docs. 2025-03-23 09:05:33 +01:00
James Cole
a3fcd636e7 Get v2 up and running (sort of) 2025-03-23 09:05:06 +01:00
James Cole
de6dc19077 Merge pull request #10023 from firefly-iii/enable-persian
Enable persian
2025-03-23 09:04:15 +01:00
James Cole
7a8e3aca03 Enable persion 2025-03-23 09:03:44 +01:00
James Cole
076047ad24 Enable Persian 2025-03-23 09:03:33 +01:00
James Cole
a4e1c8c24f Merge pull request #10019 from firefly-iii/main
Merge job changes back into develop
2025-03-22 14:09:22 +01:00
81 changed files with 2382 additions and 890 deletions

View File

@@ -406,16 +406,16 @@
},
{
"name": "friendsofphp/php-cs-fixer",
"version": "v3.73.1",
"version": "v3.75.0",
"source": {
"type": "git",
"url": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer.git",
"reference": "ffcb8200a42045e65049af7910cfd022f631b064"
"reference": "399a128ff2fdaf4281e4e79b755693286cdf325c"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/ffcb8200a42045e65049af7910cfd022f631b064",
"reference": "ffcb8200a42045e65049af7910cfd022f631b064",
"url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/399a128ff2fdaf4281e4e79b755693286cdf325c",
"reference": "399a128ff2fdaf4281e4e79b755693286cdf325c",
"shasum": ""
},
"require": {
@@ -498,7 +498,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.73.1"
"source": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/tree/v3.75.0"
},
"funding": [
{
@@ -506,7 +506,7 @@
"type": "github"
}
],
"time": "2025-03-19T23:42:16+00:00"
"time": "2025-03-31T18:40:42+00:00"
},
{
"name": "psr/container",
@@ -1256,16 +1256,16 @@
},
{
"name": "symfony/console",
"version": "v7.2.1",
"version": "v7.2.5",
"source": {
"type": "git",
"url": "https://github.com/symfony/console.git",
"reference": "fefcc18c0f5d0efe3ab3152f15857298868dc2c3"
"reference": "e51498ea18570c062e7df29d05a7003585b19b88"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/console/zipball/fefcc18c0f5d0efe3ab3152f15857298868dc2c3",
"reference": "fefcc18c0f5d0efe3ab3152f15857298868dc2c3",
"url": "https://api.github.com/repos/symfony/console/zipball/e51498ea18570c062e7df29d05a7003585b19b88",
"reference": "e51498ea18570c062e7df29d05a7003585b19b88",
"shasum": ""
},
"require": {
@@ -1329,7 +1329,7 @@
"terminal"
],
"support": {
"source": "https://github.com/symfony/console/tree/v7.2.1"
"source": "https://github.com/symfony/console/tree/v7.2.5"
},
"funding": [
{
@@ -1345,7 +1345,7 @@
"type": "tidelift"
}
],
"time": "2024-12-11T03:49:26+00:00"
"time": "2025-03-12T08:11:12+00:00"
},
{
"name": "symfony/deprecation-contracts",
@@ -2243,16 +2243,16 @@
},
{
"name": "symfony/process",
"version": "v7.2.4",
"version": "v7.2.5",
"source": {
"type": "git",
"url": "https://github.com/symfony/process.git",
"reference": "d8f411ff3c7ddc4ae9166fb388d1190a2df5b5cf"
"reference": "87b7c93e57df9d8e39a093d32587702380ff045d"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/process/zipball/d8f411ff3c7ddc4ae9166fb388d1190a2df5b5cf",
"reference": "d8f411ff3c7ddc4ae9166fb388d1190a2df5b5cf",
"url": "https://api.github.com/repos/symfony/process/zipball/87b7c93e57df9d8e39a093d32587702380ff045d",
"reference": "87b7c93e57df9d8e39a093d32587702380ff045d",
"shasum": ""
},
"require": {
@@ -2284,7 +2284,7 @@
"description": "Executes commands in sub-processes",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/process/tree/v7.2.4"
"source": "https://github.com/symfony/process/tree/v7.2.5"
},
"funding": [
{
@@ -2300,7 +2300,7 @@
"type": "tidelift"
}
],
"time": "2025-02-05T08:33:46+00:00"
"time": "2025-03-13T12:21:46+00:00"
},
{
"name": "symfony/service-contracts",

View File

@@ -59,7 +59,28 @@ jobs:
git config user.email release@firefly-iii.org
git config advice.addIgnoredFile false
git config push.autoSetupRemote true
- name: crowdin action
- name: Lint PHP
run: |
php_lint_file()
{
local php_file="$1"
php -l "$php_file" &> /dev/null
if [ "$?" -ne 0 ]
then
echo -e "[FAIL] $php_file"
return 1
fi
}
export -f php_lint_file
find . -path ./vendor -prune -o -name '*.php' | parallel -j 4 php_lint_file {}
if [ "$?" -ne 0 ]
then
exit 1
fi
- name: Crowdin action
uses: crowdin/github-action@v2
with:
upload_sources: true
@@ -260,6 +281,8 @@ jobs:
sudo chown -R runner:docker output.txt
touch output.txt
echo '' >> output.txt
echo "Welcome to release $version of Firefly III. It contains the the latest fixes, translations and features. Docker users can find this release under the \`latest\` tag." >> output.txt
echo '' >> output.txt
echo '### Instructions' >> output.txt
echo '' >> output.txt
echo "* 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

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
- =
- Lompi
- Jose Diaz-Gonzalez
- SoftBrix

View File

@@ -27,13 +27,16 @@ namespace FireflyIII\Api\V1\Controllers\Chart;
use Carbon\Carbon;
use FireflyIII\Api\V1\Controllers\Controller;
use FireflyIII\Api\V1\Requests\Data\DateRequest;
use FireflyIII\Api\V1\Requests\Chart\ChartRequest;
use FireflyIII\Enums\AccountTypeEnum;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Models\Account;
use FireflyIII\Models\Preference;
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use FireflyIII\Support\Chart\ChartData;
use FireflyIII\Support\Facades\Steam;
use FireflyIII\Support\Http\Api\ApiSupport;
use FireflyIII\Support\Http\Api\CollectsAccountsFromFilter;
use FireflyIII\User;
use Illuminate\Http\JsonResponse;
@@ -43,8 +46,10 @@ use Illuminate\Http\JsonResponse;
class AccountController extends Controller
{
use ApiSupport;
use CollectsAccountsFromFilter;
private AccountRepositoryInterface $repository;
private ChartData $chartData;
/**
* AccountController constructor.
@@ -56,6 +61,7 @@ class AccountController extends Controller
function ($request, $next) {
/** @var User $user */
$user = auth()->user();
$this->chartData = new ChartData();
$this->repository = app(AccountRepositoryInterface::class);
$this->repository->setUser($user);
@@ -64,6 +70,29 @@ class AccountController extends Controller
);
}
/**
* TODO fix documentation
*
* @throws FireflyException
*/
public function dashboard(ChartRequest $request): JsonResponse
{
$queryParameters = $request->getParameters();
$accounts = $this->getAccountList($queryParameters);
// move date to end of day
$queryParameters['start']->startOfDay();
$queryParameters['end']->endOfDay();
// loop each account, and collect info:
/** @var Account $account */
foreach ($accounts as $account) {
$this->renderAccountData($queryParameters, $account);
}
return response()->json($this->chartData->render());
}
/**
* This endpoint is documented at:
* https://api-docs.firefly-iii.org/?urls.primaryName=2.0.0%20(v1)#/charts/getChartAccountOverview
@@ -133,4 +162,45 @@ class AccountController extends Controller
return response()->json($chartData);
}
/**
* @throws FireflyException
*/
private function renderAccountData(array $params, Account $account): void
{
$currency = $this->repository->getAccountCurrency($account);
if (null === $currency) {
$currency = $this->default;
}
$currentSet = [
'label' => $account->name,
// the currency that belongs to the account.
'currency_id' => (string) $currency->id,
'currency_code' => $currency->code,
'currency_symbol' => $currency->symbol,
'currency_decimal_places' => $currency->decimal_places,
// the default currency of the user (could be the same!)
'date' => $params['start']->toAtomString(),
'start' => $params['start']->toAtomString(),
'end' => $params['end']->toAtomString(),
'period' => '1D',
'entries' => [],
];
$currentStart = clone $params['start'];
$range = Steam::finalAccountBalanceInRange($account, $params['start'], clone $params['end'], $this->convertToNative);
$previous = array_values($range)[0]['balance'];
while ($currentStart <= $params['end']) {
$format = $currentStart->format('Y-m-d');
$label = $currentStart->toAtomString();
$balance = array_key_exists($format, $range) ? $range[$format]['balance'] : $previous;
$previous = $balance;
$currentStart->addDay();
$currentSet['entries'][$label] = $balance;
}
$this->chartData->add($currentSet);
}
}

View File

@@ -0,0 +1,260 @@
<?php
/*
* BudgetController.php
* Copyright (c) 2023 james@firefly-iii.org
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace FireflyIII\Api\V1\Controllers\Chart;
use Carbon\Carbon;
use FireflyIII\Api\V1\Controllers\Controller;
use FireflyIII\Api\V1\Requests\Generic\DateRequest;
use FireflyIII\Enums\UserRoleEnum;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Models\Budget;
use FireflyIII\Models\BudgetLimit;
use FireflyIII\Models\TransactionCurrency;
use FireflyIII\Repositories\Budget\BudgetLimitRepositoryInterface;
use FireflyIII\Repositories\Budget\BudgetRepositoryInterface;
use FireflyIII\Repositories\Budget\OperationsRepositoryInterface;
use FireflyIII\Support\Http\Api\CleansChartData;
use FireflyIII\Support\Http\Api\ValidatesUserGroupTrait;
use Illuminate\Http\JsonResponse;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Log;
/**
* Class BudgetController
*/
class BudgetController extends Controller
{
use CleansChartData;
use ValidatesUserGroupTrait;
protected array $acceptedRoles = [UserRoleEnum::READ_ONLY];
protected OperationsRepositoryInterface $opsRepository;
private BudgetLimitRepositoryInterface $blRepository;
private array $currencies = [];
private TransactionCurrency $currency;
private BudgetRepositoryInterface $repository;
public function __construct()
{
parent::__construct();
$this->middleware(
function ($request, $next) {
$this->repository = app(BudgetRepositoryInterface::class);
$this->blRepository = app(BudgetLimitRepositoryInterface::class);
$this->opsRepository = app(OperationsRepositoryInterface::class);
$userGroup = $this->validateUserGroup($request);
$this->repository->setUserGroup($userGroup);
$this->opsRepository->setUserGroup($userGroup);
$this->blRepository->setUserGroup($userGroup);
return $next($request);
}
);
}
/**
* TODO see autocomplete/accountcontroller
*/
public function dashboard(DateRequest $request): JsonResponse
{
$params = $request->getAll();
/** @var Carbon $start */
$start = $params['start'];
/** @var Carbon $end */
$end = $params['end'];
// code from FrontpageChartGenerator, but not in separate class
$budgets = $this->repository->getActiveBudgets();
$data = [];
/** @var Budget $budget */
foreach ($budgets as $budget) {
// could return multiple arrays, so merge.
$data = array_merge($data, $this->processBudget($budget, $start, $end));
}
return response()->json($this->clean($data));
}
/**
* @throws FireflyException
*/
private function processBudget(Budget $budget, Carbon $start, Carbon $end): array
{
// get all limits:
$limits = $this->blRepository->getBudgetLimits($budget, $start, $end);
$rows = [];
// if no limits
if (0 === $limits->count()) {
// return as a single item in an array
$rows = $this->noBudgetLimits($budget, $start, $end);
}
if ($limits->count() > 0) {
$rows = $this->budgetLimits($budget, $limits);
}
// is always an array
$return = [];
foreach ($rows as $row) {
$current = [
'label' => $budget->name,
'currency_id' => (string) $row['currency_id'],
'currency_code' => $row['currency_code'],
'currency_name' => $row['currency_name'],
'currency_decimal_places' => $row['currency_decimal_places'],
'period' => null,
'start' => $row['start'],
'end' => $row['end'],
'entries' => [
'spent' => $row['spent'],
'left' => $row['left'],
'overspent' => $row['overspent'],
],
];
$return[] = $current;
}
return $return;
}
/**
* When no budget limits are present, the expenses of the whole period are collected and grouped.
* This is grouped per currency. Because there is no limit set, "left to spend" and "overspent" are empty.
*
* @throws FireflyException
*/
private function noBudgetLimits(Budget $budget, Carbon $start, Carbon $end): array
{
$spent = $this->opsRepository->listExpenses($start, $end, null, new Collection([$budget]));
return $this->processExpenses($budget->id, $spent, $start, $end);
}
/**
* Shared between the "noBudgetLimits" function and "processLimit". Will take a single set of expenses and return
* its info.
*
* @param array<int, array<int, string>> $array
*
* @throws FireflyException
*/
private function processExpenses(int $budgetId, array $array, Carbon $start, Carbon $end): array
{
$return = [];
/**
* This array contains the expenses in this budget. Grouped per currency.
* The grouping is on the main currency only.
*
* @var int $currencyId
* @var array $block
*/
foreach ($array as $currencyId => $block) {
$this->currencies[$currencyId] ??= TransactionCurrency::find($currencyId);
$return[$currencyId] ??= [
'currency_id' => (string) $currencyId,
'currency_code' => $block['currency_code'],
'currency_name' => $block['currency_name'],
'currency_symbol' => $block['currency_symbol'],
'currency_decimal_places' => (int) $block['currency_decimal_places'],
'start' => $start->toAtomString(),
'end' => $end->toAtomString(),
'spent' => '0',
'left' => '0',
'overspent' => '0',
];
$currentBudgetArray = $block['budgets'][$budgetId];
// var_dump($return);
/** @var array $journal */
foreach ($currentBudgetArray['transaction_journals'] as $journal) {
$return[$currencyId]['spent'] = bcadd($return[$currencyId]['spent'], $journal['amount']);
}
}
return $return;
}
/**
* Function that processes each budget limit (per budget).
*
* If you have a budget limit in EUR, only transactions in EUR will be considered.
* If you have a budget limit in GBP, only transactions in GBP will be considered.
*
* If you have a budget limit in EUR, and a transaction in GBP, it will not be considered for the EUR budget limit.
*
* @throws FireflyException
*/
private function budgetLimits(Budget $budget, Collection $limits): array
{
app('log')->debug(sprintf('Now in budgetLimits(#%d)', $budget->id));
$data = [];
/** @var BudgetLimit $limit */
foreach ($limits as $limit) {
$data = array_merge($data, $this->processLimit($budget, $limit));
}
return $data;
}
/**
* @throws FireflyException
*/
private function processLimit(Budget $budget, BudgetLimit $limit): array
{
Log::debug(sprintf('Created new ExchangeRateConverter in %s', __METHOD__));
$end = clone $limit->end_date;
$end->endOfDay();
$spent = $this->opsRepository->listExpenses($limit->start_date, $end, null, new Collection([$budget]));
$limitCurrencyId = $limit->transaction_currency_id;
$filtered = [];
/** @var array $entry */
foreach ($spent as $currencyId => $entry) {
// only spent the entry where the entry's currency matches the budget limit's currency
// so $filtered will only have 1 or 0 entries
if ($entry['currency_id'] === $limitCurrencyId) {
$filtered[$currencyId] = $entry;
}
}
$result = $this->processExpenses($budget->id, $filtered, $limit->start_date, $end);
if (1 === count($result)) {
$compare = bccomp($limit->amount, app('steam')->positive($result[$limitCurrencyId]['spent']));
if (1 === $compare) {
// convert this amount into the native currency:
$result[$limitCurrencyId]['left'] = bcadd($limit->amount, $result[$limitCurrencyId]['spent']);
}
if ($compare <= 0) {
$result[$limitCurrencyId]['overspent'] = app('steam')->positive(bcadd($limit->amount, $result[$limitCurrencyId]['spent']));
}
}
return $result;
}
}

View File

@@ -0,0 +1,128 @@
<?php
/*
* CategoryController.php
* Copyright (c) 2023 james@firefly-iii.org
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace FireflyIII\Api\V1\Controllers\Chart;
use Carbon\Carbon;
use FireflyIII\Api\V2\Controllers\Controller;
use FireflyIII\Api\V2\Request\Generic\DateRequest;
use FireflyIII\Enums\AccountTypeEnum;
use FireflyIII\Enums\TransactionTypeEnum;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Helpers\Collector\GroupCollectorInterface;
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use FireflyIII\Repositories\Currency\CurrencyRepositoryInterface;
use FireflyIII\Support\Http\Api\CleansChartData;
use FireflyIII\Support\Http\Api\ValidatesUserGroupTrait;
use Illuminate\Http\JsonResponse;
/**
* Class BudgetController
*/
class CategoryController extends Controller
{
use CleansChartData;
use ValidatesUserGroupTrait;
private AccountRepositoryInterface $accountRepos;
private CurrencyRepositoryInterface $currencyRepos;
public function __construct()
{
parent::__construct();
$this->middleware(
function ($request, $next) {
$this->accountRepos = app(AccountRepositoryInterface::class);
$this->currencyRepos = app(CurrencyRepositoryInterface::class);
$userGroup = $this->validateUserGroup($request);
$this->accountRepos->setUserGroup($userGroup);
$this->currencyRepos->setUserGroup($userGroup);
return $next($request);
}
);
}
/**
* TODO may be worth to move to a handler but the data is simple enough.
* TODO see autoComplete/account controller
*
* @throws FireflyException
*
* @SuppressWarnings("PHPMD.UnusedFormalParameter")
*/
public function dashboard(DateRequest $request): JsonResponse
{
/** @var Carbon $start */
$start = $this->parameters->get('start');
/** @var Carbon $end */
$end = $this->parameters->get('end');
$accounts = $this->accountRepos->getAccountsByType([AccountTypeEnum::DEBT->value, AccountTypeEnum::LOAN->value, AccountTypeEnum::MORTGAGE->value, AccountTypeEnum::ASSET->value, AccountTypeEnum::DEFAULT->value]);
$currencies = [];
$return = [];
// get journals for entire period:
/** @var GroupCollectorInterface $collector */
$collector = app(GroupCollectorInterface::class);
$collector->setRange($start, $end)->withAccountInformation();
$collector->setXorAccounts($accounts)->withCategoryInformation();
$collector->setTypes([TransactionTypeEnum::WITHDRAWAL->value, TransactionTypeEnum::RECONCILIATION->value]);
$journals = $collector->getExtractedJournals();
/** @var array $journal */
foreach ($journals as $journal) {
$currencyId = (int) $journal['currency_id'];
$currency = $currencies[$currencyId] ?? $this->currencyRepos->find($currencyId);
$currencies[$currencyId] = $currency;
$categoryName = null === $journal['category_name'] ? (string) trans('firefly.no_category') : $journal['category_name'];
$amount = app('steam')->positive($journal['amount']);
$key = sprintf('%s-%s', $categoryName, $currency->code);
// create arrays
$return[$key] ??= [
'label' => $categoryName,
'currency_id' => (string) $currency->id,
'currency_code' => $currency->code,
'currency_name' => $currency->name,
'currency_symbol' => $currency->symbol,
'currency_decimal_places' => $currency->decimal_places,
'period' => null,
'start' => $start->toAtomString(),
'end' => $end->toAtomString(),
'amount' => '0',
];
// add monies
$return[$key]['amount'] = bcadd($return[$key]['amount'], $amount);
}
$return = array_values($return);
// order by amount
usort($return, static function (array $a, array $b) {
return (float) $a['amount'] < (float) $b['amount'] ? 1 : -1;
});
return response()->json($this->clean($return));
}
}

View File

@@ -39,6 +39,8 @@ use FireflyIII\Repositories\Budget\BudgetRepositoryInterface;
use FireflyIII\Repositories\Budget\OperationsRepositoryInterface;
use FireflyIII\Repositories\Currency\CurrencyRepositoryInterface;
use FireflyIII\Support\Facades\Amount;
use FireflyIII\Support\Http\Api\ExchangeRateConverter;
use FireflyIII\Support\Report\Summarizer\TransactionSummarizer;
use FireflyIII\User;
use Illuminate\Http\JsonResponse;
use Illuminate\Support\Facades\Log;
@@ -100,7 +102,7 @@ class BasicController extends Controller
// balance information:
$balanceData = $this->getBalanceInformation($start, $end);
$billData = $this->getBillInformation($start, $end);
$billData = $this->getSubscriptionInformation($start, $end);
$spentData = $this->getLeftToSpendInfo($start, $end);
$netWorthData = $this->getNetWorthInfo($end);
// $balanceData = [];
@@ -122,6 +124,7 @@ class BasicController extends Controller
private function getBalanceInformation(Carbon $start, Carbon $end): array
{
Log::debug('getBalanceInformation');
// some config settings
$convertToNative = Amount::convertToNative();
$default = Amount::getNativeCurrency();
@@ -130,47 +133,110 @@ class BasicController extends Controller
$expenses = [];
$sums = [];
$return = [];
$currencies = [
$default->id => $default,
];
// collect income of user using the new group collector.
/** @var GroupCollectorInterface $collector */
$collector = app(GroupCollectorInterface::class);
$collector->setRange($start, $end)->setPage($this->parameters->get('page'))->setTypes([TransactionTypeEnum::DEPOSIT->value]);
$summarizer = new TransactionSummarizer();
$set = $collector->setRange($start, $end)->setTypes([TransactionTypeEnum::DEPOSIT->value])->getExtractedJournals();
$incomes = $summarizer->groupByCurrencyId($set, 'positive', false);
$set = $collector->getExtractedJournals();
/** @var array $journal */
foreach ($set as $journal) {
$currencyId = $convertToNative ? $default->id : (int) $journal['currency_id'];
$amount = Amount::getAmountFromJournal($journal);
$incomes[$currencyId] ??= '0';
$incomes[$currencyId] = bcadd(
$incomes[$currencyId],
bcmul($amount, '-1')
);
$sums[$currencyId] ??= '0';
$sums[$currencyId] = bcadd($sums[$currencyId], bcmul($amount, '-1'));
}
// collect expenses of user.
// collect expenses of user using the new group collector.
/** @var GroupCollectorInterface $collector */
$collector = app(GroupCollectorInterface::class);
$collector->setRange($start, $end)->setPage($this->parameters->get('page'))->setTypes([TransactionTypeEnum::WITHDRAWAL->value]);
$set = $collector->getExtractedJournals();
$set = $collector->setRange($start, $end)->setPage($this->parameters->get('page'))->setTypes([TransactionTypeEnum::WITHDRAWAL->value])->getExtractedJournals();
$expenses = $summarizer->groupByCurrencyId($set, 'negative', false);
/** @var array $journal */
foreach ($set as $journal) {
$currencyId = $convertToNative ? $default->id : (int) $journal['currency_id'];
$amount = Amount::getAmountFromJournal($journal);
$expenses[$currencyId] ??= '0';
$expenses[$currencyId] = bcadd($expenses[$currencyId], $amount);
$sums[$currencyId] ??= '0';
$sums[$currencyId] = bcadd($sums[$currencyId], $amount);
// if convert to native, do so right now.
if ($convertToNative) {
$newExpenses = [
$default->id => [
'currency_id' => $default->id,
'currency_code' => $default->code,
'currency_symbol' => $default->symbol,
'currency_decimal_places' => $default->decimal_places,
'sum' => '0',
],
];
$newIncomes = [
$default->id => [
'currency_id' => $default->id,
'currency_code' => $default->code,
'currency_symbol' => $default->symbol,
'currency_decimal_places' => $default->decimal_places,
'sum' => '0',
],
];
$sums = [
$default->id => [
'currency_id' => $default->id,
'currency_code' => $default->code,
'currency_symbol' => $default->symbol,
'currency_decimal_places' => $default->decimal_places,
'sum' => '0',
],
];
$converter = new ExchangeRateConverter();
// loop over income and expenses
foreach ([$expenses, $incomes] as $index => $array) {
// loop over either one.
foreach ($array as $entry) {
// if it is the native currency already.
if ($entry['currency_id'] === $default->id) {
$sums[$default->id]['sum'] = bcadd($entry['sum'], $sums[$default->id]['sum']);
// don't forget to add it to newExpenses and newIncome
if (0 === $index) {
$newExpenses[$default->id]['sum'] = bcadd($newExpenses[$default->id]['sum'], $entry['sum']);
}
if (1 === $index) {
$newIncomes[$default->id]['sum'] = bcadd($newIncomes[$default->id]['sum'], $entry['sum']);
}
continue;
}
$currencies[$entry['currency_id']] ??= $this->currencyRepos->find($entry['currency_id']);
$convertedSum = $converter->convert($currencies[$entry['currency_id']], $default, $start, $entry['sum']);
$sums[$default->id]['sum'] = bcadd($sums[$default->id]['sum'], $convertedSum);
if (0 === $index) {
$newExpenses[$default->id]['sum'] = bcadd($newExpenses[$default->id]['sum'], $convertedSum);
}
if (1 === $index) {
$newIncomes[$default->id]['sum'] = bcadd($newIncomes[$default->id]['sum'], $convertedSum);
}
}
}
$incomes = $newIncomes;
$expenses = $newExpenses;
}
if (!$convertToNative) {
foreach ([$expenses, $incomes] as $array) {
foreach ($array as $entry) {
$currencyId = $entry['currency_id'];
$sums[$currencyId] ??= [
'currency_id' => $entry['currency_id'],
'currency_code' => $entry['currency_code'],
'currency_symbol' => $entry['currency_symbol'],
'currency_decimal_places' => $entry['currency_decimal_places'],
'sum' => '0',
];
$sums[$currencyId]['sum'] = bcadd($sums[$currencyId]['sum'], $entry['sum']);
}
}
}
// format amounts:
$keys = array_keys($sums);
foreach ($keys as $currencyId) {
$currency = $this->currencyRepos->find($currencyId);
$currency = $currencies[$currencyId] ?? $this->currencyRepos->find($currencyId);
if (null === $currency) {
continue;
}
@@ -178,37 +244,37 @@ class BasicController extends Controller
$return[] = [
'key' => sprintf('balance-in-%s', $currency->code),
'title' => trans('firefly.box_balance_in_currency', ['currency' => $currency->symbol]),
'monetary_value' => $sums[$currencyId] ?? '0',
'monetary_value' => $sums[$currencyId]['sum'] ?? '0',
'currency_id' => (string) $currency->id,
'currency_code' => $currency->code,
'currency_symbol' => $currency->symbol,
'currency_decimal_places' => $currency->decimal_places,
'value_parsed' => app('amount')->formatAnything($currency, $sums[$currencyId] ?? '0', false),
'value_parsed' => app('amount')->formatAnything($currency, $sums[$currencyId]['sum'] ?? '0', false),
'local_icon' => 'balance-scale',
'sub_title' => app('amount')->formatAnything($currency, $expenses[$currencyId] ?? '0', false)
.' + '.app('amount')->formatAnything($currency, $incomes[$currencyId] ?? '0', false),
'sub_title' => app('amount')->formatAnything($currency, $expenses[$currencyId]['sum'] ?? '0', false)
.' + '.app('amount')->formatAnything($currency, $incomes[$currencyId]['sum'] ?? '0', false),
];
$return[] = [
'key' => sprintf('spent-in-%s', $currency->code),
'title' => trans('firefly.box_spent_in_currency', ['currency' => $currency->symbol]),
'monetary_value' => $expenses[$currencyId] ?? '0',
'monetary_value' => $expenses[$currencyId]['sum'] ?? '0',
'currency_id' => (string) $currency->id,
'currency_code' => $currency->code,
'currency_symbol' => $currency->symbol,
'currency_decimal_places' => $currency->decimal_places,
'value_parsed' => app('amount')->formatAnything($currency, $expenses[$currencyId] ?? '0', false),
'value_parsed' => app('amount')->formatAnything($currency, $expenses[$currencyId]['sum'] ?? '0', false),
'local_icon' => 'balance-scale',
'sub_title' => '',
];
$return[] = [
'key' => sprintf('earned-in-%s', $currency->code),
'title' => trans('firefly.box_earned_in_currency', ['currency' => $currency->symbol]),
'monetary_value' => $incomes[$currencyId] ?? '0',
'monetary_value' => $incomes[$currencyId]['sum'] ?? '0',
'currency_id' => (string) $currency->id,
'currency_code' => $currency->code,
'currency_symbol' => $currency->symbol,
'currency_decimal_places' => $currency->decimal_places,
'value_parsed' => app('amount')->formatAnything($currency, $incomes[$currencyId] ?? '0', false),
'value_parsed' => app('amount')->formatAnything($currency, $incomes[$currencyId]['sum'] ?? '0', false),
'local_icon' => 'balance-scale',
'sub_title' => '',
];
@@ -227,7 +293,7 @@ class BasicController extends Controller
'value_parsed' => app('amount')->formatAnything($currency, '0', false),
'local_icon' => 'balance-scale',
'sub_title' => app('amount')->formatAnything($currency, '0', false)
.' + '.app('amount')->formatAnything($currency, '0', false),
.' + '.app('amount')->formatAnything($currency, '0', false),
];
$return[] = [
'key' => sprintf('spent-in-%s', $currency->code),
@@ -258,15 +324,72 @@ class BasicController extends Controller
return $return;
}
private function getBillInformation(Carbon $start, Carbon $end): array
private function getSubscriptionInformation(Carbon $start, Carbon $end): array
{
app('log')->debug(sprintf('Now in getBillInformation("%s", "%s")', $start->format('Y-m-d'), $end->format('Y-m-d-')));
Log::debug(sprintf('Now in getBillInformation("%s", "%s")', $start->format('Y-m-d'), $end->format('Y-m-d-')));
/*
* Since both this method and the chart use the exact same data, we can suffice
* with calling the one method in the bill repository that will get this amount.
*/
$paidAmount = $this->billRepository->sumPaidInRange($start, $end);
$unpaidAmount = $this->billRepository->sumUnpaidInRange($start, $end);
$currencies = [
$this->nativeCurrency->id => $this->nativeCurrency,
];
if ($this->convertToNative) {
$converter = new ExchangeRateConverter();
$newPaidAmount = [[
'id' => $this->nativeCurrency->id,
'name' => $this->nativeCurrency->name,
'symbol' => $this->nativeCurrency->symbol,
'code' => $this->nativeCurrency->code,
'decimal_places' => $this->nativeCurrency->decimal_places,
'sum' => '0',
]];
$newUnpaidAmount = [[
'id' => $this->nativeCurrency->id,
'name' => $this->nativeCurrency->name,
'symbol' => $this->nativeCurrency->symbol,
'code' => $this->nativeCurrency->code,
'decimal_places' => $this->nativeCurrency->decimal_places,
'sum' => '0',
]];
foreach ([$paidAmount, $unpaidAmount] as $index => $array) {
foreach ($array as $item) {
$currencyId = (int) $item['id'];
if (0 === $index) {
// paid amount
if ($currencyId === $this->nativeCurrency->id) {
$newPaidAmount[0]['sum'] = bcadd($newPaidAmount[0]['sum'], $item['sum']);
continue;
}
$currencies[$currencyId] ??= $this->currencyRepos->find($currencyId);
$convertedAmount = $converter->convert($currencies[$currencyId], $this->nativeCurrency, $start, $item['sum']);
$newPaidAmount[0]['sum'] = bcadd($newPaidAmount[0]['sum'], $convertedAmount);
continue;
}
// unpaid amount
if ($currencyId === $this->nativeCurrency->id) {
$newUnpaidAmount[0]['sum'] = bcadd($newUnpaidAmount[0]['sum'], $item['sum']);
continue;
}
$currencies[$currencyId] ??= $this->currencyRepos->find($currencyId);
$convertedAmount = $converter->convert($currencies[$currencyId], $this->nativeCurrency, $start, $item['sum']);
$newUnpaidAmount[0]['sum'] = bcadd($newUnpaidAmount[0]['sum'], $convertedAmount);
}
}
$paidAmount = $newPaidAmount;
$unpaidAmount = $newUnpaidAmount;
}
// var_dump($paidAmount);
// var_dump($unpaidAmount);
// exit;
$return = [];
@@ -307,7 +430,7 @@ class BasicController extends Controller
'sub_title' => '',
];
}
app('log')->debug(sprintf('Done with getBillInformation("%s", "%s")', $start->format('Y-m-d'), $end->format('Y-m-d-')));
Log::debug(sprintf('Done with getBillInformation("%s", "%s")', $start->format('Y-m-d'), $end->format('Y-m-d-')));
if (0 === count($return)) {
$currency = $this->nativeCurrency;

View File

@@ -0,0 +1,91 @@
<?php
/*
* DashboardChartRequest.php
* Copyright (c) 2023 james@firefly-iii.org
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace FireflyIII\Api\V1\Requests\Chart;
use FireflyIII\Enums\UserRoleEnum;
use FireflyIII\Support\Http\Api\ValidatesUserGroupTrait;
use FireflyIII\Support\Request\ChecksLogin;
use FireflyIII\Support\Request\ConvertsDataTypes;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Support\Facades\Log;
use Illuminate\Validation\Validator;
/**
* Class ChartRequest
*/
class ChartRequest extends FormRequest
{
use ChecksLogin;
use ConvertsDataTypes;
use ValidatesUserGroupTrait;
protected array $acceptedRoles = [UserRoleEnum::READ_ONLY];
public function getParameters(): array
{
return [
'start' => $this->convertDateTime('start')?->startOfDay(),
'end' => $this->convertDateTime('end')?->endOfDay(),
'preselected' => $this->convertString('preselected', 'empty'),
'period' => $this->convertString('period', '1M'),
'accounts' => $this->arrayFromValue($this->get('accounts')),
];
}
/**
* The rules that the incoming request must be matched against.
*/
public function rules(): array
{
return [
'start' => 'required|date|after:1900-01-01|before:2099-12-31|before_or_equal:end',
'end' => 'required|date|after:1900-01-01|before:2099-12-31|after_or_equal:start',
'preselected' => sprintf('nullable|in:%s', implode(',', config('firefly.preselected_accounts'))),
'period' => sprintf('nullable|in:%s', implode(',', config('firefly.valid_view_ranges'))),
'accounts.*' => 'exists:accounts,id',
];
}
public function withValidator(Validator $validator): void
{
$validator->after(
static function (Validator $validator): void {
// validate transaction query data.
$data = $validator->getData();
if (!array_key_exists('accounts', $data)) {
// $validator->errors()->add('accounts', trans('validation.filled', ['attribute' => 'accounts']));
return;
}
if (!is_array($data['accounts'])) {
$validator->errors()->add('accounts', trans('validation.filled', ['attribute' => 'accounts']));
}
}
);
if ($validator->fails()) {
Log::channel('audit')->error(sprintf('Validation errors in %s', __CLASS__), $validator->errors()->toArray());
}
}
}

View File

@@ -0,0 +1,62 @@
<?php
/*
* DateRequest.php
* Copyright (c) 2021 james@firefly-iii.org
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace FireflyIII\Api\V1\Requests\Generic;
use FireflyIII\Support\Request\ChecksLogin;
use FireflyIII\Support\Request\ConvertsDataTypes;
use Illuminate\Foundation\Http\FormRequest;
/**
* Request class for end points that require date parameters.
*
* Class DateRequest
*/
class DateRequest extends FormRequest
{
use ChecksLogin;
use ConvertsDataTypes;
/**
* Get all data from the request.
*/
public function getAll(): array
{
return [
'start' => $this->getCarbonDate('start')->startOfDay(),
'end' => $this->getCarbonDate('end')->endOfDay(),
];
}
/**
* The rules that the incoming request must be matched against.
*/
public function rules(): array
{
return [
'start' => 'required|date|after:1900-01-01|before:2099-12-31',
'end' => 'required|date|after_or_equal:start|before:2099-12-31|after:1900-01-01',
];
}
}

View File

@@ -0,0 +1,59 @@
<?php
/*
* DateRequest.php
* Copyright (c) 2021 james@firefly-iii.org
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace FireflyIII\Api\V1\Requests\Generic;
use Carbon\Carbon;
use FireflyIII\Support\Request\ChecksLogin;
use FireflyIII\Support\Request\ConvertsDataTypes;
use Illuminate\Foundation\Http\FormRequest;
/**
* Request class for end points that require a date parameter.
*
* Class SingleDateRequest
*/
class SingleDateRequest extends FormRequest
{
use ChecksLogin;
use ConvertsDataTypes;
/**
* Get all data from the request.
*/
public function getDate(): Carbon
{
return $this->getCarbonDate('date');
}
/**
* The rules that the incoming request must be matched against.
*/
public function rules(): array
{
return [
'date' => 'required|date|after:1900-01-01|before:2099-12-31',
];
}
}

View File

@@ -32,6 +32,7 @@ use FireflyIII\Support\Export\ExportDataGenerator;
use Illuminate\Contracts\View\Factory;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Response as LaravelResponse;
use Illuminate\Support\Facades\Log;
use Illuminate\View\View;
/**
@@ -71,6 +72,7 @@ class IndexController extends Controller
return redirect(route('export.index'));
}
Log::debug('Will export from the UI.');
/** @var ExportDataGenerator $generator */
$generator = app(ExportDataGenerator::class);
@@ -83,6 +85,7 @@ class IndexController extends Controller
$firstDate->subYear();
$journal = $this->journalRepository->firstNull();
if (null !== $journal) {
Log::debug('First journal is NULL, using today() - 1 year.');
$firstDate = clone $journal->date;
}
$generator->setStart($firstDate);

View File

@@ -27,6 +27,7 @@ namespace FireflyIII\Notifications\Admin;
use FireflyIII\Notifications\Notifiables\OwnerNotifiable;
use FireflyIII\Notifications\ReturnsAvailableChannels;
use FireflyIII\Notifications\ReturnsSettings;
use FireflyIII\Support\Facades\FireflyConfig;
use FireflyIII\Support\Facades\Steam;
use Illuminate\Bus\Queueable;
use Illuminate\Notifications\Messages\MailMessage;
@@ -111,6 +112,12 @@ class UnknownUserLoginAttempt extends Notification
*/
public function via(OwnerNotifiable $notifiable): array
{
return ReturnsAvailableChannels::returnChannels('owner');
$channels = ReturnsAvailableChannels::returnChannels('owner');
$isDemoSite = FireflyConfig::get('is_demo_site', false)->data;
if (true === $isDemoSite) {
return array_diff($channels, ['mail']);
}
return $channels;
}
}

View File

@@ -26,6 +26,7 @@ namespace FireflyIII\Notifications\Security;
use FireflyIII\Notifications\ReturnsAvailableChannels;
use FireflyIII\Notifications\ReturnsSettings;
use FireflyIII\Support\Facades\FireflyConfig;
use FireflyIII\Support\Facades\Steam;
use FireflyIII\User;
use Illuminate\Bus\Queueable;
@@ -103,6 +104,12 @@ class UserFailedLoginAttempt extends Notification
*/
public function via(User $notifiable): array
{
return ReturnsAvailableChannels::returnChannels('user', $notifiable);
$channels = ReturnsAvailableChannels::returnChannels('user', $notifiable);
$isDemoSite = FireflyConfig::get('is_demo_site', false)->data;
if (true === $isDemoSite) {
return array_diff($channels, ['mail']);
}
return $channels;
}
}

View File

@@ -25,6 +25,7 @@ declare(strict_types=1);
namespace FireflyIII\Notifications\Test;
use FireflyIII\Notifications\Notifiables\OwnerNotifiable;
use FireflyIII\Support\Facades\FireflyConfig;
use Illuminate\Bus\Queueable;
use Illuminate\Notifications\Messages\MailMessage;
use Illuminate\Notifications\Notification;
@@ -63,6 +64,11 @@ class OwnerTestNotificationEmail extends Notification
*/
public function via(OwnerNotifiable $notifiable): array
{
$isDemoSite = FireflyConfig::get('is_demo_site', false)->data;
if (true === $isDemoSite) {
return [];
}
return ['mail'];
}
}

View File

@@ -24,6 +24,7 @@ declare(strict_types=1);
namespace FireflyIII\Notifications\Test;
use FireflyIII\Support\Facades\FireflyConfig;
use FireflyIII\User;
use Illuminate\Bus\Queueable;
use Illuminate\Notifications\Messages\MailMessage;
@@ -60,6 +61,11 @@ class UserTestNotificationEmail extends Notification
*/
public function via(User $notifiable): array
{
$isDemoSite = FireflyConfig::get('is_demo_site', false)->data;
if (true === $isDemoSite) {
return [];
}
return ['mail'];
}
}

View File

@@ -26,6 +26,7 @@ namespace FireflyIII\Notifications\User;
use FireflyIII\Notifications\ReturnsAvailableChannels;
use FireflyIII\Notifications\ReturnsSettings;
use FireflyIII\Support\Facades\FireflyConfig;
use FireflyIII\Support\Facades\Steam;
use FireflyIII\User;
use Illuminate\Bus\Queueable;
@@ -101,6 +102,12 @@ class NewAccessToken extends Notification
*/
public function via(User $notifiable): array
{
return ReturnsAvailableChannels::returnChannels('user', $notifiable);
$channels = ReturnsAvailableChannels::returnChannels('user', $notifiable);
$isDemoSite = FireflyConfig::get('is_demo_site', false)->data;
if (true === $isDemoSite) {
return array_diff($channels, ['mail']);
}
return $channels;
}
}

View File

@@ -676,7 +676,7 @@ class AccountRepository implements AccountRepositoryInterface, UserGroupInterfac
'foreign_currencies.code as foreign_currency_code',
'foreign_currencies.name as foreign_currency_name',
'foreign_currencies.symbol as foreign_currency_symbol',
'foreign_currencies.decimal_places as foreign_decimal_places',
'foreign_currencies.decimal_places as foreign_currency_decimal_places',
// fields
'transaction_journals.date', 'transaction_types.type', 'transaction_journals.transaction_currency_id', 'transactions.amount'])

View File

@@ -138,7 +138,7 @@ class AvailableBudgetRepository implements AvailableBudgetRepositoryInterface, U
->where('end_date', $end->format('Y-m-d'))->get()
;
Log::debug(sprintf('Found %d available budgets', $availableBudgets->count()));
Log::debug(sprintf('Found %d available budgets (already converted)', $availableBudgets->count()));
// use native amount if necessary?
$convertToNative = Amount::convertToNative($this->user);
@@ -149,8 +149,9 @@ class AvailableBudgetRepository implements AvailableBudgetRepositoryInterface, U
$currencyId = $convertToNative && $availableBudget->transaction_currency_id !== $default->id ? $default->id : $availableBudget->transaction_currency_id;
$field = $convertToNative && $availableBudget->transaction_currency_id !== $default->id ? 'native_amount' : 'amount';
$return[$currencyId] ??= '0';
$return[$currencyId] = bcadd($return[$currencyId], $availableBudget->{$field});
Log::debug(sprintf('Add #%d %s (%s) for a total of %s', $currencyId, $availableBudget->{$field}, $field, $return[$currencyId]));
$amount = '' === (string) $availableBudget->{$field} ? '0' : (string) $availableBudget->{$field};
$return[$currencyId] = bcadd($return[$currencyId], $amount);
Log::debug(sprintf('Add #%d %s (%s) for a total of %s', $currencyId, $amount, $field, $return[$currencyId]));
}
return $return;

View File

@@ -55,6 +55,7 @@ class OperationsRepository implements OperationsRepositoryInterface, UserGroupIn
$collector->setUser($this->user)->setRange($start, $end)->setTypes([TransactionTypeEnum::WITHDRAWAL->value]);
if (null !== $accounts && $accounts->count() > 0) {
$collector->setAccounts($accounts);
$collector->excludeDestinationAccounts($accounts); // to exclude withdrawals to liabilities.
}
if (null !== $categories && $categories->count() > 0) {
$collector->setCategories($categories);
@@ -132,6 +133,7 @@ class OperationsRepository implements OperationsRepositoryInterface, UserGroupIn
$collector->setUser($this->user)->setRange($start, $end)->setTypes([TransactionTypeEnum::DEPOSIT->value]);
if (null !== $accounts && $accounts->count() > 0) {
$collector->setAccounts($accounts);
$collector->excludeSourceAccounts($accounts); // to prevent income from liabilities.
}
if (null !== $categories && $categories->count() > 0) {
$collector->setCategories($categories);

View File

@@ -46,7 +46,7 @@ class ChartData
if (array_key_exists('native_currency_id', $data)) {
$data['native_currency_id'] = (string) $data['native_currency_id'];
}
$required = ['start', 'date', 'end', 'entries', 'native_entries'];
$required = ['start', 'date', 'end', 'entries'];
foreach ($required as $field) {
if (!array_key_exists($field, $data)) {
throw new FireflyException(sprintf('Data-set is missing the "%s"-variable.', $field));

View File

@@ -45,8 +45,8 @@ class UpdateCheckCronjob extends AbstractCronjob
Log::debug('Update check is not enabled.');
// get stuff from job:
$this->jobFired = false;
$this->jobErrored = true;
$this->jobSucceeded = false;
$this->jobErrored = false;
$this->jobSucceeded = true;
$this->message = 'The update check is not enabled.';
return;
@@ -61,8 +61,8 @@ class UpdateCheckCronjob extends AbstractCronjob
if ($diff < 604800 && false === $this->force) {
// get stuff from job:
$this->jobFired = false;
$this->jobErrored = true;
$this->jobSucceeded = false;
$this->jobErrored = false;
$this->jobSucceeded = true;
$this->message = sprintf('Checked for updates less than a week ago (on %s).', date('Y-m-d H:i:s', $lastCheckTime->data));
return;

View File

@@ -731,6 +731,7 @@ class ExportDataGenerator
*/
private function exportTransactions(): string
{
Log::debug('Will now export transactions.');
// TODO better place for keys?
$header = ['user_id', 'group_id', 'journal_id', 'created_at', 'updated_at', 'group_title', 'type', 'currency_code', 'amount', 'foreign_currency_code', 'foreign_amount', 'native_currency_code', 'native_amount', 'native_foreign_amount', 'description', 'date', 'source_name', 'source_iban', 'source_type', 'destination_name', 'destination_iban', 'destination_type', 'reconciled', 'category', 'budget', 'bill', 'tags', 'notes'];

View File

@@ -49,7 +49,7 @@ class TransactionSummarizer
$this->convertToNative = Amount::convertToNative($user);
}
public function groupByCurrencyId(array $journals, string $method = 'negative'): array
public function groupByCurrencyId(array $journals, string $method = 'negative', bool $includeForeign = true): array
{
Log::debug(sprintf('Now in groupByCurrencyId(array, "%s")', $method));
$array = [];
@@ -94,10 +94,10 @@ class TransactionSummarizer
}
}
if (!$this->convertToNative) {
Log::debug(sprintf('Journal #%d also includes foreign amount (foreign is %s)', $journal['transaction_journal_id'], $journal['foreign_currency_code']));
// use foreign amount?
$foreignCurrencyId = (int) $journal['foreign_currency_id'];
if (0 !== $foreignCurrencyId) {
Log::debug(sprintf('Journal #%d also includes foreign amount (foreign is "%s")', $journal['transaction_journal_id'], $journal['foreign_currency_code']));
$foreignCurrencyName = $journal['foreign_currency_name'];
$foreignCurrencySymbol = $journal['foreign_currency_symbol'];
$foreignCurrencyCode = $journal['foreign_currency_code'];
@@ -124,7 +124,7 @@ class TransactionSummarizer
}
// then process foreign amount, if it exists.
if (0 !== $foreignCurrencyId) {
if (0 !== $foreignCurrencyId && true === $includeForeign) {
$amount = (string) ($journal['foreign_amount'] ?? '0');
$array[$foreignCurrencyId] ??= [
'sum' => '0',

View File

@@ -84,7 +84,7 @@
"bacon/bacon-qr-code": "^2",
"diglactic/laravel-breadcrumbs": "^10",
"gdbots/query-parser": "^3.0",
"guzzlehttp/guzzle": "^7.8",
"guzzlehttp/guzzle": "^7.9",
"jc5/google2fa-laravel": "^2.0",
"jc5/recovery": "^2",
"laravel-notification-channels/pushover": "^4.0",

349
composer.lock generated
View File

@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "f5bc893e4af6924e2fbfe02989dbe719",
"content-hash": "3c350a535ca785e45a43f67c3a41154b",
"packages": [
{
"name": "bacon/bacon-qr-code",
@@ -1245,16 +1245,16 @@
},
{
"name": "guzzlehttp/guzzle",
"version": "7.9.2",
"version": "7.9.3",
"source": {
"type": "git",
"url": "https://github.com/guzzle/guzzle.git",
"reference": "d281ed313b989f213357e3be1a179f02196ac99b"
"reference": "7b2f29fe81dc4da0ca0ea7d42107a0845946ea77"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/guzzle/guzzle/zipball/d281ed313b989f213357e3be1a179f02196ac99b",
"reference": "d281ed313b989f213357e3be1a179f02196ac99b",
"url": "https://api.github.com/repos/guzzle/guzzle/zipball/7b2f29fe81dc4da0ca0ea7d42107a0845946ea77",
"reference": "7b2f29fe81dc4da0ca0ea7d42107a0845946ea77",
"shasum": ""
},
"require": {
@@ -1351,7 +1351,7 @@
],
"support": {
"issues": "https://github.com/guzzle/guzzle/issues",
"source": "https://github.com/guzzle/guzzle/tree/7.9.2"
"source": "https://github.com/guzzle/guzzle/tree/7.9.3"
},
"funding": [
{
@@ -1367,20 +1367,20 @@
"type": "tidelift"
}
],
"time": "2024-07-24T11:22:20+00:00"
"time": "2025-03-27T13:37:11+00:00"
},
{
"name": "guzzlehttp/promises",
"version": "2.0.4",
"version": "2.2.0",
"source": {
"type": "git",
"url": "https://github.com/guzzle/promises.git",
"reference": "f9c436286ab2892c7db7be8c8da4ef61ccf7b455"
"reference": "7c69f28996b0a6920945dd20b3857e499d9ca96c"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/guzzle/promises/zipball/f9c436286ab2892c7db7be8c8da4ef61ccf7b455",
"reference": "f9c436286ab2892c7db7be8c8da4ef61ccf7b455",
"url": "https://api.github.com/repos/guzzle/promises/zipball/7c69f28996b0a6920945dd20b3857e499d9ca96c",
"reference": "7c69f28996b0a6920945dd20b3857e499d9ca96c",
"shasum": ""
},
"require": {
@@ -1434,7 +1434,7 @@
],
"support": {
"issues": "https://github.com/guzzle/promises/issues",
"source": "https://github.com/guzzle/promises/tree/2.0.4"
"source": "https://github.com/guzzle/promises/tree/2.2.0"
},
"funding": [
{
@@ -1450,20 +1450,20 @@
"type": "tidelift"
}
],
"time": "2024-10-17T10:06:22+00:00"
"time": "2025-03-27T13:27:01+00:00"
},
{
"name": "guzzlehttp/psr7",
"version": "2.7.0",
"version": "2.7.1",
"source": {
"type": "git",
"url": "https://github.com/guzzle/psr7.git",
"reference": "a70f5c95fb43bc83f07c9c948baa0dc1829bf201"
"reference": "c2270caaabe631b3b44c85f99e5a04bbb8060d16"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/guzzle/psr7/zipball/a70f5c95fb43bc83f07c9c948baa0dc1829bf201",
"reference": "a70f5c95fb43bc83f07c9c948baa0dc1829bf201",
"url": "https://api.github.com/repos/guzzle/psr7/zipball/c2270caaabe631b3b44c85f99e5a04bbb8060d16",
"reference": "c2270caaabe631b3b44c85f99e5a04bbb8060d16",
"shasum": ""
},
"require": {
@@ -1550,7 +1550,7 @@
],
"support": {
"issues": "https://github.com/guzzle/psr7/issues",
"source": "https://github.com/guzzle/psr7/tree/2.7.0"
"source": "https://github.com/guzzle/psr7/tree/2.7.1"
},
"funding": [
{
@@ -1566,7 +1566,7 @@
"type": "tidelift"
}
],
"time": "2024-07-18T11:15:46+00:00"
"time": "2025-03-27T12:30:47+00:00"
},
{
"name": "guzzlehttp/uri-template",
@@ -2292,16 +2292,16 @@
},
{
"name": "laravel/serializable-closure",
"version": "v2.0.3",
"version": "v2.0.4",
"source": {
"type": "git",
"url": "https://github.com/laravel/serializable-closure.git",
"reference": "f379c13663245f7aa4512a7869f62eb14095f23f"
"reference": "b352cf0534aa1ae6b4d825d1e762e35d43f8a841"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/laravel/serializable-closure/zipball/f379c13663245f7aa4512a7869f62eb14095f23f",
"reference": "f379c13663245f7aa4512a7869f62eb14095f23f",
"url": "https://api.github.com/repos/laravel/serializable-closure/zipball/b352cf0534aa1ae6b4d825d1e762e35d43f8a841",
"reference": "b352cf0534aa1ae6b4d825d1e762e35d43f8a841",
"shasum": ""
},
"require": {
@@ -2349,7 +2349,7 @@
"issues": "https://github.com/laravel/serializable-closure/issues",
"source": "https://github.com/laravel/serializable-closure"
},
"time": "2025-02-11T15:03:05+00:00"
"time": "2025-03-19T13:51:03+00:00"
},
{
"name": "laravel/slack-notification-channel",
@@ -2807,16 +2807,16 @@
},
{
"name": "league/csv",
"version": "9.22.0",
"version": "9.23.0",
"source": {
"type": "git",
"url": "https://github.com/thephpleague/csv.git",
"reference": "afc109aa11f3086b8be8dfffa04ac31480b36b76"
"reference": "774008ad8a634448e4f8e288905e070e8b317ff3"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/thephpleague/csv/zipball/afc109aa11f3086b8be8dfffa04ac31480b36b76",
"reference": "afc109aa11f3086b8be8dfffa04ac31480b36b76",
"url": "https://api.github.com/repos/thephpleague/csv/zipball/774008ad8a634448e4f8e288905e070e8b317ff3",
"reference": "774008ad8a634448e4f8e288905e070e8b317ff3",
"shasum": ""
},
"require": {
@@ -2894,7 +2894,7 @@
"type": "github"
}
],
"time": "2025-02-28T10:00:39+00:00"
"time": "2025-03-28T06:52:04+00:00"
},
{
"name": "league/event",
@@ -3472,22 +3472,22 @@
},
{
"name": "mailersend/laravel-driver",
"version": "v2.8.0",
"version": "v2.9.0",
"source": {
"type": "git",
"url": "https://github.com/mailersend/mailersend-laravel-driver.git",
"reference": "b28fde8f6ec0cd5406100abf05f7899935e71652"
"reference": "a34e2db5d63d2421b055d8271066d204479a8b6a"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/mailersend/mailersend-laravel-driver/zipball/b28fde8f6ec0cd5406100abf05f7899935e71652",
"reference": "b28fde8f6ec0cd5406100abf05f7899935e71652",
"url": "https://api.github.com/repos/mailersend/mailersend-laravel-driver/zipball/a34e2db5d63d2421b055d8271066d204479a8b6a",
"reference": "a34e2db5d63d2421b055d8271066d204479a8b6a",
"shasum": ""
},
"require": {
"ext-json": "*",
"illuminate/support": "^9.0 || ^10.0 || ^11.0 || ^12.0",
"mailersend/mailersend": "^0.8.0 || ^0.23.0 || ^0.24.0 || ^0.30.0",
"mailersend/mailersend": "^0.31.0",
"nyholm/psr7": "^1.5",
"php": ">=8.0",
"php-http/guzzle7-adapter": "^1.0",
@@ -3535,22 +3535,22 @@
],
"support": {
"issues": "https://github.com/mailersend/mailersend-laravel-driver/issues",
"source": "https://github.com/mailersend/mailersend-laravel-driver/tree/v2.8.0"
"source": "https://github.com/mailersend/mailersend-laravel-driver/tree/v2.9.0"
},
"time": "2025-03-06T16:55:40+00:00"
"time": "2025-04-04T10:38:10+00:00"
},
{
"name": "mailersend/mailersend",
"version": "v0.30.0",
"version": "v0.31.0",
"source": {
"type": "git",
"url": "https://github.com/mailersend/mailersend-php.git",
"reference": "7ac40e50fa914a506c58d13c82dbf0d3bf0a6487"
"reference": "513ff83ee768526055ad52987cde401ea7218c67"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/mailersend/mailersend-php/zipball/7ac40e50fa914a506c58d13c82dbf0d3bf0a6487",
"reference": "7ac40e50fa914a506c58d13c82dbf0d3bf0a6487",
"url": "https://api.github.com/repos/mailersend/mailersend-php/zipball/513ff83ee768526055ad52987cde401ea7218c67",
"reference": "513ff83ee768526055ad52987cde401ea7218c67",
"shasum": ""
},
"require": {
@@ -3602,22 +3602,22 @@
],
"support": {
"issues": "https://github.com/mailersend/mailersend-php/issues",
"source": "https://github.com/mailersend/mailersend-php/tree/v0.30.0"
"source": "https://github.com/mailersend/mailersend-php/tree/v0.31.0"
},
"time": "2025-03-06T15:45:57+00:00"
"time": "2025-04-03T12:16:11+00:00"
},
{
"name": "monolog/monolog",
"version": "3.8.1",
"version": "3.9.0",
"source": {
"type": "git",
"url": "https://github.com/Seldaek/monolog.git",
"reference": "aef6ee73a77a66e404dd6540934a9ef1b3c855b4"
"reference": "10d85740180ecba7896c87e06a166e0c95a0e3b6"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/Seldaek/monolog/zipball/aef6ee73a77a66e404dd6540934a9ef1b3c855b4",
"reference": "aef6ee73a77a66e404dd6540934a9ef1b3c855b4",
"url": "https://api.github.com/repos/Seldaek/monolog/zipball/10d85740180ecba7896c87e06a166e0c95a0e3b6",
"reference": "10d85740180ecba7896c87e06a166e0c95a0e3b6",
"shasum": ""
},
"require": {
@@ -3695,7 +3695,7 @@
],
"support": {
"issues": "https://github.com/Seldaek/monolog/issues",
"source": "https://github.com/Seldaek/monolog/tree/3.8.1"
"source": "https://github.com/Seldaek/monolog/tree/3.9.0"
},
"funding": [
{
@@ -3707,20 +3707,20 @@
"type": "tidelift"
}
],
"time": "2024-12-05T17:15:07+00:00"
"time": "2025-03-24T10:02:05+00:00"
},
{
"name": "nesbot/carbon",
"version": "3.8.6",
"version": "3.9.0",
"source": {
"type": "git",
"url": "https://github.com/CarbonPHP/carbon.git",
"reference": "ff2f20cf83bd4d503720632ce8a426dc747bf7fd"
"reference": "6d16a8a015166fe54e22c042e0805c5363aef50d"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/CarbonPHP/carbon/zipball/ff2f20cf83bd4d503720632ce8a426dc747bf7fd",
"reference": "ff2f20cf83bd4d503720632ce8a426dc747bf7fd",
"url": "https://api.github.com/repos/CarbonPHP/carbon/zipball/6d16a8a015166fe54e22c042e0805c5363aef50d",
"reference": "6d16a8a015166fe54e22c042e0805c5363aef50d",
"shasum": ""
},
"require": {
@@ -3813,7 +3813,7 @@
"type": "tidelift"
}
],
"time": "2025-02-20T17:33:38+00:00"
"time": "2025-03-27T12:57:33+00:00"
},
{
"name": "nette/schema",
@@ -3879,16 +3879,16 @@
},
{
"name": "nette/utils",
"version": "v4.0.5",
"version": "v4.0.6",
"source": {
"type": "git",
"url": "https://github.com/nette/utils.git",
"reference": "736c567e257dbe0fcf6ce81b4d6dbe05c6899f96"
"reference": "ce708655043c7050eb050df361c5e313cf708309"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/nette/utils/zipball/736c567e257dbe0fcf6ce81b4d6dbe05c6899f96",
"reference": "736c567e257dbe0fcf6ce81b4d6dbe05c6899f96",
"url": "https://api.github.com/repos/nette/utils/zipball/ce708655043c7050eb050df361c5e313cf708309",
"reference": "ce708655043c7050eb050df361c5e313cf708309",
"shasum": ""
},
"require": {
@@ -3959,44 +3959,45 @@
],
"support": {
"issues": "https://github.com/nette/utils/issues",
"source": "https://github.com/nette/utils/tree/v4.0.5"
"source": "https://github.com/nette/utils/tree/v4.0.6"
},
"time": "2024-08-07T15:39:19+00:00"
"time": "2025-03-30T21:06:30+00:00"
},
{
"name": "nunomaduro/collision",
"version": "v8.7.0",
"version": "v8.8.0",
"source": {
"type": "git",
"url": "https://github.com/nunomaduro/collision.git",
"reference": "586cb8181a257a2152b6a855ca8d9598878a1a26"
"reference": "4cf9f3b47afff38b139fb79ce54fc71799022ce8"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/nunomaduro/collision/zipball/586cb8181a257a2152b6a855ca8d9598878a1a26",
"reference": "586cb8181a257a2152b6a855ca8d9598878a1a26",
"url": "https://api.github.com/repos/nunomaduro/collision/zipball/4cf9f3b47afff38b139fb79ce54fc71799022ce8",
"reference": "4cf9f3b47afff38b139fb79ce54fc71799022ce8",
"shasum": ""
},
"require": {
"filp/whoops": "^2.17.0",
"filp/whoops": "^2.18.0",
"nunomaduro/termwind": "^2.3.0",
"php": "^8.2.0",
"symfony/console": "^7.2.1"
"symfony/console": "^7.2.5"
},
"conflict": {
"laravel/framework": "<11.39.1 || >=13.0.0",
"phpunit/phpunit": "<11.5.3 || >=12.0.0"
"laravel/framework": "<11.44.2 || >=13.0.0",
"phpunit/phpunit": "<11.5.15 || >=13.0.0"
},
"require-dev": {
"larastan/larastan": "^2.10.0",
"laravel/framework": "^11.44.2",
"brianium/paratest": "^7.8.3",
"larastan/larastan": "^3.2",
"laravel/framework": "^11.44.2 || ^12.6",
"laravel/pint": "^1.21.2",
"laravel/sail": "^1.41.0",
"laravel/sanctum": "^4.0.8",
"laravel/tinker": "^2.10.1",
"orchestra/testbench-core": "^9.12.0",
"pestphp/pest": "^3.7.4",
"sebastian/environment": "^6.1.0 || ^7.2.0"
"orchestra/testbench-core": "^9.12.0 || ^10.1",
"pestphp/pest": "^3.8.0",
"sebastian/environment": "^7.2.0 || ^8.0"
},
"type": "library",
"extra": {
@@ -4059,7 +4060,7 @@
"type": "patreon"
}
],
"time": "2025-03-14T22:37:40+00:00"
"time": "2025-04-03T14:33:09+00:00"
},
{
"name": "nunomaduro/termwind",
@@ -6360,16 +6361,16 @@
},
{
"name": "spatie/laravel-package-tools",
"version": "1.91.1",
"version": "1.92.0",
"source": {
"type": "git",
"url": "https://github.com/spatie/laravel-package-tools.git",
"reference": "b0b509b9b01d77caa431ce9af3a706bc678e09c9"
"reference": "dd46cd0ed74015db28822d88ad2e667f4496a6f6"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/spatie/laravel-package-tools/zipball/b0b509b9b01d77caa431ce9af3a706bc678e09c9",
"reference": "b0b509b9b01d77caa431ce9af3a706bc678e09c9",
"url": "https://api.github.com/repos/spatie/laravel-package-tools/zipball/dd46cd0ed74015db28822d88ad2e667f4496a6f6",
"reference": "dd46cd0ed74015db28822d88ad2e667f4496a6f6",
"shasum": ""
},
"require": {
@@ -6408,7 +6409,7 @@
],
"support": {
"issues": "https://github.com/spatie/laravel-package-tools/issues",
"source": "https://github.com/spatie/laravel-package-tools/tree/1.91.1"
"source": "https://github.com/spatie/laravel-package-tools/tree/1.92.0"
},
"funding": [
{
@@ -6416,7 +6417,7 @@
"type": "github"
}
],
"time": "2025-03-21T09:50:49+00:00"
"time": "2025-03-27T08:34:10+00:00"
},
{
"name": "spatie/period",
@@ -6474,16 +6475,16 @@
},
{
"name": "symfony/cache",
"version": "v7.2.4",
"version": "v7.2.5",
"source": {
"type": "git",
"url": "https://github.com/symfony/cache.git",
"reference": "d33cd9e14326e14a4145c21e600602eaf17cc9e7"
"reference": "9131e3018872d2ebb6fe8a9a4d6631273513d42c"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/cache/zipball/d33cd9e14326e14a4145c21e600602eaf17cc9e7",
"reference": "d33cd9e14326e14a4145c21e600602eaf17cc9e7",
"url": "https://api.github.com/repos/symfony/cache/zipball/9131e3018872d2ebb6fe8a9a4d6631273513d42c",
"reference": "9131e3018872d2ebb6fe8a9a4d6631273513d42c",
"shasum": ""
},
"require": {
@@ -6552,7 +6553,7 @@
"psr6"
],
"support": {
"source": "https://github.com/symfony/cache/tree/v7.2.4"
"source": "https://github.com/symfony/cache/tree/v7.2.5"
},
"funding": [
{
@@ -6568,7 +6569,7 @@
"type": "tidelift"
}
],
"time": "2025-02-26T09:57:54+00:00"
"time": "2025-03-25T15:54:33+00:00"
},
{
"name": "symfony/cache-contracts",
@@ -6722,16 +6723,16 @@
},
{
"name": "symfony/console",
"version": "v7.2.1",
"version": "v7.2.5",
"source": {
"type": "git",
"url": "https://github.com/symfony/console.git",
"reference": "fefcc18c0f5d0efe3ab3152f15857298868dc2c3"
"reference": "e51498ea18570c062e7df29d05a7003585b19b88"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/console/zipball/fefcc18c0f5d0efe3ab3152f15857298868dc2c3",
"reference": "fefcc18c0f5d0efe3ab3152f15857298868dc2c3",
"url": "https://api.github.com/repos/symfony/console/zipball/e51498ea18570c062e7df29d05a7003585b19b88",
"reference": "e51498ea18570c062e7df29d05a7003585b19b88",
"shasum": ""
},
"require": {
@@ -6795,7 +6796,7 @@
"terminal"
],
"support": {
"source": "https://github.com/symfony/console/tree/v7.2.1"
"source": "https://github.com/symfony/console/tree/v7.2.5"
},
"funding": [
{
@@ -6811,7 +6812,7 @@
"type": "tidelift"
}
],
"time": "2024-12-11T03:49:26+00:00"
"time": "2025-03-12T08:11:12+00:00"
},
{
"name": "symfony/css-selector",
@@ -6947,16 +6948,16 @@
},
{
"name": "symfony/error-handler",
"version": "v7.2.4",
"version": "v7.2.5",
"source": {
"type": "git",
"url": "https://github.com/symfony/error-handler.git",
"reference": "aabf79938aa795350c07ce6464dd1985607d95d5"
"reference": "102be5e6a8e4f4f3eb3149bcbfa33a80d1ee374b"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/error-handler/zipball/aabf79938aa795350c07ce6464dd1985607d95d5",
"reference": "aabf79938aa795350c07ce6464dd1985607d95d5",
"url": "https://api.github.com/repos/symfony/error-handler/zipball/102be5e6a8e4f4f3eb3149bcbfa33a80d1ee374b",
"reference": "102be5e6a8e4f4f3eb3149bcbfa33a80d1ee374b",
"shasum": ""
},
"require": {
@@ -7002,7 +7003,7 @@
"description": "Provides tools to manage errors and ease debugging PHP code",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/error-handler/tree/v7.2.4"
"source": "https://github.com/symfony/error-handler/tree/v7.2.5"
},
"funding": [
{
@@ -7018,7 +7019,7 @@
"type": "tidelift"
}
],
"time": "2025-02-02T20:27:07+00:00"
"time": "2025-03-03T07:12:39+00:00"
},
{
"name": "symfony/event-dispatcher",
@@ -7479,16 +7480,16 @@
},
{
"name": "symfony/http-foundation",
"version": "v7.2.3",
"version": "v7.2.5",
"source": {
"type": "git",
"url": "https://github.com/symfony/http-foundation.git",
"reference": "ee1b504b8926198be89d05e5b6fc4c3810c090f0"
"reference": "371272aeb6286f8135e028ca535f8e4d6f114126"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/http-foundation/zipball/ee1b504b8926198be89d05e5b6fc4c3810c090f0",
"reference": "ee1b504b8926198be89d05e5b6fc4c3810c090f0",
"url": "https://api.github.com/repos/symfony/http-foundation/zipball/371272aeb6286f8135e028ca535f8e4d6f114126",
"reference": "371272aeb6286f8135e028ca535f8e4d6f114126",
"shasum": ""
},
"require": {
@@ -7537,7 +7538,7 @@
"description": "Defines an object-oriented layer for the HTTP specification",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/http-foundation/tree/v7.2.3"
"source": "https://github.com/symfony/http-foundation/tree/v7.2.5"
},
"funding": [
{
@@ -7553,20 +7554,20 @@
"type": "tidelift"
}
],
"time": "2025-01-17T10:56:55+00:00"
"time": "2025-03-25T15:54:33+00:00"
},
{
"name": "symfony/http-kernel",
"version": "v7.2.4",
"version": "v7.2.5",
"source": {
"type": "git",
"url": "https://github.com/symfony/http-kernel.git",
"reference": "9f1103734c5789798fefb90e91de4586039003ed"
"reference": "b1fe91bc1fa454a806d3f98db4ba826eb9941a54"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/http-kernel/zipball/9f1103734c5789798fefb90e91de4586039003ed",
"reference": "9f1103734c5789798fefb90e91de4586039003ed",
"url": "https://api.github.com/repos/symfony/http-kernel/zipball/b1fe91bc1fa454a806d3f98db4ba826eb9941a54",
"reference": "b1fe91bc1fa454a806d3f98db4ba826eb9941a54",
"shasum": ""
},
"require": {
@@ -7651,7 +7652,7 @@
"description": "Provides a structured process for converting a Request into a Response",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/http-kernel/tree/v7.2.4"
"source": "https://github.com/symfony/http-kernel/tree/v7.2.5"
},
"funding": [
{
@@ -7667,7 +7668,7 @@
"type": "tidelift"
}
],
"time": "2025-02-26T11:01:22+00:00"
"time": "2025-03-28T13:32:50+00:00"
},
{
"name": "symfony/mailer",
@@ -8607,16 +8608,16 @@
},
{
"name": "symfony/process",
"version": "v7.2.4",
"version": "v7.2.5",
"source": {
"type": "git",
"url": "https://github.com/symfony/process.git",
"reference": "d8f411ff3c7ddc4ae9166fb388d1190a2df5b5cf"
"reference": "87b7c93e57df9d8e39a093d32587702380ff045d"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/process/zipball/d8f411ff3c7ddc4ae9166fb388d1190a2df5b5cf",
"reference": "d8f411ff3c7ddc4ae9166fb388d1190a2df5b5cf",
"url": "https://api.github.com/repos/symfony/process/zipball/87b7c93e57df9d8e39a093d32587702380ff045d",
"reference": "87b7c93e57df9d8e39a093d32587702380ff045d",
"shasum": ""
},
"require": {
@@ -8648,7 +8649,7 @@
"description": "Executes commands in sub-processes",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/process/tree/v7.2.4"
"source": "https://github.com/symfony/process/tree/v7.2.5"
},
"funding": [
{
@@ -8664,7 +8665,7 @@
"type": "tidelift"
}
],
"time": "2025-02-05T08:33:46+00:00"
"time": "2025-03-13T12:21:46+00:00"
},
{
"name": "symfony/psr-http-message-bridge",
@@ -9332,16 +9333,16 @@
},
{
"name": "symfony/var-exporter",
"version": "v7.2.4",
"version": "v7.2.5",
"source": {
"type": "git",
"url": "https://github.com/symfony/var-exporter.git",
"reference": "4ede73aa7a73d81506002d2caadbbdad1ef5b69a"
"reference": "c37b301818bd7288715d40de634f05781b686ace"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/var-exporter/zipball/4ede73aa7a73d81506002d2caadbbdad1ef5b69a",
"reference": "4ede73aa7a73d81506002d2caadbbdad1ef5b69a",
"url": "https://api.github.com/repos/symfony/var-exporter/zipball/c37b301818bd7288715d40de634f05781b686ace",
"reference": "c37b301818bd7288715d40de634f05781b686ace",
"shasum": ""
},
"require": {
@@ -9388,7 +9389,7 @@
"serialize"
],
"support": {
"source": "https://github.com/symfony/var-exporter/tree/v7.2.4"
"source": "https://github.com/symfony/var-exporter/tree/v7.2.5"
},
"funding": [
{
@@ -9404,7 +9405,7 @@
"type": "tidelift"
}
],
"time": "2025-02-13T10:27:23+00:00"
"time": "2025-03-13T12:21:46+00:00"
},
{
"name": "thecodingmachine/safe",
@@ -9681,16 +9682,16 @@
},
{
"name": "verifiedjoseph/ntfy-php-library",
"version": "v4.7.0",
"version": "v4.7.1",
"source": {
"type": "git",
"url": "https://github.com/VerifiedJoseph/ntfy-php-library.git",
"reference": "c84d4dd7074d4cd89bfc1c10b1aa7f2568105412"
"reference": "b191721dfed447a94f220a89dd372861d4c41115"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/VerifiedJoseph/ntfy-php-library/zipball/c84d4dd7074d4cd89bfc1c10b1aa7f2568105412",
"reference": "c84d4dd7074d4cd89bfc1c10b1aa7f2568105412",
"url": "https://api.github.com/repos/VerifiedJoseph/ntfy-php-library/zipball/b191721dfed447a94f220a89dd372861d4c41115",
"reference": "b191721dfed447a94f220a89dd372861d4c41115",
"shasum": ""
},
"require": {
@@ -9729,9 +9730,9 @@
],
"support": {
"issues": "https://github.com/VerifiedJoseph/ntfy-php-library/issues",
"source": "https://github.com/VerifiedJoseph/ntfy-php-library/tree/v4.7.0"
"source": "https://github.com/VerifiedJoseph/ntfy-php-library/tree/v4.7.1"
},
"time": "2024-12-10T10:48:38+00:00"
"time": "2025-04-01T14:02:04+00:00"
},
{
"name": "vlucas/phpdotenv",
@@ -10320,16 +10321,16 @@
},
{
"name": "composer/class-map-generator",
"version": "1.6.0",
"version": "1.6.1",
"source": {
"type": "git",
"url": "https://github.com/composer/class-map-generator.git",
"reference": "ffe442c5974c44a9343e37a0abcb1cc37319f5b9"
"reference": "134b705ddb0025d397d8318a75825fe3c9d1da34"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/composer/class-map-generator/zipball/ffe442c5974c44a9343e37a0abcb1cc37319f5b9",
"reference": "ffe442c5974c44a9343e37a0abcb1cc37319f5b9",
"url": "https://api.github.com/repos/composer/class-map-generator/zipball/134b705ddb0025d397d8318a75825fe3c9d1da34",
"reference": "134b705ddb0025d397d8318a75825fe3c9d1da34",
"shasum": ""
},
"require": {
@@ -10373,7 +10374,7 @@
],
"support": {
"issues": "https://github.com/composer/class-map-generator/issues",
"source": "https://github.com/composer/class-map-generator/tree/1.6.0"
"source": "https://github.com/composer/class-map-generator/tree/1.6.1"
},
"funding": [
{
@@ -10389,7 +10390,7 @@
"type": "tidelift"
}
],
"time": "2025-02-05T10:05:34+00:00"
"time": "2025-03-24T13:50:44+00:00"
},
{
"name": "composer/pcre",
@@ -10586,16 +10587,16 @@
},
{
"name": "iamcal/sql-parser",
"version": "v0.5",
"version": "v0.6",
"source": {
"type": "git",
"url": "https://github.com/iamcal/SQLParser.git",
"reference": "644fd994de3b54e5d833aecf406150aa3b66ca88"
"reference": "947083e2dca211a6f12fb1beb67a01e387de9b62"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/iamcal/SQLParser/zipball/644fd994de3b54e5d833aecf406150aa3b66ca88",
"reference": "644fd994de3b54e5d833aecf406150aa3b66ca88",
"url": "https://api.github.com/repos/iamcal/SQLParser/zipball/947083e2dca211a6f12fb1beb67a01e387de9b62",
"reference": "947083e2dca211a6f12fb1beb67a01e387de9b62",
"shasum": ""
},
"require-dev": {
@@ -10621,46 +10622,46 @@
"description": "MySQL schema parser",
"support": {
"issues": "https://github.com/iamcal/SQLParser/issues",
"source": "https://github.com/iamcal/SQLParser/tree/v0.5"
"source": "https://github.com/iamcal/SQLParser/tree/v0.6"
},
"time": "2024-03-22T22:46:32+00:00"
"time": "2025-03-17T16:59:46+00:00"
},
{
"name": "larastan/larastan",
"version": "v3.2.0",
"version": "v3.3.1",
"source": {
"type": "git",
"url": "https://github.com/larastan/larastan.git",
"reference": "d84d5a3b6536a586899ad6855a3e098473703690"
"reference": "58bee8be51daf12d78ed0a909be3b205607d2f27"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/larastan/larastan/zipball/d84d5a3b6536a586899ad6855a3e098473703690",
"reference": "d84d5a3b6536a586899ad6855a3e098473703690",
"url": "https://api.github.com/repos/larastan/larastan/zipball/58bee8be51daf12d78ed0a909be3b205607d2f27",
"reference": "58bee8be51daf12d78ed0a909be3b205607d2f27",
"shasum": ""
},
"require": {
"ext-json": "*",
"iamcal/sql-parser": "^0.5.0",
"illuminate/console": "^11.41.3 || ^12.0",
"illuminate/container": "^11.41.3 || ^12.0",
"illuminate/contracts": "^11.41.3 || ^12.0",
"illuminate/database": "^11.41.3 || ^12.0",
"illuminate/http": "^11.41.3 || ^12.0",
"illuminate/pipeline": "^11.41.3 || ^12.0",
"illuminate/support": "^11.41.3 || ^12.0",
"iamcal/sql-parser": "^0.6.0",
"illuminate/console": "^11.44.2 || ^12.4.1",
"illuminate/container": "^11.44.2 || ^12.4.1",
"illuminate/contracts": "^11.44.2 || ^12.4.1",
"illuminate/database": "^11.44.2 || ^12.4.1",
"illuminate/http": "^11.44.2 || ^12.4.1",
"illuminate/pipeline": "^11.44.2 || ^12.4.1",
"illuminate/support": "^11.44.2 || ^12.4.1",
"php": "^8.2",
"phpstan/phpstan": "^2.1.3"
"phpstan/phpstan": "^2.1.11"
},
"require-dev": {
"doctrine/coding-standard": "^12.0",
"laravel/framework": "^11.41.3 || ^12.0",
"mockery/mockery": "^1.6",
"nikic/php-parser": "^5.3",
"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.35 || ^11.3.6"
"laravel/framework": "^11.44.2 || ^12.7.2",
"mockery/mockery": "^1.6.12",
"nikic/php-parser": "^5.4",
"orchestra/canvas": "^v9.2.2 || ^10.0.1",
"orchestra/testbench-core": "^9.12.0 || ^10.1",
"phpstan/phpstan-deprecation-rules": "^2.0.1",
"phpunit/phpunit": "^10.5.35 || ^11.5.15"
},
"suggest": {
"orchestra/testbench": "Using Larastan for analysing a package needs Testbench"
@@ -10708,15 +10709,19 @@
],
"support": {
"issues": "https://github.com/larastan/larastan/issues",
"source": "https://github.com/larastan/larastan/tree/v3.2.0"
"source": "https://github.com/larastan/larastan/tree/v3.3.1"
},
"funding": [
{
"url": "https://github.com/canvural",
"type": "github"
},
{
"url": "https://github.com/nunomaduro",
"type": "github"
}
],
"time": "2025-03-14T21:54:26+00:00"
"time": "2025-04-03T20:08:04+00:00"
},
{
"name": "laravel-json-api/testing",
@@ -11222,16 +11227,16 @@
},
{
"name": "phpstan/phpstan",
"version": "2.1.8",
"version": "2.1.11",
"source": {
"type": "git",
"url": "https://github.com/phpstan/phpstan.git",
"reference": "f9adff3b87c03b12cc7e46a30a524648e497758f"
"reference": "8ca5f79a8f63c49b2359065832a654e1ec70ac30"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/f9adff3b87c03b12cc7e46a30a524648e497758f",
"reference": "f9adff3b87c03b12cc7e46a30a524648e497758f",
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/8ca5f79a8f63c49b2359065832a654e1ec70ac30",
"reference": "8ca5f79a8f63c49b2359065832a654e1ec70ac30",
"shasum": ""
},
"require": {
@@ -11276,7 +11281,7 @@
"type": "github"
}
],
"time": "2025-03-09T09:30:48+00:00"
"time": "2025-03-24T13:45:00+00:00"
},
{
"name": "phpstan/phpstan-deprecation-rules",
@@ -11698,16 +11703,16 @@
},
{
"name": "phpunit/phpunit",
"version": "11.5.14",
"version": "11.5.15",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/phpunit.git",
"reference": "9d6046153c2893b521784069e6b5249ce7d2acae"
"reference": "4b6a4ee654e5e0c5e1f17e2f83c0f4c91dee1f9c"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/9d6046153c2893b521784069e6b5249ce7d2acae",
"reference": "9d6046153c2893b521784069e6b5249ce7d2acae",
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/4b6a4ee654e5e0c5e1f17e2f83c0f4c91dee1f9c",
"reference": "4b6a4ee654e5e0c5e1f17e2f83c0f4c91dee1f9c",
"shasum": ""
},
"require": {
@@ -11779,7 +11784,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.14"
"source": "https://github.com/sebastianbergmann/phpunit/tree/11.5.15"
},
"funding": [
{
@@ -11795,7 +11800,7 @@
"type": "tidelift"
}
],
"time": "2025-03-19T13:45:48+00:00"
"time": "2025-03-23T16:02:11+00:00"
},
{
"name": "sebastian/cli-parser",

View File

@@ -29,12 +29,10 @@ use FireflyIII\Models\Bill;
use FireflyIII\Models\Budget;
use FireflyIII\Models\Category;
use FireflyIII\Models\PiggyBank;
use FireflyIII\Models\Preference;
use FireflyIII\Models\Recurrence;
use FireflyIII\Models\Tag;
use FireflyIII\Models\Transaction;
use FireflyIII\Models\TransactionJournal;
use FireflyIII\Support\Binder\Date;
use FireflyIII\TransactionRules\Actions\AddTag;
use FireflyIII\TransactionRules\Actions\ClearBudget;
use FireflyIII\TransactionRules\Actions\ClearCategory;
@@ -57,7 +55,6 @@ use FireflyIII\TransactionRules\Actions\SetSourceAccount;
use FireflyIII\TransactionRules\Actions\SetSourceToCashAccount;
use FireflyIII\TransactionRules\Actions\SwitchAccounts;
use FireflyIII\TransactionRules\Actions\UpdatePiggyBank;
use FireflyIII\User;
/*
* DO NOT EDIT THIS FILE. IT IS AUTO GENERATED.
@@ -81,7 +78,7 @@ return [
'running_balance_column' => env('USE_RUNNING_BALANCE', false),
// see cer.php for exchange rates feature flag.
],
'version' => '6.2.10',
'version' => 'develop/2025-04-06',
'api_version' => '2.1.0', // field is no longer used.
'db_version' => 25,
@@ -132,7 +129,7 @@ return [
'es_ES' => ['name_locale' => 'Español', 'name_english' => 'Spanish'],
'ca_ES' => ['name_locale' => 'Català (Espanya)', 'name_english' => 'Catalan (Spain)'],
// 'et_EE' => ['name_locale' => 'Estonian', 'name_english' => 'Estonian'],
// 'fa_IR' => ['name_locale' => 'فارسی', 'name_english' => 'Persian'],
'fa_IR' => ['name_locale' => 'فارسی', 'name_english' => 'Persian'],
'fi_FI' => ['name_locale' => 'Suomi', 'name_english' => 'Finnish'],
'fr_FR' => ['name_locale' => 'Français', 'name_english' => 'French'],
// 'he_IL' => ['name_locale' => 'Hebrew', 'name_english' => 'Hebrew'],
@@ -187,6 +184,7 @@ return [
'currencyPreference' => 'EUR',
'language' => 'en_US',
'locale' => 'equal',
'convertToNative' => false,
],
'default_currency' => 'EUR',
'default_language' => envNonEmpty('DEFAULT_LANGUAGE', 'en_US'),

View File

@@ -339,6 +339,7 @@ return [
'en_US',
'es_ES',
'ca_ES',
'fa_IR',
'fi_FI',
'fr_FR',
'hu_HU',

658
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -16,7 +16,8 @@ The different alpha and beta builds will be compiled from their corresponding ta
### Minor Release Support Matrix
| Version | Supported |
|----------------------------------|--------------------|
| Firefly III v6.1.x | :white_check_mark: |
| Firefly III v6.2.x | :white_check_mark: |
| Firefly III v6.1.x | :x: |
| Firefly III v6.0.x | :x: |
| Firefly III v5.8.x | :x: |
| Firefly III v5.7.x | :x: |

View File

@@ -46,7 +46,7 @@
"tags": "Etiquetas",
"no_budget": "(sin presupuesto)",
"no_bill": "(no subscription)",
"category": "Categoria",
"category": "Categor\u00eda",
"attachments": "Archivos adjuntos",
"notes": "Notas",
"external_url": "URL externa",
@@ -141,13 +141,13 @@
"reset_webhook_secret": "Restablecer secreto del webhook",
"header_exchange_rates": "Exchange rates",
"exchange_rates_intro": "Firefly III supports downloading and using exchange rates. Read more about this in <a href=\"https:\/\/docs.firefly-iii.org\/explanation\/financial-concepts\/exchange-rates\/\">the documentation<\/a>.",
"exchange_rates_from_to": "Between {from} and {to} (and the other way around)",
"exchange_rates_intro_rates": "Firefly III uses the following exchange rates. The inverse is automatically calculated when it is not provided. If no exchange rate exists for the date of the transaction, Firefly III will go back in time to find one. If none are present, the rate \"1\" will be used.",
"exchange_rates_from_to": "Entre {from} y {to} (y viceversa)",
"exchange_rates_intro_rates": "Firefly III utiliza los siguientes tipos de cambio. El inverso se calcula autom\u00e1ticamente cuando no se proporciona. Si no existe un tipo de cambio para la fecha de la transacci\u00f3n, Firefly III retroceder\u00e1 en el tiempo para encontrar uno. Si no hay ninguno presente, se usar\u00e1 la tasa \"1\".",
"header_exchange_rates_rates": "Exchange rates",
"header_exchange_rates_table": "Table with exchange rates",
"help_rate_form": "On this day, how many {to} will you get for one {from}?",
"add_new_rate": "Add a new exchange rate",
"save_new_rate": "Save new rate"
"header_exchange_rates_table": "Tabla con tipos de cambio",
"help_rate_form": "En este d\u00eda, \u00bfcu\u00e1nto {to} conseguir\u00e1s por un {from}?",
"add_new_rate": "Agregar un nuevo tipo de cambio",
"save_new_rate": "Guardar nuevo tipo de cambio"
},
"form": {
"url": "URL",
@@ -182,6 +182,6 @@
},
"config": {
"html_language": "es",
"date_time_fns": "El MMMM hacer, yyyy a las HH:mm:ss"
"date_time_fns": "'El' d 'de' MMMM 'de' yyyy 'a las' HH:mm:ss"
}
}

View File

@@ -0,0 +1,187 @@
{
"firefly": {
"administrations_page_title": "Financial administrations",
"administrations_index_menu": "Financial administrations",
"temp_administrations_introduction": "Firefly III will soon get the ability to manage multiple financial administrations. Right now, you only have the one. You can set the title of this administration and its native currency. This replaces the previous setting where you would set your \"default currency\". This setting is now tied to the financial administration and can be different per administration.",
"administration_currency_form_help": "It may take a long time for the page to load if you change the native currency because transaction may need to be converted to your (new) native currency.",
"administrations_page_edit_sub_title_js": "Edit financial administration \"{title}\"",
"table": "\u062c\u062f\u0648\u0644",
"welcome_back": "\u0686\u0647 \u062e\u0628\u0631\u061f",
"flash_error": "\u062e\u0637\u0627!",
"flash_warning": "\u0647\u0634\u062f\u0627\u0631!",
"flash_success": "\u0645\u0648\u0641\u0642\u06cc\u062a!",
"close": "\u0628\u0633\u062a\u0646",
"select_dest_account": "Please select or type a valid destination account name",
"select_source_account": "Please select or type a valid source account name",
"split_transaction_title": "\u0634\u0631\u062d \u062a\u0631\u0627\u06a9\u0646\u0634 \u062a\u0642\u0633\u06cc\u0645\n",
"errors_submission": "\u0645\u0634\u06a9\u0644\u06cc \u062f\u0631 \u0627\u0631\u0633\u0627\u0644 \u0634\u0645\u0627 \u0648\u062c\u0648\u062f \u062f\u0627\u0634\u062a. \u0644\u0637\u0641\u0627\u064b \u062e\u0637\u0627\u0647\u0627\u06cc \u0632\u06cc\u0631 \u0631\u0627 \u0628\u0631\u0631\u0633\u06cc \u06a9\u0646\u06cc\u062f.\n",
"is_reconciled": "Is reconciled",
"split": "\u062a\u0641\u06a9\u06cc\u06a9",
"single_split": "\u062a\u0641\u06a9\u06cc\u06a9",
"not_enough_currencies": "Not enough currencies",
"not_enough_currencies_enabled": "If you have just one currency enabled, there is no need to add exchange rates.",
"transaction_stored_link": "<a href=\"transactions\/show\/{ID}\">\u0645\u0639\u0627\u0645\u0644\u0647 \u0634\u0645\u0627\u0631\u0647{ID} (\"{title}\")<\/a> \u0630\u062e\u06cc\u0631\u0647 \u0634\u062f\u0647 \u0627\u0633\u062a.\n",
"webhook_stored_link": "<a href=\"webhooks\/show\/{ID}\">Webhooks #{ID} (\"{title}\")<\/a> \u0630\u062e\u06cc\u0631\u0647 \u0634\u062f\u0647 \u0627\u0633\u062a.\n",
"webhook_updated_link": "<a href=\"webhooks\/show\/{ID}\">Webhooks #{ID}<\/a> (\"{title}\") \u0628\u0647\u200c\u0631\u0648\u0632\u0631\u0633\u0627\u0646\u06cc \u0634\u062f\u0647 \u0627\u0633\u062a.\n",
"transaction_updated_link": "<a href=\"transactions\/show\/{ID}\">\u0645\u0639\u0627\u0645\u0644\u0647 \u0634\u0645\u0627\u0631\u0647{ID}<\/a> (\"{title}\") \u0628\u0647 \u0631\u0648\u0632 \u0634\u062f\u0647 \u0627\u0633\u062a.\n",
"transaction_new_stored_link": "<a href=\"transactions\/show\/{ID}\">\u0645\u0639\u0627\u0645\u0644\u0647 \u0634\u0645\u0627\u0631\u0647{ID}<\/a> \u0630\u062e\u06cc\u0631\u0647 \u0634\u062f\u0647 \u0627\u0633\u062a.\n",
"transaction_journal_information": "\u0627\u0637\u0644\u0627\u0639\u0627\u062a \u062a\u0631\u0627\u06a9\u0646\u0634",
"submission_options": "\u06af\u0632\u06cc\u0646\u0647 \u0647\u0627\u06cc \u0627\u0631\u0633\u0627\u0644\n",
"apply_rules_checkbox": "\u0642\u0648\u0627\u0646\u06cc\u0646 \u0631\u0627 \u0627\u0639\u0645\u0627\u0644 \u06a9\u0646\u06cc\u062f\n",
"fire_webhooks_checkbox": "\u0648\u0628\u200c\u0647\u0648\u06a9\u200c\u0647\u0627\u06cc \u0622\u062a\u0634\u06cc\u0646\n\n\n\n\n\n",
"no_budget_pointer": "\u0628\u0647 \u0646\u0638\u0631 \u0645\u06cc \u0631\u0633\u062f \u0647\u0646\u0648\u0632 \u0628\u0648\u062f\u062c\u0647 \u0627\u06cc \u0646\u062f\u0627\u0631\u06cc\u062f. \u0628\u0627\u06cc\u062f \u0645\u0642\u062f\u0627\u0631\u06cc \u0631\u0627 \u062f\u0631 \u0635\u0641\u062d\u0647 <a href=\"budgets\">\u0628\u0648\u062f\u062c\u0647\u200c\u0647\u0627<\/a> \u0627\u06cc\u062c\u0627\u062f \u06a9\u0646\u06cc\u062f. \u0628\u0648\u062f\u062c\u0647 \u0645\u06cc \u062a\u0648\u0627\u0646\u062f \u0628\u0647 \u0634\u0645\u0627 \u062f\u0631 \u067e\u06cc\u06af\u06cc\u0631\u06cc \u0647\u0632\u06cc\u0646\u0647 \u0647\u0627 \u06a9\u0645\u06a9 \u06a9\u0646\u062f.\n",
"no_bill_pointer": "You seem to have no subscription yet. You should create some on the <a href=\"subscriptions\">subscription<\/a>-page. Subscriptions can help you keep track of expenses.",
"source_account": "\u062d\u0633\u0627\u0628 \u0645\u0646\u0628\u0639\n",
"hidden_fields_preferences": "\u0645\u06cc\u200c\u062a\u0648\u0627\u0646\u06cc\u062f \u06af\u0632\u06cc\u0646\u0647\u200c\u0647\u0627\u06cc \u062a\u0631\u0627\u06a9\u0646\u0634 \u0628\u06cc\u0634\u062a\u0631\u06cc \u0631\u0627 \u062f\u0631 <a href=\"preferences\">\u062a\u0646\u0638\u06cc\u0645\u0627\u062a<\/a> \u062e\u0648\u062f \u0641\u0639\u0627\u0644 \u06a9\u0646\u06cc\u062f.\n",
"destination_account": "\u062d\u0633\u0627\u0628 \u0645\u0642\u0635\u062f\n",
"add_another_split": "\u06cc\u06a9 \u062a\u0642\u0633\u06cc\u0645 \u062f\u06cc\u06af\u0631 \u0627\u0636\u0627\u0641\u0647 \u06a9\u0646\u06cc\u062f\n",
"submission": "\u0627\u0631\u0633\u0627\u0644",
"stored_journal": "\u062a\u0631\u0627\u06a9\u0646\u0634 \u062c\u062f\u06cc\u062f \":description\" \u0628\u0627 \u0645\u0648\u0641\u0642\u06cc\u062a \u0627\u06cc\u062c\u0627\u062f \u0634\u062f\n",
"create_another": "\u067e\u0633 \u0627\u0632 \u0630\u062e\u06cc\u0631\u0647\u200c\u0633\u0627\u0632\u06cc\u060c \u0628\u0631\u0627\u06cc \u0627\u06cc\u062c\u0627\u062f \u06cc\u06a9\u06cc \u062f\u06cc\u06af\u0631 \u0628\u0647 \u0627\u06cc\u0646\u062c\u0627 \u0628\u0627\u0632\u06af\u0631\u062f\u06cc\u062f.\n",
"reset_after": "\u0628\u0627\u0632\u0646\u0634\u0627\u0646\u06cc \u0641\u0631\u0645 \u067e\u0633 \u0627\u0632 \u0627\u0631\u0633\u0627\u0644\n",
"submit": "\u0627\u0631\u0633\u0627\u0644",
"amount": "\u0645\u0628\u0644\u063a",
"date": "\u062a\u0627\u0631\u06cc\u062e",
"is_reconciled_fields_dropped": "Because this transaction is reconciled, you will not be able to update the accounts, nor the amount(s) unless you remove the reconciliation flag.",
"tags": "\u0628\u0631\u0686\u0633\u0628\u200c\u0647\u0627",
"no_budget": "(\u0628\u062f\u0648\u0646 \u0628\u0648\u062f\u062c\u0647)\n",
"no_bill": "(no subscription)",
"category": "\u062f\u0633\u062a\u0647 \u0628\u0646\u062f\u06cc",
"attachments": "\u067e\u06cc\u0648\u0633\u062a\u200c\u0647\u0627",
"notes": "\u06cc\u0627\u062f\u062f\u0627\u0634\u062a",
"external_url": "\u0622\u062f\u0631\u0633 \u0627\u06cc\u0646\u062a\u0631\u0646\u062a\u06cc \u062e\u0627\u0631\u062c\u06cc",
"update_transaction": "\u0628\u0647 \u0631\u0648\u0632 \u0631\u0633\u0627\u0646\u06cc \u062a\u0631\u0627\u06a9\u0646\u0634\n",
"after_update_create_another": "\u067e\u0633 \u0627\u0632 \u0628\u0647\u200c\u0631\u0648\u0632\u0631\u0633\u0627\u0646\u06cc\u060c \u0628\u0631\u0627\u06cc \u0627\u062f\u0627\u0645\u0647 \u0648\u06cc\u0631\u0627\u06cc\u0634 \u0628\u0647 \u0627\u06cc\u0646\u062c\u0627 \u0628\u0627\u0632\u06af\u0631\u062f\u06cc\u062f.\n",
"store_as_new": "\u0630\u062e\u06cc\u0631\u0647 \u0628\u0647 \u0639\u0646\u0648\u0627\u0646 \u06cc\u06a9 \u062a\u0631\u0627\u06a9\u0646\u0634 \u062c\u062f\u06cc\u062f \u0628\u0647 \u062c\u0627\u06cc \u0628\u0647 \u0631\u0648\u0632 \u0631\u0633\u0627\u0646\u06cc.\n",
"split_title_help": "\u0627\u06af\u0631 \u06cc\u06a9 \u062a\u0631\u0627\u06a9\u0646\u0634 \u062a\u0642\u0633\u06cc\u0645 \u0645\u06cc\u200c\u06a9\u0646\u06cc\u062f\u060c \u0628\u0627\u06cc\u062f \u06cc\u06a9 \u062a\u0648\u0636\u06cc\u062d \u06a9\u0644\u06cc \u0628\u0631\u0627\u06cc \u0647\u0645\u0647 \u062a\u0642\u0633\u06cc\u0645\u200c\u0628\u0646\u062f\u06cc\u200c\u0647\u0627\u06cc \u062a\u0631\u0627\u06a9\u0646\u0634 \u0648\u062c\u0648\u062f \u062f\u0627\u0634\u062a\u0647 \u0628\u0627\u0634\u062f.\n",
"none_in_select_list": "(\u0647\u06cc\u0686)",
"no_piggy_bank": "\u0628\u062f\u0648\u0646 \u0635\u0646\u062f\u0648\u0642\u0686\u0647\n\n",
"description": "\u062a\u0648\u0636\u06cc\u062d\u0627\u062a",
"split_transaction_title_help": "\u0627\u06af\u0631 \u06cc\u06a9 \u062a\u0631\u0627\u06a9\u0646\u0634 \u062a\u0642\u0633\u06cc\u0645 \u0645\u06cc\u200c\u06a9\u0646\u06cc\u062f\u060c \u0628\u0627\u06cc\u062f \u06cc\u06a9 \u062a\u0648\u0636\u06cc\u062d \u06a9\u0644\u06cc \u0628\u0631\u0627\u06cc \u0647\u0645\u0647 \u062a\u0642\u0633\u06cc\u0645\u200c\u0628\u0646\u062f\u06cc\u200c\u0647\u0627\u06cc \u062a\u0631\u0627\u06a9\u0646\u0634 \u0648\u062c\u0648\u062f \u062f\u0627\u0634\u062a\u0647 \u0628\u0627\u0634\u062f.\n",
"destination_account_reconciliation": "\u0646\u0645\u06cc\u200c\u062a\u0648\u0627\u0646\u06cc\u062f \u062d\u0633\u0627\u0628 \u0645\u0642\u0635\u062f \u062a\u0631\u0627\u06a9\u0646\u0634 \u062a\u0637\u0628\u06cc\u0642 \u0631\u0627 \u0648\u06cc\u0631\u0627\u06cc\u0634 \u06a9\u0646\u06cc\u062f.\n",
"source_account_reconciliation": "\u0646\u0645\u06cc\u200c\u062a\u0648\u0627\u0646\u06cc\u062f \u062d\u0633\u0627\u0628 \u0645\u0646\u0628\u0639 \u06cc\u06a9 \u062a\u0631\u0627\u06a9\u0646\u0634 \u062a\u0637\u0628\u06cc\u0642 \u0631\u0627 \u0648\u06cc\u0631\u0627\u06cc\u0634 \u06a9\u0646\u06cc\u062f.\n",
"budget": "\u0628\u0648\u062f\u062c\u0647",
"bill": "Subscription",
"you_create_withdrawal": "\u0634\u0645\u0627 \u062f\u0631 \u062d\u0627\u0644 \u0627\u06cc\u062c\u0627\u062f \u06cc\u06a9 \u0628\u0631\u062f\u0627\u0634\u062a \u0647\u0633\u062a\u06cc\u062f.\n",
"you_create_transfer": "\u0634\u0645\u0627 \u062f\u0631 \u062d\u0627\u0644 \u0627\u06cc\u062c\u0627\u062f \u06cc\u06a9 \u0627\u0646\u062a\u0642\u0627\u0644 \u0647\u0633\u062a\u06cc\u062f.\n",
"you_create_deposit": "\u0634\u0645\u0627 \u062f\u0631 \u062d\u0627\u0644 \u0627\u06cc\u062c\u0627\u062f \u06cc\u06a9 \u0633\u067e\u0631\u062f\u0647 \u0647\u0633\u062a\u06cc\u062f.\n",
"edit": "\u0648\u06cc\u0631\u0627\u06cc\u0634",
"delete": "\u062d\u0630\u0641",
"name": "\u0646\u0627\u0645",
"profile_whoops": "\u0627\u0648\u0647!",
"profile_something_wrong": "\u0645\u0634\u06a9\u0644\u06cc \u067e\u06cc\u0634 \u0622\u0645\u062f\u0647 \u0627\u0633\u062a!\n\n\n\n\n\n",
"profile_try_again": "\u0645\u0634\u06a9\u0644\u06cc \u067e\u06cc\u0634 \u0622\u0645\u062f. \u0644\u0637\u0641\u0627 \u062f\u0648\u0628\u0627\u0631\u0647 \u062a\u0644\u0627\u0634 \u06a9\u0646\u06cc\u062f.\n",
"profile_oauth_clients": "\u0645\u0634\u062a\u0631\u06cc\u200c\u0647\u0627\u06cc OAuth\n\n\n\n\n\n",
"profile_oauth_no_clients": "\u0634\u0645\u0627 \u0647\u06cc\u0686 \u0645\u0634\u062a\u0631\u06cc OAuth \u0627\u06cc\u062c\u0627\u062f \u0646\u06a9\u0631\u062f\u0647\u200c\u0627\u06cc\u062f.\n\n\n\n\n\n",
"profile_oauth_clients_header": "\u0645\u0634\u062a\u0631\u06cc\u200c\u0647\u0627",
"profile_oauth_client_id": "\u0634\u0646\u0627\u0633\u0647 \u0645\u0634\u062a\u0631\u06cc",
"profile_oauth_client_name": "\u0646\u0627\u0645",
"profile_oauth_client_secret": "\u0645\u062d\u0631\u0645\u0627\u0646\u0647",
"profile_oauth_create_new_client": "\u0645\u0634\u062a\u0631\u06cc \u062c\u062f\u06cc\u062f \u0627\u06cc\u062c\u0627\u062f \u06a9\u0646\u06cc\u062f\n",
"profile_oauth_create_client": "\u0645\u0634\u062a\u0631\u06cc \u0627\u06cc\u062c\u0627\u062f \u06a9\u0646\u06cc\u062f\n",
"profile_oauth_edit_client": "\u0648\u06cc\u0631\u0627\u06cc\u0634 \u0645\u0634\u062a\u0631\u06cc\n\n\n\n\n\n",
"profile_oauth_name_help": "\u0686\u06cc\u0632\u06cc \u06a9\u0647 \u06a9\u0627\u0631\u0628\u0631\u0627\u0646 \u0634\u0645\u0627 \u0645\u06cc \u0634\u0646\u0627\u0633\u0646\u062f \u0648 \u0628\u0647 \u0622\u0646 \u0627\u0639\u062a\u0645\u0627\u062f \u0645\u06cc \u06a9\u0646\u0646\u062f.\n",
"profile_oauth_redirect_url": "\u062a\u063a\u06cc\u06cc\u0631 \u0645\u0633\u06cc\u0631 URL\n",
"profile_oauth_clients_external_auth": "\u0627\u06af\u0631 \u0627\u0632 \u06cc\u06a9 \u0627\u0631\u0627\u0626\u0647 \u062f\u0647\u0646\u062f\u0647 \u0627\u062d\u0631\u0627\u0632 \u0647\u0648\u06cc\u062a \u062e\u0627\u0631\u062c\u06cc \u0645\u0627\u0646\u0646\u062f Authelia \u0627\u0633\u062a\u0641\u0627\u062f\u0647 \u0645\u06cc \u06a9\u0646\u06cc\u062f\u060c OAuth Clients \u06a9\u0627\u0631 \u0646\u0645\u06cc \u06a9\u0646\u062f. \u0634\u0645\u0627 \u0645\u06cc \u062a\u0648\u0627\u0646\u06cc\u062f \u0641\u0642\u0637 \u0627\u0632 \u0631\u0645\u0632\u0647\u0627\u06cc \u062f\u0633\u062a\u0631\u0633\u06cc \u0634\u062e\u0635\u06cc \u0627\u0633\u062a\u0641\u0627\u062f\u0647 \u06a9\u0646\u06cc\u062f.\n",
"profile_oauth_redirect_url_help": "URL \u0628\u0627\u0632\u06af\u0634\u062a \u0628\u0647 \u062a\u0645\u0627\u0633 \u0645\u062c\u0648\u0632 \u0628\u0631\u0646\u0627\u0645\u0647 \u0634\u0645\u0627.\n",
"profile_authorized_apps": "\u0628\u0631\u0646\u0627\u0645\u0647 \u0647\u0627\u06cc \u06a9\u0627\u0631\u0628\u0631\u062f\u06cc \u0645\u062c\u0627\u0632\n",
"profile_authorized_clients": "\u0645\u0634\u062a\u0631\u06cc\u0627\u0646 \u0645\u062c\u0627\u0632\n",
"profile_scopes": "\u0645\u062d\u062f\u0648\u062f\u0647 \u0647\u0627",
"profile_revoke": "\u0644\u063a\u0648",
"profile_personal_access_tokens": "\u062a\u0648\u06a9\u0646 \u0647\u0627\u06cc \u062f\u0633\u062a\u0631\u0633\u06cc \u0634\u062e\u0635\u06cc\n",
"profile_personal_access_token": "\u062a\u0648\u06a9\u0646 \u0647\u0627\u06cc \u062f\u0633\u062a\u0631\u0633\u06cc \u0634\u062e\u0635\u06cc\n",
"profile_personal_access_token_explanation": "\u0627\u06cc\u0646 \u0631\u0645\u0632 \u062f\u0633\u062a\u0631\u0633\u06cc \u0634\u062e\u0635\u06cc \u062c\u062f\u06cc\u062f \u0634\u0645\u0627\u0633\u062a. \u0627\u06cc\u0646 \u062a\u0646\u0647\u0627 \u0628\u0627\u0631\u06cc \u0627\u0633\u062a \u06a9\u0647 \u0646\u0645\u0627\u06cc\u0634 \u062f\u0627\u062f\u0647 \u062e\u0648\u0627\u0647\u062f \u0634\u062f\u060c \u067e\u0633 \u0622\u0646 \u0631\u0627 \u0627\u0632 \u062f\u0633\u062a \u0646\u062f\u0647\u06cc\u062f! \u0627\u06a9\u0646\u0648\u0646 \u0645\u06cc \u062a\u0648\u0627\u0646\u06cc\u062f \u0627\u0632 \u0627\u06cc\u0646 \u0646\u0634\u0627\u0646\u0647 \u0628\u0631\u0627\u06cc \u0627\u06cc\u062c\u0627\u062f \u062f\u0631\u062e\u0648\u0627\u0633\u062a \u0647\u0627\u06cc API \u0627\u0633\u062a\u0641\u0627\u062f\u0647 \u06a9\u0646\u06cc\u062f.\n",
"profile_no_personal_access_token": "\u0634\u0645\u0627 \u0647\u06cc\u0686 \u0646\u0634\u0627\u0646\u0647 \u062f\u0633\u062a\u0631\u0633\u06cc \u0634\u062e\u0635\u06cc \u0627\u06cc\u062c\u0627\u062f \u0646\u06a9\u0631\u062f\u0647 \u0627\u06cc\u062f.\n",
"profile_create_new_token": "\u062a\u0648\u06a9\u0646 \u062c\u062f\u06cc\u062f \u0627\u06cc\u062c\u0627\u062f \u06a9\u0646\u06cc\u062f\n",
"profile_create_token": "\u0627\u06cc\u062c\u0627\u062f \u062a\u0648\u06a9\u0646",
"profile_create": "\u0627\u06cc\u062c\u0627\u062f",
"profile_save_changes": "\u0630\u062e\u06cc\u0631\u0647\u0654 \u062a\u063a\u06cc\u06cc\u0631\u0627\u062a",
"default_group_title_name": "(\u06af\u0631\u0648\u0647 \u0628\u0646\u062f\u06cc \u0646\u0634\u062f\u0647)\n",
"piggy_bank": "\u0635\u0646\u062f\u0648\u0642 \u067e\u0633\u200c\u0627\u0646\u062f\u0627\u0632\n\n\n\n\n\n",
"profile_oauth_client_secret_title": "\u0631\u0627\u0632 \u0645\u0634\u062a\u0631\u06cc",
"profile_oauth_client_secret_expl": "\u062f\u0631 \u0627\u06cc\u0646\u062c\u0627 \u0631\u0627\u0632 \u0645\u0634\u062a\u0631\u06cc \u062c\u062f\u06cc\u062f \u0634\u0645\u0627 \u0648\u062c\u0648\u062f \u062f\u0627\u0631\u062f. \u0627\u06cc\u0646 \u062a\u0646\u0647\u0627 \u0628\u0627\u0631\u06cc \u0627\u0633\u062a \u06a9\u0647 \u0646\u0645\u0627\u06cc\u0634 \u062f\u0627\u062f\u0647 \u062e\u0648\u0627\u0647\u062f \u0634\u062f\u060c \u067e\u0633 \u0622\u0646 \u0631\u0627 \u0627\u0632 \u062f\u0633\u062a \u0646\u062f\u0647\u06cc\u062f! \u0627\u06a9\u0646\u0648\u0646 \u0645\u06cc \u062a\u0648\u0627\u0646\u06cc\u062f \u0627\u0632 \u0627\u06cc\u0646 \u0631\u0627\u0632 \u0628\u0631\u0627\u06cc \u0627\u06cc\u062c\u0627\u062f \u062f\u0631\u062e\u0648\u0627\u0633\u062a \u0647\u0627\u06cc API \u0627\u0633\u062a\u0641\u0627\u062f\u0647 \u06a9\u0646\u06cc\u062f.\n",
"profile_oauth_confidential": "\u0645\u062d\u0631\u0645\u0627\u0646\u0647",
"profile_oauth_confidential_help": "\u0627\u0632 \u0645\u0634\u062a\u0631\u06cc \u0628\u062e\u0648\u0627\u0647\u06cc\u062f \u0628\u0627 \u06cc\u06a9 \u0631\u0627\u0632 \u0627\u062d\u0631\u0627\u0632 \u0647\u0648\u06cc\u062a \u06a9\u0646\u062f. \u0645\u0634\u062a\u0631\u06cc\u0627\u0646 \u0645\u062d\u0631\u0645\u0627\u0646\u0647 \u0645\u06cc \u062a\u0648\u0627\u0646\u0646\u062f \u0627\u0639\u062a\u0628\u0627\u0631\u0646\u0627\u0645\u0647 \u0647\u0627 \u0631\u0627 \u0628\u0647 \u0631\u0648\u0634\u06cc \u0627\u0645\u0646 \u0648 \u0628\u062f\u0648\u0646 \u0642\u0631\u0627\u0631 \u062f\u0627\u062f\u0646 \u0622\u0646\u0647\u0627 \u062f\u0631 \u0645\u0639\u0631\u0636 \u0627\u0634\u062e\u0627\u0635 \u063a\u06cc\u0631\u0645\u062c\u0627\u0632 \u0646\u06af\u0647\u062f\u0627\u0631\u06cc \u06a9\u0646\u0646\u062f. \u0628\u0631\u0646\u0627\u0645\u0647 \u0647\u0627\u06cc \u0639\u0645\u0648\u0645\u06cc\u060c \u0645\u0627\u0646\u0646\u062f \u0628\u0631\u0646\u0627\u0645\u0647 \u0647\u0627\u06cc \u062f\u0633\u06a9\u062a\u0627\u067e \u0628\u0648\u0645\u06cc \u06cc\u0627 \u062c\u0627\u0648\u0627 \u0627\u0633\u06a9\u0631\u06cc\u067e\u062a SPA\u060c \u0646\u0645\u06cc \u062a\u0648\u0627\u0646\u0646\u062f \u0627\u0633\u0631\u0627\u0631 \u0631\u0627 \u0628\u0647 \u0635\u0648\u0631\u062a \u0627\u06cc\u0645\u0646 \u0646\u06af\u0647 \u062f\u0627\u0631\u0646\u062f.\n",
"multi_account_warning_unknown": "\u0628\u0633\u062a\u0647 \u0628\u0647 \u0646\u0648\u0639 \u062a\u0631\u0627\u06a9\u0646\u0634\u06cc \u06a9\u0647 \u0627\u06cc\u062c\u0627\u062f \u0645\u06cc\u200c\u06a9\u0646\u06cc\u062f\u060c \u062d\u0633\u0627\u0628 \u0645\u0646\u0628\u0639 \u0648\/\u06cc\u0627 \u0645\u0642\u0635\u062f \u062a\u0642\u0633\u06cc\u0645\u200c\u0647\u0627\u06cc \u0628\u0639\u062f\u06cc \u0645\u0645\u06a9\u0646 \u0627\u0633\u062a \u0628\u0627 \u0647\u0631 \u0622\u0646\u0686\u0647 \u062f\u0631 \u062a\u0642\u0633\u06cc\u0645 \u0627\u0648\u0644 \u062a\u0631\u0627\u06a9\u0646\u0634 \u062a\u0639\u0631\u06cc\u0641 \u0634\u062f\u0647 \u0627\u0633\u062a \u0644\u063a\u0648 \u0634\u0648\u062f.\n",
"multi_account_warning_withdrawal": "\u0628\u0647 \u062e\u0627\u0637\u0631 \u062f\u0627\u0634\u062a\u0647 \u0628\u0627\u0634\u06cc\u062f \u06a9\u0647 \u062d\u0633\u0627\u0628 \u0645\u0646\u0628\u0639 \u0627\u0646\u0634\u0639\u0627\u0628\u0627\u062a \u0628\u0639\u062f\u06cc \u0628\u0627 \u0647\u0631 \u0622\u0646\u0686\u0647 \u062f\u0631 \u062a\u0642\u0633\u06cc\u0645 \u0627\u0648\u0644 \u0628\u0631\u062f\u0627\u0634\u062a \u062a\u0639\u0631\u06cc\u0641 \u0634\u062f\u0647 \u0627\u0633\u062a \u0644\u063a\u0648 \u0645\u06cc \u0634\u0648\u062f.\n",
"multi_account_warning_deposit": "\u0628\u0647 \u062e\u0627\u0637\u0631 \u062f\u0627\u0634\u062a\u0647 \u0628\u0627\u0634\u06cc\u062f \u06a9\u0647 \u062d\u0633\u0627\u0628 \u0645\u0642\u0635\u062f \u062a\u0642\u0633\u06cc\u0645 \u0647\u0627\u06cc \u0628\u0639\u062f\u06cc \u0628\u0627 \u0647\u0631 \u0622\u0646\u0686\u0647 \u062f\u0631 \u0627\u0648\u0644\u06cc\u0646 \u062a\u0642\u0633\u06cc\u0645 \u0633\u067e\u0631\u062f\u0647 \u062a\u0639\u0631\u06cc\u0641 \u0634\u062f\u0647 \u0627\u0633\u062a \u0644\u063a\u0648 \u0645\u06cc \u0634\u0648\u062f.\n",
"multi_account_warning_transfer": "\u0628\u0647 \u062e\u0627\u0637\u0631 \u062f\u0627\u0634\u062a\u0647 \u0628\u0627\u0634\u06cc\u062f \u06a9\u0647 \u062d\u0633\u0627\u0628 \u0645\u0628\u062f\u0627 + \u0645\u0642\u0635\u062f \u062a\u0642\u0633\u06cc\u0645\u200c\u0647\u0627\u06cc \u0628\u0639\u062f\u06cc \u0628\u0627 \u0647\u0631 \u0622\u0646\u0686\u0647 \u062f\u0631 \u062a\u0642\u0633\u06cc\u0645 \u0627\u0648\u0644 \u0627\u0646\u062a\u0642\u0627\u0644 \u062a\u0639\u0631\u06cc\u0641 \u0634\u062f\u0647 \u0627\u0633\u062a \u0644\u063a\u0648 \u0645\u06cc\u200c\u0634\u0648\u062f.\n",
"webhook_trigger_STORE_TRANSACTION": "\u067e\u0633 \u0627\u0632 \u0627\u06cc\u062c\u0627\u062f \u062a\u0631\u0627\u06a9\u0646\u0634\n",
"webhook_trigger_UPDATE_TRANSACTION": "\u067e\u0633 \u0627\u0632 \u0628\u0647 \u0631\u0648\u0632 \u0631\u0633\u0627\u0646\u06cc \u062a\u0631\u0627\u06a9\u0646\u0634\n",
"webhook_trigger_DESTROY_TRANSACTION": "\u067e\u0633 \u0627\u0632 \u062a\u0631\u0627\u06a9\u0646\u0634 \u062d\u0630\u0641 \u0634\u0648\u062f\n",
"webhook_response_TRANSACTIONS": "\u062c\u0632\u0626\u06cc\u0627\u062a \u062a\u0631\u0627\u06a9\u0646\u0634",
"webhook_response_ACCOUNTS": "\u062c\u0632\u0626\u06cc\u0627\u062a \u062d\u0633\u0627\u0628",
"webhook_response_none_NONE": "\u0628\u062f\u0648\u0646 \u062c\u0632\u0626\u06cc\u0627\u062a",
"webhook_delivery_JSON": "JSON",
"actions": "\u0639\u0645\u0644\u06cc\u0627\u062a \u0647\u0627",
"meta_data": "\u062f\u0627\u062f\u0647 \u0647\u0627\u06cc \u0645\u062a\u0627\n",
"webhook_messages": "\u067e\u06cc\u0627\u0645 \u0648\u0628 \u0647\u0648\u06a9\n",
"inactive": "\u063a\u06cc\u0631 \u0641\u0639\u0627\u0644",
"no_webhook_messages": "\u0647\u06cc\u0686 \u067e\u06cc\u0627\u0645\u06cc \u0628\u0631\u0627\u06cc \u0648\u0628 \u0647\u0648\u06a9 \u0648\u062c\u0648\u062f \u0646\u062f\u0627\u0631\u062f\n",
"inspect": "\u0628\u0627\u0632\u0631\u0633\u06cc \u06a9\u0646\u06cc\u062f",
"create_new_webhook": "\u0627\u06cc\u062c\u0627\u062f \u0648\u0628 \u0647\u0648\u06a9 \u062c\u062f\u06cc\u062f",
"webhooks": "\u0647\u0648\u06a9 \u0647\u0627\u06cc \u062a\u062d\u062a \u0648\u0628",
"webhook_trigger_form_help": "\u0646\u0634\u0627\u0646 \u062f\u0647\u06cc\u062f \u06a9\u0647 \u062f\u0631 \u0686\u0647 \u0631\u0648\u06cc\u062f\u0627\u062f\u06cc \u0648\u0628 \u0647\u0648\u06a9 \u0631\u0627\u0647 \u0627\u0646\u062f\u0627\u0632\u06cc \u0645\u06cc \u0634\u0648\u062f\n",
"webhook_response_form_help": "\u0622\u0646\u0686\u0647 \u0631\u0627 \u06a9\u0647 \u0648\u0628 \u0647\u0648\u06a9 \u0628\u0627\u06cc\u062f \u0628\u0647 URL \u0627\u0631\u0633\u0627\u0644 \u06a9\u0646\u062f \u0631\u0627 \u0645\u0634\u062e\u0635 \u06a9\u0646\u06cc\u062f.\n",
"webhook_delivery_form_help": "\u0648\u0628 \u0647\u0648\u06a9 \u0628\u0627\u06cc\u062f \u062f\u0631 \u0686\u0647 \u0642\u0627\u0644\u0628\u06cc \u062f\u0627\u062f\u0647 \u0647\u0627 \u0631\u0627 \u062a\u062d\u0648\u06cc\u0644 \u062f\u0647\u062f.\n",
"webhook_active_form_help": "\u0648\u0628 \u0647\u0648\u06a9 \u0628\u0627\u06cc\u062f \u0641\u0639\u0627\u0644 \u0628\u0627\u0634\u062f \u0648\u06af\u0631\u0646\u0647 \u0641\u0631\u0627\u062e\u0648\u0627\u0646\u06cc \u0646\u0645\u06cc \u0634\u0648\u062f.\n",
"edit_webhook_js": "\u0648\u06cc\u0631\u0627\u06cc\u0634 \u0648\u0628 \u0647\u0648\u06a9 \"{title}\"\n",
"webhook_was_triggered": "\u0648\u0628 \u0647\u0648\u06a9 \u062f\u0631 \u062a\u0631\u0627\u06a9\u0646\u0634 \u0645\u0634\u062e\u0635 \u0634\u062f\u0647 \u0641\u0639\u0627\u0644 \u0634\u062f. \u0644\u0637\u0641\u0627 \u0635\u0628\u0631 \u06a9\u0646\u06cc\u062f \u062a\u0627 \u0646\u062a\u0627\u06cc\u062c \u0638\u0627\u0647\u0631 \u0634\u0648\u062f.\n",
"view_message": "\u0645\u0634\u0627\u0647\u062f\u0647 \u067e\u06cc\u0627\u0645",
"view_attempts": "\u0645\u0634\u0627\u0647\u062f\u0647 \u062a\u0644\u0627\u0634 \u0647\u0627\u06cc \u0646\u0627\u0645\u0648\u0641\u0642\n",
"message_content_title": "\u0645\u062d\u062a\u0648\u0627\u06cc \u067e\u06cc\u0627\u0645 \u0648\u0628 \u0647\u0648\u06a9\n",
"message_content_help": "\u0627\u06cc\u0646 \u0645\u062d\u062a\u0648\u0627\u06cc \u067e\u06cc\u0627\u0645\u06cc \u0627\u0633\u062a \u06a9\u0647 \u0628\u0627 \u0627\u0633\u062a\u0641\u0627\u062f\u0647 \u0627\u0632 \u0627\u06cc\u0646 \u0648\u0628 \u0647\u0648\u06a9 \u0627\u0631\u0633\u0627\u0644 \u0634\u062f\u0647 (\u06cc\u0627 \u0627\u0645\u062a\u062d\u0627\u0646 \u0634\u062f\u0647 \u0627\u0633\u062a).\n",
"attempt_content_title": "\u062a\u0644\u0627\u0634 \u0647\u0627\u06cc \u0648\u0628 \u0647\u0648\u06a9\n",
"attempt_content_help": "\u0627\u06cc\u0646\u0647\u0627 \u0647\u0645\u0647 \u062a\u0644\u0627\u0634 \u0647\u0627\u06cc \u0646\u0627\u0645\u0648\u0641\u0642 \u0627\u06cc\u0646 \u067e\u06cc\u0627\u0645 \u0648\u0628 \u0647\u0648\u06a9 \u0628\u0631\u0627\u06cc \u0627\u0631\u0633\u0627\u0644 \u0628\u0647 URL \u067e\u06cc\u06a9\u0631\u0628\u0646\u062f\u06cc \u0634\u062f\u0647 \u0627\u0633\u062a. \u067e\u0633 \u0627\u0632 \u0645\u062f\u062a\u06cc\u060c Firefly III \u062a\u0644\u0627\u0634 \u062e\u0648\u062f \u0631\u0627 \u0645\u062a\u0648\u0642\u0641 \u0645\u06cc \u06a9\u0646\u062f.\n",
"no_attempts": "\u0647\u06cc\u0686 \u062a\u0644\u0627\u0634 \u0646\u0627\u0645\u0648\u0641\u0642\u06cc \u0648\u062c\u0648\u062f \u0646\u062f\u0627\u0631\u062f. \u0627\u06cc\u0646 \u0686\u06cc\u0632 \u062e\u0648\u0628\u06cc \u0627\u0633\u062a!\n",
"webhook_attempt_at": "\u062a\u0644\u0627\u0634 \u062f\u0631 {moment}\n",
"logs": "\u06af\u0632\u0627\u0631\u0634\u200c\u0647\u0627",
"response": "\u067e\u0627\u0633\u062e",
"visit_webhook_url": "\u0627\u0632 URL webhook \u062f\u06cc\u062f\u0646 \u06a9\u0646\u06cc\u062f\n",
"reset_webhook_secret": "\u0631\u0627\u0632 \u0648\u0628 \u0647\u0648\u06a9 \u0631\u0627 \u0628\u0627\u0632\u0646\u0634\u0627\u0646\u06cc \u06a9\u0646\u06cc\u062f\n",
"header_exchange_rates": "Exchange rates",
"exchange_rates_intro": "Firefly III supports downloading and using exchange rates. Read more about this in <a href=\"https:\/\/docs.firefly-iii.org\/explanation\/financial-concepts\/exchange-rates\/\">the documentation<\/a>.",
"exchange_rates_from_to": "Between {from} and {to} (and the other way around)",
"exchange_rates_intro_rates": "Firefly III uses the following exchange rates. The inverse is automatically calculated when it is not provided. If no exchange rate exists for the date of the transaction, Firefly III will go back in time to find one. If none are present, the rate \"1\" will be used.",
"header_exchange_rates_rates": "Exchange rates",
"header_exchange_rates_table": "Table with exchange rates",
"help_rate_form": "On this day, how many {to} will you get for one {from}?",
"add_new_rate": "Add a new exchange rate",
"save_new_rate": "Save new rate"
},
"form": {
"url": "\u0646\u0634\u0627\u0646\u06cc \u200cURL",
"active": "\u0641\u0639\u0627\u0644",
"interest_date": "\u0646\u0631\u062e \u0628\u0647\u0631\u0647",
"administration_currency": "Native currency",
"title": "\u0639\u0646\u0648\u0627\u0646",
"date": "\u062a\u0627\u0631\u06cc\u062e",
"book_date": "\u062a\u0627\u0631\u06cc\u062e \u06a9\u062a\u0627\u0628",
"process_date": "\u062a\u0627\u0631\u06cc\u062e \u067e\u0631\u062f\u0627\u0632\u0634",
"due_date": "\u0633\u0631\u0631\u0633\u06cc\u062f",
"foreign_amount": "\u0645\u0642\u062f\u0627\u0631 \u062e\u0627\u0631\u062c\u06cc\n\n\n\n\n\n",
"payment_date": "\u062a\u0627\u0631\u06cc\u062e \u067e\u0631\u062f\u0627\u062e\u062a",
"invoice_date": "\u062a\u0627\u0631\u06cc\u062e \u0641\u0627\u06a9\u062a\u0648\u0631",
"internal_reference": "\u0645\u0631\u062c\u0639 \u062f\u0627\u062e\u0644\u06cc\n",
"webhook_response": "\u067e\u0627\u0633\u062e",
"webhook_trigger": "\u0631\u0627\u0647\u200c\u0627\u0646\u062f\u0627\u0632",
"webhook_delivery": "\u062a\u062d\u0648\u06cc\u0644",
"from_currency_to_currency": "{from} &rarr; {to}",
"to_currency_from_currency": "{to} &rarr; {from}",
"rate": "Rate"
},
"list": {
"title": "\u0639\u0646\u0648\u0627\u0646",
"active": "\u0641\u0639\u0627\u0644 \u0627\u0633\u062a\u061f",
"native_currency": "Native currency",
"trigger": "\u0631\u0627\u0647\u200c\u0627\u0646\u062f\u0627\u0632",
"response": "\u067e\u0627\u0633\u062e",
"delivery": "\u062a\u062d\u0648\u06cc\u0644",
"url": "\u0646\u0634\u0627\u0646\u06cc \u200cURL",
"secret": "\u0645\u062d\u0631\u0645\u0627\u0646\u0647"
},
"config": {
"html_language": "fa",
"date_time_fns": "MMMM Do, YYYY, @ HH:mm:ss"
}
}

View File

@@ -135,7 +135,7 @@
"attempt_content_help": "These are all the unsuccessful attempts of this webhook message to submit to the configured URL. After some time, Firefly III will stop trying.",
"no_attempts": "There are no unsuccessful attempts. That's a good thing!",
"webhook_attempt_at": "Attempt at {moment}",
"logs": "Logs",
"logs": "Log",
"response": "Response",
"visit_webhook_url": "Visit webhook URL",
"reset_webhook_secret": "Reset webhook secret",

View File

@@ -30,7 +30,7 @@
"apply_rules_checkbox": "Applica le regole",
"fire_webhooks_checkbox": "Esegui webhook",
"no_budget_pointer": "Sembra che tu non abbia ancora dei budget. Dovresti crearne alcuni nella pagina dei <a href=\"budgets\">budget<\/a>. I budget possono aiutarti a tenere traccia delle spese.",
"no_bill_pointer": "Sembra che tu non abbia ancora un abbonamento. Dovresti crearne alcuni sulla pagina <a href=\"subscriptions\">abbonamento<\/a>. Gli abbonamenti possono aiutarti a tenere traccia delle spese.",
"no_bill_pointer": "Sembra che tu non abbia ancora un pagamento ricorrente. Dovresti crearne alcuni sulla pagina <a href=\"subscriptions\">pagamenti ricorrenti<\/a>. I pagamenti ricorrenti possono aiutarti a tenere traccia delle spese.",
"source_account": "Conto di origine",
"hidden_fields_preferences": "Puoi abilitare maggiori opzioni per le transazioni nelle tue <a href=\"preferences\">impostazioni<\/a>.",
"destination_account": "Conto destinazione",

View File

@@ -153,7 +153,7 @@
"url": "URL",
"active": "\ud65c\uc131",
"interest_date": "\uc774\uc790 \ub0a0\uc9dc",
"administration_currency": "Native currency",
"administration_currency": "\uc790\uad6d \ud1b5\ud654",
"title": "\uc81c\ubaa9",
"date": "\ub0a0\uc9dc",
"book_date": "\uc608\uc57d\uc77c",
@@ -173,7 +173,7 @@
"list": {
"title": "\uc81c\ubaa9",
"active": "\ud65c\uc131 \uc0c1\ud0dc\uc785\ub2c8\uae4c?",
"native_currency": "Native currency",
"native_currency": "\uc790\uad6d \ud1b5\ud654",
"trigger": "\ud2b8\ub9ac\uac70",
"response": "\uc751\ub2f5",
"delivery": "\uc804\ub2ec",

View File

@@ -8,26 +8,22 @@
"postinstall": "patch-package --error-on-fail"
},
"devDependencies": {
"axios": "^1.8.2",
"laravel-vite-plugin": "^1.0.5",
"patch-package": "^8.0.0",
"sass": "^1.78.0",
"axios": "^1",
"laravel-vite-plugin": "^1",
"patch-package": "^8",
"sass": "^1",
"vite": "^6",
"vite-plugin-manifest-sri": "^0.2.0"
},
"dependencies": {
"@ag-grid-community/client-side-row-model": "^32.0.2",
"@ag-grid-community/core": "^32.0.2",
"@ag-grid-community/infinite-row-model": "^32.0.2",
"@ag-grid-community/styles": "^33.0.2",
"@fortawesome/fontawesome-free": "^6.4.0",
"@popperjs/core": "^2.11.8",
"admin-lte": "^4.0.0-alpha3",
"admin-lte": "^4.0.0-beta3",
"alpinejs": "^3.13.7",
"bootstrap": "^5.3.0",
"bootstrap5-autocomplete": "^1.1.22",
"bootstrap5-tags": "^1.7",
"chart.js": "^4.4.0",
"bootstrap": "^5",
"bootstrap5-autocomplete": "^1",
"bootstrap5-tags": "^1",
"chart.js": "^4",
"chartjs-adapter-date-fns": "^3.0.0",
"chartjs-chart-sankey": "^0.14.0",
"date-fns": "^4.0.0",

View File

@@ -0,0 +1,36 @@
/*
* overview.js
* Copyright (c) 2022 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/>.
*/
import {api} from "../../../../boot/axios";
import {format} from "date-fns";
export default class Dashboard {
dashboard(start, end) {
let startStr = format(start, 'y-MM-dd');
let endStr = format(end, 'y-MM-dd');
return api.get('/api/v1/chart/account/dashboard', {params: {fix: true, start: startStr, end: endStr}});
}
expense(start, end) {
let startStr = format(start, 'y-MM-dd');
let endStr = format(end, 'y-MM-dd');
return api.get('/api/v1/chart/account/expense-dashboard', {params: {start: startStr, end: endStr}});
}
}

View File

@@ -0,0 +1,30 @@
/*
* overview.js
* Copyright (c) 2022 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/>.
*/
import {api} from "../../../../boot/axios";
import {format} from "date-fns";
export default class Dashboard {
dashboard(start, end) {
let startStr = format(start, 'y-MM-dd');
let endStr = format(end, 'y-MM-dd');
return api.get('/api/v1/chart/budget/dashboard', {params: {start: startStr, end: endStr}});
}
}

View File

@@ -0,0 +1,30 @@
/*
* overview.js
* Copyright (c) 2022 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/>.
*/
import {api} from "../../../../boot/axios";
import {format} from "date-fns";
export default class Dashboard {
dashboard(start, end) {
let startStr = format(start, 'y-MM-dd');
let endStr = format(end, 'y-MM-dd');
return api.get('/api/v1/chart/category/dashboard', {params: {start: startStr, end: endStr}});
}
}

View File

@@ -18,7 +18,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import {api} from "../../../boot/axios";
import {api} from "../../../../boot/axios";
import format from "date-fns/format";
export default class Get {
@@ -37,6 +37,18 @@ export default class Get {
return api.get('/api/v1/accounts/' + identifier, {params: params});
}
/**
*
* @param identifier
* @param params
* @returns {Promise<AxiosResponse<any>>}
*/
show(identifier, params) {
return api.get('/api/v1/accounts/' + identifier, {params: params});
}
/**
*
* @param identifier

View File

@@ -0,0 +1,36 @@
/*
* list.js
* Copyright (c) 2022 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/>.
*/
import {api} from "../../../../boot/axios";
import format from "date-fns/format";
export default class Put {
/**
*
* @param identifier
* @param params
* @returns {Promise<AxiosResponse<any>>}
*/
put(identifier, params) {
return api.put('/api/v2/accounts/' + identifier, params);
}
}

View File

@@ -18,7 +18,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import {api} from "../../../boot/axios";
import {api} from "../../../../boot/axios";
export default class Post {
post(fileName, attachableType, attachableId) {

View File

@@ -0,0 +1,35 @@
/*
* list.js
* Copyright (c) 2022 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/>.
*/
import {api} from "../../../../boot/axios";
import format from "date-fns/format";
export default class Get {
/**
*
* @param params
* @returns {Promise<AxiosResponse<any>>}
*/
list(params) {
return api.get('/api/v2/budgets', {params: params});
}
}

View File

@@ -0,0 +1,35 @@
/*
* list.js
* Copyright (c) 2022 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/>.
*/
import {api} from "../../../../boot/axios";
import format from "date-fns/format";
export default class Get {
/**
*
* @param params
* @returns {Promise<AxiosResponse<any>>}
*/
list(params) {
return api.get('/api/v2/currencies', {params: params});
}
}

View File

@@ -0,0 +1,35 @@
/*
* get.js
* Copyright (c) 2023 james@firefly-iii.org
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import {api} from "../../../../boot/axios";
export default class Get {
/**
*
* @param params
* @returns {Promise<AxiosResponse<any>>}
*/
list(params) {
return api.get('/api/v1/piggy-banks', {params: params});
}
}

View File

@@ -0,0 +1,42 @@
/*
* get.js
* Copyright (c) 2023 james@firefly-iii.org
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import {api} from "../../../../boot/axios";
export default class Get {
/**
*
* @param params
* @returns {Promise<AxiosResponse<any>>}
*/
list(params) {
return api.get('/api/v1/subscriptions', {params: params});
}
paid(params) {
return api.get('/api/v1/subscriptions/sum/paid', {params: params});
}
unpaid(params) {
return api.get('/api/v1/subscriptions/sum/unpaid', {params: params});
}
}

View File

@@ -0,0 +1,37 @@
/*
* get.js
* Copyright (c) 2023 james@firefly-iii.org
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import {api} from "../../../../boot/axios";
export default class Get {
/**
*
* @param params
* @returns {Promise<AxiosResponse<any>>}
*/
list(params) {
return api.get('/api/v1/transactions', {params: params});
}
show(id, params){
return api.get('/api/v1/transactions/' + id, {params: params});
}
}

View File

@@ -0,0 +1,28 @@
/*
* post.js
* Copyright (c) 2023 james@firefly-iii.org
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import {api} from "../../../../boot/axios";
export default class Post {
post(submission) {
let url = '/api/v1/transactions';
return api.post(url, submission);
}
}

View File

@@ -0,0 +1,28 @@
/*
* post.js
* Copyright (c) 2023 james@firefly-iii.org
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import {api} from "../../../../boot/axios";
export default class Put {
put(submission, params) {
let url = '/api/v1/transactions/' + parseInt(params.id);
return api.put(url, submission);
}
}

View File

@@ -0,0 +1,45 @@
/*
* list.js
* Copyright (c) 2022 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/>.
*/
import {api} from "../../../../boot/axios";
import format from "date-fns/format";
export default class Get {
/**
*
* @param identifier
* @param params
* @returns {Promise<AxiosResponse<any>>}
*/
show(identifier, params) {
return api.get('/api/v2/user-groups/' + identifier, {params: params});
}
/**
*
* @param params
* @returns {Promise<AxiosResponse<any>>}
*/
index(params) {
return api.get('/api/v2/user-groups', {params: params});
}
}

View File

@@ -0,0 +1,33 @@
/*
* post.js
* Copyright (c) 2024 james@firefly-iii.org.
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see https://www.gnu.org/licenses/.
*/
import {api} from "../../../../boot/axios";
export default class Post {
post(submission) {
let url = './api/v2/user-groups';
return api.post(url, submission);
}
use(groupId) {
let url = './api/v2/user-groups/' + groupId + '/use';
return api.post(url, {});
}
}

View File

@@ -0,0 +1,28 @@
/*
* post.js
* Copyright (c) 2023 james@firefly-iii.org
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import {api} from "../../../../boot/axios";
export default class Put {
put(submission, params) {
let url = '/api/v2/user-groups/' + parseInt(params.id);
return api.put(url, submission);
}
}

View File

@@ -25,7 +25,7 @@ export default class Dashboard {
dashboard(start, end) {
let startStr = format(start, 'y-MM-dd');
let endStr = format(end, 'y-MM-dd');
return api.get('/api/v2/chart/account/dashboard', {params: {filter: {start: startStr, end: endStr}}});
return api.get('/api/v2/chart/account/dashboard', {params: {start: startStr, end: endStr}});
}
expense(start, end) {

View File

@@ -24,8 +24,8 @@ import i18next from "i18next";
import {format} from "date-fns";
import formatMoney from "../../util/format-money.js";
import Get from "../../api/v2/model/account/get.js";
import Put from "../../api/v2/model/account/put.js";
import Get from "../../api/v1/model/account/get.js";
import Put from "../../api/v1/model/account/put.js";
import AccountRenderer from "../../support/renderers/AccountRenderer.js";
import {showInternalsButton} from "../../support/page-settings/show-internals-button.js";
import {showWizardButton} from "../../support/page-settings/show-wizard-button.js";

View File

@@ -20,7 +20,7 @@
import '../../boot/bootstrap.js';
import dates from "../shared/dates.js";
import Post from "../../api/v2/model/user-group/post.js";
import Post from "../../api/v1/model/user-group/post.js";
import i18next from "i18next";

View File

@@ -20,10 +20,10 @@
import '../../boot/bootstrap.js';
import dates from "../shared/dates.js";
import Post from "../../api/v2/model/user-group/post.js";
import Post from "../../api/v1/model/user-group/post.js";
import i18next from "i18next";
import Get from "../../api/v2/model/user-group/get.js";
import Put from "../../api/v2/model/user-group/put.js";
import Get from "../../api/v1/model/user-group/get.js";
import Put from "../../api/v1/model/user-group/put.js";
let administrations = function () {

View File

@@ -23,11 +23,9 @@ import dates from "../shared/dates.js";
import i18next from "i18next";
import {format} from "date-fns";
import '@ag-grid-community/styles/ag-grid.css';
import '@ag-grid-community/styles/ag-theme-alpine.css';
import '../../css/grid-ff3-theme.css';
import Get from "../../api/v2/model/user-group/get.js";
import Post from "../../api/v2/model/user-group/post.js";
import Get from "../../api/v1/model/user-group/get.js";
import Post from "../../api/v1/model/user-group/post.js";
let index = function () {
return {

View File

@@ -20,9 +20,9 @@
import {getVariable} from "../../store/get-variable.js";
import {setVariable} from "../../store/set-variable.js";
import Dashboard from "../../api/v2/chart/account/dashboard.js";
import Dashboard from "../../api/v1/chart/account/dashboard.js";
import formatMoney from "../../util/format-money.js";
import Get from "../../api/v2/model/account/get.js";
import Get from "../../api/v1/model/account/get.js";
import {Chart} from 'chart.js';
import {getDefaultChartSettings} from "../../support/default-chart-settings.js";
import {getCacheKey} from "../../support/get-cache-key.js";
@@ -39,12 +39,12 @@ export default () => ({
loading: false,
loadingAccounts: false,
accountList: [],
autoConversion: false,
autoConversionAvailable: false,
convertToNative: false,
convertToNativeAvailable: false,
chartOptions: null,
switchAutoConversion() {
this.autoConversion = !this.autoConversion;
setVariable('autoConversion', this.autoConversion);
switchConvertToNative() {
this.convertToNative = !this.convertToNative;
setVariable('convertToNative', this.convertToNative);
},
localCacheKey(type) {
return 'ds_accounts_' + type;
@@ -90,18 +90,18 @@ export default () => ({
dataset.label = current.label;
// use the "native" currency code and use the "native_entries" as array
if (this.autoConversion) {
currencies.push(current.native_currency_code);
dataset.currency_code = current.native_currency_code;
collection = Object.values(current.native_entries);
yAxis = 'y' + current.native_currency_code;
}
if (!this.autoConversion) {
// if (this.convertToNative) {
// currencies.push(current.native_currency_code);
// dataset.currency_code = current.native_currency_code;
// collection = Object.values(current.native_entries);
// yAxis = 'y' + current.native_currency_code;
// }
// if (!this.convertToNative) {
yAxis = 'y' + current.currency_code;
dataset.currency_code = current.currency_code;
currencies.push(current.currency_code);
collection = Object.values(current.entries);
}
// }
dataset.yAxisID = yAxis;
dataset.data = collection;
@@ -217,12 +217,12 @@ export default () => ({
for (let iii = 0; iii < current.attributes.transactions.length; iii++) {
let currentTransaction = current.attributes.transactions[iii];
//console.log(currentTransaction);
let nativeAmountRaw = 'withdrawal' === currentTransaction.type ? parseFloat(currentTransaction.native_amount) * -1 : parseFloat(currentTransaction.native_amount);
//let nativeAmountRaw = 'withdrawal' === currentTransaction.type ? parseFloat(currentTransaction.native_amount) * -1 : parseFloat(currentTransaction.native_amount);
let amountRaw = 'withdrawal' === currentTransaction.type ? parseFloat(currentTransaction.amount) * -1 : parseFloat(currentTransaction.amount);
// if transfer and source is this account, multiply again
if('transfer' === currentTransaction.type && parseInt(currentTransaction.source_id) === accountId) { //
nativeAmountRaw = nativeAmountRaw * -1;
// nativeAmountRaw = nativeAmountRaw * -1;
amountRaw = amountRaw * -1;
}
@@ -232,8 +232,8 @@ export default () => ({
type: currentTransaction.type,
amount_raw: amountRaw,
amount: formatMoney(amountRaw, currentTransaction.currency_code),
native_amount_raw: nativeAmountRaw,
native_amount: formatMoney(nativeAmountRaw, currentTransaction.native_currency_code),
// native_amount_raw: nativeAmountRaw,
// native_amount: formatMoney(nativeAmountRaw, currentTransaction.native_currency_code),
});
}
groups.push(group);
@@ -244,7 +244,7 @@ export default () => ({
order: parent.attributes.order,
id: parent.id,
balance: parent.attributes.balance,
native_balance: parent.attributes.native_balance,
//native_balance: parent.attributes.native_balance,
groups: groups,
});
// console.log(parent.attributes);
@@ -266,12 +266,12 @@ export default () => ({
init() {
// console.log('accounts init');
Promise.all([getVariable('viewRange', '1M'), getVariable('autoConversion', false), getVariable('language', 'en_US'),
Promise.all([getVariable('viewRange', '1M'), getVariable('convertToNative', false), getVariable('language', 'en_US'),
getConfiguration('cer.enabled', false)
]).then((values) => {
//console.log('accounts after promises');
this.autoConversion = values[1] && values[3];
this.autoConversionAvailable = values[3];
this.convertToNative = values[1] && values[3];
this.convertToNativeAvailable = values[3];
afterPromises = true;
// main dashboard chart:
@@ -289,11 +289,11 @@ export default () => ({
this.loadChart();
this.loadAccounts();
});
window.store.observe('autoConversion', () => {
window.store.observe('convertToNative', () => {
if (!afterPromises) {
return;
}
// console.log('accounts observe autoconversion');
// console.log('accounts observe convertToNative');
this.loadChart();
this.loadAccounts();
});

View File

@@ -18,7 +18,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import Summary from "../../api/v2/summary/index.js";
import Summary from "../../api/v1/summary/index.js";
import {format} from "date-fns";
import {getVariable} from "../../store/get-variable.js";
import formatMoney from "../../util/format-money.js";
@@ -31,7 +31,7 @@ export default () => ({
billBox: {paid: [], unpaid: []},
leftBox: {left: [], perDay: []},
netBox: {net: []},
autoConversion: false,
convertToNative: false,
loading: false,
boxData: null,
boxOptions: null,
@@ -42,8 +42,9 @@ export default () => ({
const boxesCacheKey = getCacheKey('ds_boxes_data', {start: start, end: end});
cleanupCache();
const cacheValid = window.store.get('cacheValid');
//const cacheValid = window.store.get('cacheValid');
let cachedData = window.store.get(boxesCacheKey);
const cacheValid = false; // force refresh
if (cacheValid && typeof cachedData !== 'undefined') {
this.boxData = cachedData;
@@ -75,114 +76,56 @@ export default () => ({
continue;
}
let key = current.key;
// native (auto conversion):
if (this.autoConversion) {
if (key.startsWith('balance-in-native')) {
this.balanceBox.amounts.push(formatMoney(current.value, current.currency_code));
// prep subtitles (for later)
if (!subtitles.hasOwnProperty(current.currency_code)) {
subtitles[current.currency_code] = '';
}
continue;
}
// spent info is used in subtitle:
if (key.startsWith('spent-in-native')) {
// prep subtitles (for later)
if (!subtitles.hasOwnProperty(current.currency_code)) {
subtitles[current.currency_code] = '';
}
// append the amount spent.
subtitles[current.currency_code] =
subtitles[current.currency_code] +
formatMoney(current.value, current.currency_code);
continue;
}
// earned info is used in subtitle:
if (key.startsWith('earned-in-native')) {
// prep subtitles (for later)
if (!subtitles.hasOwnProperty(current.currency_code)) {
subtitles[current.currency_code] = '';
}
// prepend the amount earned.
subtitles[current.currency_code] =
formatMoney(current.value, current.currency_code) + ' + ' +
subtitles[current.currency_code];
continue;
}
if (key.startsWith('bills-unpaid-in-native')) {
this.billBox.unpaid.push(formatMoney(current.value, current.currency_code));
continue;
}
if (key.startsWith('bills-paid-in-native')) {
this.billBox.paid.push(formatMoney(current.value, current.currency_code));
continue;
}
if (key.startsWith('left-to-spend-in-native')) {
this.leftBox.left.push(formatMoney(current.value, current.currency_code));
continue;
}
if (key.startsWith('left-per-day-to-spend-in-native')) { // per day
this.leftBox.perDay.push(formatMoney(current.value, current.currency_code));
continue;
}
if (key.startsWith('net-worth-in-native')) {
this.netBox.net.push(formatMoney(current.value, current.currency_code));
continue;
}
console.log('NOT NATIVE');
if (key.startsWith('balance-in-')) {
this.balanceBox.amounts.push(formatMoney(current.monetary_value, current.currency_code));
continue;
}
// not native
if (!this.autoConversion && !key.endsWith('native')) {
if (key.startsWith('balance-in-')) {
this.balanceBox.amounts.push(formatMoney(current.value, current.currency_code));
continue;
// spent info is used in subtitle:
if (key.startsWith('spent-in-')) {
// prep subtitles (for later)
if (!subtitles.hasOwnProperty(current.currency_code)) {
subtitles[current.currency_code] = '';
}
// spent info is used in subtitle:
if (key.startsWith('spent-in-')) {
// prep subtitles (for later)
if (!subtitles.hasOwnProperty(current.currency_code)) {
subtitles[current.currency_code] = '';
}
// append the amount spent.
subtitles[current.currency_code] =
subtitles[current.currency_code] +
formatMoney(current.value, current.currency_code);
continue;
}
// earned info is used in subtitle:
if (key.startsWith('earned-in-')) {
// prep subtitles (for later)
if (!subtitles.hasOwnProperty(current.currency_code)) {
subtitles[current.currency_code] = '';
}
// prepend the amount earned.
subtitles[current.currency_code] =
formatMoney(current.value, current.currency_code) + ' + ' +
subtitles[current.currency_code];
continue;
// append the amount spent.
subtitles[current.currency_code] =
subtitles[current.currency_code] +
formatMoney(current.monetary_value, current.currency_code);
continue;
}
// earned info is used in subtitle:
if (key.startsWith('earned-in-')) {
// prep subtitles (for later)
if (!subtitles.hasOwnProperty(current.currency_code)) {
subtitles[current.currency_code] = '';
}
// prepend the amount earned.
subtitles[current.currency_code] =
formatMoney(current.monetary_value, current.currency_code) + ' + ' +
subtitles[current.currency_code];
continue;
}
if (key.startsWith('bills-unpaid-in-')) {
this.billBox.unpaid.push(formatMoney(current.value, current.currency_code));
continue;
}
if (key.startsWith('bills-paid-in-')) {
this.billBox.paid.push(formatMoney(current.value, current.currency_code));
continue;
}
if (key.startsWith('left-to-spend-in-')) {
this.leftBox.left.push(formatMoney(current.value, current.currency_code));
continue;
}
if (key.startsWith('left-per-day-to-spend-in-')) {
this.leftBox.perDay.push(formatMoney(current.value, current.currency_code));
continue;
}
if (key.startsWith('net-worth-in-')) {
this.netBox.net.push(formatMoney(current.value, current.currency_code));
if (key.startsWith('bills-unpaid-in-')) {
this.billBox.unpaid.push(formatMoney(current.monetary_value, current.currency_code));
continue;
}
if (key.startsWith('bills-paid-in-')) {
this.billBox.paid.push(formatMoney(current.monetary_value, current.currency_code));
continue;
}
if (key.startsWith('left-to-spend-in-')) {
this.leftBox.left.push(formatMoney(current.monetary_value, current.currency_code));
continue;
}
if (key.startsWith('left-per-day-to-spend-in-')) {
this.leftBox.perDay.push(formatMoney(current.monetary_value, current.currency_code));
continue;
}
if (key.startsWith('net-worth-in-')) {
this.netBox.net.push(formatMoney(current.monetary_value, current.currency_code));
}
}
}
}
@@ -210,10 +153,10 @@ export default () => ({
init() {
// console.log('boxes init');
// TODO can be replaced by "getVariables"
Promise.all([getVariable('viewRange'), getVariable('autoConversion', false)]).then((values) => {
Promise.all([getVariable('viewRange'), getVariable('convertToNative', false)]).then((values) => {
// console.log('boxes after promises');
afterPromises = true;
this.autoConversion = values[1];
this.convertToNative = values[1];
this.loadBoxes();
});
window.store.observe('end', () => {
@@ -224,12 +167,12 @@ export default () => ({
this.boxData = null;
this.loadBoxes();
});
window.store.observe('autoConversion', (newValue) => {
window.store.observe('convertToNative', (newValue) => {
if (!afterPromises) {
return;
}
// console.log('boxes observe autoConversion');
this.autoConversion = newValue;
// console.log('boxes observe convertToNative');
this.convertToNative = newValue;
this.loadBoxes();
});
},

View File

@@ -18,7 +18,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import {getVariable} from "../../store/get-variable.js";
import Dashboard from "../../api/v2/chart/budget/dashboard.js";
import Dashboard from "../../api/v1/chart/budget/dashboard.js";
import {getDefaultChartSettings} from "../../support/default-chart-settings.js";
import formatMoney from "../../util/format-money.js";
import {Chart} from 'chart.js';
@@ -34,7 +34,7 @@ let afterPromises = false;
export default () => ({
loading: false,
autoConversion: false,
convertToNative: false,
loadChart() {
if (true === this.loading) {
return;
@@ -134,7 +134,7 @@ export default () => ({
// // convert to EUR yes no?
let label = current.label + ' (' + current.currency_code + ')';
options.data.labels.push(label);
if (this.autoConversion) {
if (this.convertToNative) {
currencies.push(current.native_currency_code);
// series 0: spent
options.data.datasets[0].data.push(parseFloat(current.native_entries.spent) * -1);
@@ -143,7 +143,7 @@ export default () => ({
// series 2: overspent
options.data.datasets[2].data.push(parseFloat(current.native_entries.overspent));
}
if (!this.autoConversion) {
if (!this.convertToNative) {
currencies.push(current.currency_code);
// series 0: spent
options.data.datasets[0].data.push(parseFloat(current.entries.spent) * -1);
@@ -172,8 +172,8 @@ export default () => ({
init() {
Promise.all([getVariable('autoConversion', false)]).then((values) => {
this.autoConversion = values[0];
Promise.all([getVariable('convertToNative', false)]).then((values) => {
this.convertToNative = values[0];
afterPromises = true;
if (false === this.loading) {
this.loadChart();
@@ -189,12 +189,12 @@ export default () => ({
this.loadChart();
}
});
window.store.observe('autoConversion', (newValue) => {
window.store.observe('convertToNative', (newValue) => {
if (!afterPromises) {
return;
}
// console.log('boxes observe autoConversion');
this.autoConversion = newValue;
// console.log('boxes observe convertToNative');
this.convertToNative = newValue;
if (false === this.loading) {
this.loadChart();
}

View File

@@ -18,7 +18,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import {getVariable} from "../../store/get-variable.js";
import Dashboard from "../../api/v2/chart/category/dashboard.js";
import Dashboard from "../../api/v1/chart/category/dashboard.js";
import {getDefaultChartSettings} from "../../support/default-chart-settings.js";
import {Chart} from "chart.js";
import formatMoney from "../../util/format-money.js";
@@ -32,7 +32,7 @@ let afterPromises = false;
export default () => ({
loading: false,
autoConversion: false,
convertToNative: false,
generateOptions(data) {
currencies = [];
let options = getDefaultChartSettings('column');
@@ -44,7 +44,7 @@ export default () => ({
let current = data[i];
let code = current.currency_code;
// only use native code when doing auto conversion.
if (this.autoConversion) {
if (this.convertToNative) {
code = current.native_currency_code;
}
@@ -65,7 +65,7 @@ export default () => ({
let yAxis = 'y';
let current = data[i];
let code = current.currency_code;
if (this.autoConversion) {
if (this.convertToNative) {
code = current.native_currency_code;
}
@@ -77,7 +77,7 @@ export default () => ({
// this series' currency matches this column's currency.
amount = parseFloat(current.amount);
yAxis = 'y' + current.currency_code;
if (this.autoConversion) {
if (this.convertToNative) {
amount = parseFloat(current.native_amount);
yAxis = 'y' + current.native_currency_code;
}
@@ -183,8 +183,8 @@ export default () => ({
},
init() {
// console.log('categories init');
Promise.all([getVariable('autoConversion', false),]).then((values) => {
this.autoConversion = values[0];
Promise.all([getVariable('convertToNative', false),]).then((values) => {
this.convertToNative = values[0];
afterPromises = true;
this.loadChart();
});
@@ -195,11 +195,11 @@ export default () => ({
this.chartData = null;
this.loadChart();
});
window.store.observe('autoConversion', (newValue) => {
window.store.observe('convertToNative', (newValue) => {
if (!afterPromises) {
return;
}
this.autoConversion = newValue;
this.convertToNative = newValue;
this.loadChart();
});
},

View File

@@ -18,7 +18,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import {getVariable} from "../../store/get-variable.js";
import Get from "../../api/v2/model/piggy-bank/get.js";
import Get from "../../api/v1/model/piggy-bank/get.js";
import {getCacheKey} from "../../support/get-cache-key.js";
import {format} from "date-fns";
import i18next from "i18next";
@@ -29,7 +29,7 @@ const PIGGY_CACHE_KEY = 'ds_pg_data';
export default () => ({
loading: false,
autoConversion: false,
convertToNative: false,
sankeyGrouping: 'account',
piggies: [],
getFreshData() {
@@ -96,14 +96,14 @@ export default () => ({
id: current.id,
name: current.attributes.name,
percentage: parseInt(current.attributes.percentage),
amount: this.autoConversion ? current.attributes.native_current_amount : current.attributes.current_amount,
amount: this.convertToNative ? current.attributes.native_current_amount : current.attributes.current_amount,
// left to save
left_to_save: this.autoConversion ? current.attributes.native_left_to_save : current.attributes.left_to_save,
left_to_save: this.convertToNative ? current.attributes.native_left_to_save : current.attributes.left_to_save,
// target amount
target_amount: this.autoConversion ? current.attributes.native_target_amount : current.attributes.target_amount,
target_amount: this.convertToNative ? current.attributes.native_target_amount : current.attributes.target_amount,
// save per month
save_per_month: this.autoConversion ? current.attributes.native_save_per_month : current.attributes.save_per_month,
currency_code: this.autoConversion ? current.attributes.native_currency_code : current.attributes.currency_code,
save_per_month: this.convertToNative ? current.attributes.native_save_per_month : current.attributes.save_per_month,
currency_code: this.convertToNative ? current.attributes.native_currency_code : current.attributes.currency_code,
};
dataSet[groupName].piggies.push(piggy);
@@ -129,10 +129,10 @@ export default () => ({
init() {
// console.log('piggies init');
apiData = [];
Promise.all([getVariable('autoConversion', false)]).then((values) => {
Promise.all([getVariable('convertToNative', false)]).then((values) => {
afterPromises = true;
this.autoConversion = values[0];
this.convertToNative = values[0];
this.loadPiggyBanks();
});
@@ -144,12 +144,12 @@ export default () => ({
apiData = [];
this.loadPiggyBanks();
});
window.store.observe('autoConversion', (newValue) => {
window.store.observe('convertToNative', (newValue) => {
if (!afterPromises) {
return;
}
// console.log('piggies observe autoConversion');
this.autoConversion = newValue;
// console.log('piggies observe convertToNative');
this.convertToNative = newValue;
this.loadPiggyBanks();
});
},

View File

@@ -18,7 +18,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import {getVariable} from "../../store/get-variable.js";
import Get from "../../api/v2/model/transaction/get.js";
import Get from "../../api/v1/model/transaction/get.js";
import {getDefaultChartSettings} from "../../support/default-chart-settings.js";
import {Chart} from 'chart.js';
import {Flow, SankeyController} from 'chartjs-chart-sankey';
@@ -33,7 +33,7 @@ let currencies = [];
let afterPromises = false;
let chart = null;
let transactions = [];
let autoConversion = false;
let convertToNative = false;
let translations = {
category: null,
unknown_category: null,
@@ -83,37 +83,37 @@ function getObjectName(type, name, direction, code) {
// category 4x
if ('category' === type && null !== name && 'in' === direction) {
return translations.category + ' "' + name + '" (' + translations.in + (autoConversion ? ', ' + code + ')' : ')');
return translations.category + ' "' + name + '" (' + translations.in + (convertToNative ? ', ' + code + ')' : ')');
}
if ('category' === type && null === name && 'in' === direction) {
return translations.unknown_category + ' (' + translations.in + (autoConversion ? ', ' + code + ')' : ')');
return translations.unknown_category + ' (' + translations.in + (convertToNative ? ', ' + code + ')' : ')');
}
if ('category' === type && null !== name && 'out' === direction) {
return translations.category + ' "' + name + '" (' + translations.out + (autoConversion ? ', ' + code + ')' : ')');
return translations.category + ' "' + name + '" (' + translations.out + (convertToNative ? ', ' + code + ')' : ')');
}
if ('category' === type && null === name && 'out' === direction) {
return translations.unknown_category + ' (' + translations.out + (autoConversion ? ', ' + code + ')' : ')');
return translations.unknown_category + ' (' + translations.out + (convertToNative ? ', ' + code + ')' : ')');
}
// account 4x
if ('account' === type && null === name && 'in' === direction) {
return translations.unknown_source + (autoConversion ? ' (' + code + ')' : '');
return translations.unknown_source + (convertToNative ? ' (' + code + ')' : '');
}
if ('account' === type && null !== name && 'in' === direction) {
return translations.revenue_account + '"' + name + '"' + (autoConversion ? ' (' + code + ')' : '');
return translations.revenue_account + '"' + name + '"' + (convertToNative ? ' (' + code + ')' : '');
}
if ('account' === type && null === name && 'out' === direction) {
return translations.unknown_dest + (autoConversion ? ' (' + code + ')' : '');
return translations.unknown_dest + (convertToNative ? ' (' + code + ')' : '');
}
if ('account' === type && null !== name && 'out' === direction) {
return translations.expense_account + ' "' + name + '"' + (autoConversion ? ' (' + code + ')' : '');
return translations.expense_account + ' "' + name + '"' + (convertToNative ? ' (' + code + ')' : '');
}
// budget 2x
if ('budget' === type && null !== name) {
return translations.budget + ' "' + name + '"' + (autoConversion ? ' (' + code + ')' : '');
return translations.budget + ' "' + name + '"' + (convertToNative ? ' (' + code + ')' : '');
}
if ('budget' === type && null === name) {
return translations.unknown_budget + (autoConversion ? ' (' + code + ')' : '');
return translations.unknown_budget + (convertToNative ? ' (' + code + ')' : '');
}
console.error('Cannot handle: type:"' + type + '", dir: "' + direction + '"');
}
@@ -121,25 +121,25 @@ function getObjectName(type, name, direction, code) {
function getLabelName(type, name, code) {
// category
if ('category' === type && null !== name) {
return translations.category + ' "' + name + '"' + (autoConversion ? ' (' + code + ')' : '');
return translations.category + ' "' + name + '"' + (convertToNative ? ' (' + code + ')' : '');
}
if ('category' === type && null === name) {
return translations.unknown_category + (autoConversion ? ' (' + code + ')' : '');
return translations.unknown_category + (convertToNative ? ' (' + code + ')' : '');
}
// account
if ('account' === type && null === name) {
return translations.unknown_account + (autoConversion ? ' (' + code + ')' : '');
return translations.unknown_account + (convertToNative ? ' (' + code + ')' : '');
}
if ('account' === type && null !== name) {
return name + (autoConversion ? ' (' + code + ')' : '');
return name + (convertToNative ? ' (' + code + ')' : '');
}
// budget 2x
if ('budget' === type && null !== name) {
return translations.budget + ' "' + name + '"' + (autoConversion ? ' (' + code + ')' : '');
return translations.budget + ' "' + name + '"' + (convertToNative ? ' (' + code + ')' : '');
}
if ('budget' === type && null === name) {
return translations.unknown_budget + (autoConversion ? ' (' + code + ')' : '');
return translations.unknown_budget + (convertToNative ? ' (' + code + ')' : '');
}
console.error('Cannot handle: type:"' + type + '"');
}
@@ -147,7 +147,7 @@ function getLabelName(type, name, code) {
export default () => ({
loading: false,
autoConversion: false,
convertToNative: false,
generateOptions() {
let options = getDefaultChartSettings('sankey');
@@ -164,8 +164,8 @@ export default () => ({
if (group.attributes.transactions.hasOwnProperty(ii)) {
// properties of the transaction, used in the generation of the chart:
let transaction = group.attributes.transactions[ii];
let currencyCode = this.autoConversion ? transaction.native_currency_code : transaction.currency_code;
let amount = this.autoConversion ? parseFloat(transaction.native_amount) : parseFloat(transaction.amount);
let currencyCode = this.convertToNative ? transaction.native_currency_code : transaction.currency_code;
let amount = this.convertToNative ? parseFloat(transaction.native_amount) : parseFloat(transaction.amount);
let flowKey;
/*
@@ -194,7 +194,7 @@ export default () => ({
if (!amounts.hasOwnProperty(flowKey)) {
amounts[flowKey] = {
from: category,
to: translations.all_money + (this.autoConversion ? ' (' + currencyCode + ')' : ''),
to: translations.all_money + (this.convertToNative ? ' (' + currencyCode + ')' : ''),
amount: 0
};
}
@@ -214,7 +214,7 @@ export default () => ({
if (!amounts.hasOwnProperty(flowKey)) {
amounts[flowKey] = {
from: translations.all_money + (this.autoConversion ? ' (' + currencyCode + ')' : ''),
from: translations.all_money + (this.convertToNative ? ' (' + currencyCode + ')' : ''),
to: budget,
amount: 0
};
@@ -348,9 +348,9 @@ export default () => ({
init() {
// console.log('sankey init');
transactions = [];
Promise.all([getVariable('autoConversion', false)]).then((values) => {
this.autoConversion = values[0];
autoConversion = values[0];
Promise.all([getVariable('convertToNative', false)]).then((values) => {
this.convertToNative = values[0];
convertToNative = values[0];
// some translations:
translations.all_money = i18next.t('firefly.all_money');
translations.category = i18next.t('firefly.category');
@@ -378,12 +378,12 @@ export default () => ({
this.transactions = [];
this.loadChart();
});
window.store.observe('autoConversion', (newValue) => {
window.store.observe('convertToNative', (newValue) => {
if (!afterPromises) {
return;
}
// console.log('sankey observe autoConversion');
this.autoConversion = newValue;
// console.log('sankey observe convertToNative');
this.convertToNative = newValue;
this.loadChart();
});
},

View File

@@ -18,7 +18,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import {getVariable} from "../../store/get-variable.js";
import Get from "../../api/v2/model/subscription/get.js";
import Get from "../../api/v1/model/subscription/get.js";
import {format} from "date-fns";
import {getCacheKey} from "../../support/get-cache-key.js";
import {Chart} from "chart.js";
@@ -66,10 +66,10 @@ function downloadSubscriptions(params) {
currency_code: current.attributes.currency_code,
// native amount
native_amount_min: current.attributes.native_amount_min,
native_amount_max: current.attributes.native_amount_max,
native_amount: (parseFloat(current.attributes.native_amount_max) + parseFloat(current.attributes.native_amount_min)) / 2,
native_currency_code: current.attributes.native_currency_code,
// native_amount_min: current.attributes.native_amount_min,
// native_amount_max: current.attributes.native_amount_max,
// native_amount: (parseFloat(current.attributes.native_amount_max) + parseFloat(current.attributes.native_amount_min)) / 2,
// native_currency_code: current.attributes.native_currency_code,
// paid transactions:
transactions: [],
@@ -79,8 +79,7 @@ function downloadSubscriptions(params) {
paid: current.attributes.paid_dates.length > 0,
};
// set variables
bill.expected_amount = params.autoConversion ? formatMoney(bill.native_amount, bill.native_currency_code) :
formatMoney(bill.amount, bill.currency_code);
bill.expected_amount = formatMoney(bill.amount, bill.currency_code);
bill.expected_times = i18next.t('firefly.subscr_expected_x_times', {
times: current.attributes.pay_dates.length,
amount: bill.expected_amount
@@ -92,22 +91,25 @@ function downloadSubscriptions(params) {
const currentPayment = current.attributes.paid_dates[iii];
let percentage = 100;
// math: -100+(paid/expected)*100
if (params.autoConversion) {
if (params.convertToNative) {
percentage = Math.round(-100 + ((parseFloat(currentPayment.native_amount) * -1) / parseFloat(bill.native_amount)) * 100);
}
if (!params.autoConversion) {
if (!params.convertToNative) {
percentage = Math.round(-100 + ((parseFloat(currentPayment.amount) * -1) / parseFloat(bill.amount)) * 100);
}
// TODO fix me
currentPayment.currency_code = 'EUR';
console.log('Currency code: "'+currentPayment+'"');
console.log(currentPayment);
let currentTransaction = {
amount: params.autoConversion ? formatMoney(currentPayment.native_amount, currentPayment.native_currency_code) : formatMoney(currentPayment.amount, currentPayment.currency_code),
amount: formatMoney(currentPayment.amount, currentPayment.currency_code),
percentage: percentage,
date: format(new Date(currentPayment.date), 'PP'),
foreign_amount: null,
};
if (null !== currentPayment.foreign_currency_code) {
currentTransaction.foreign_amount = params.autoConversion ? currentPayment.foreign_native_amount : currentPayment.foreign_amount;
currentTransaction.foreign_currency_code = params.autoConversion ? currentPayment.native_currency_code : currentPayment.foreign_currency_code;
currentTransaction.foreign_amount = currentPayment.foreign_amount;
currentTransaction.foreign_currency_code = currentPayment.foreign_currency_code;
}
bill.transactions.push(currentTransaction);
@@ -119,7 +121,7 @@ function downloadSubscriptions(params) {
// bill is unpaid, count the "pay_dates" and multiply with the "amount".
// since bill is unpaid, this can only be in currency amount and native currency amount.
const totalAmount = current.attributes.pay_dates.length * bill.amount;
const totalNativeAmount = current.attributes.pay_dates.length * bill.native_amount;
// const totalNativeAmount = current.attributes.pay_dates.length * bill.native_amount;
// for bill's currency
if (!subscriptionData[objectGroupId].payment_info.hasOwnProperty(bill.currency_code)) {
subscriptionData[objectGroupId].payment_info[bill.currency_code] = {
@@ -128,11 +130,11 @@ function downloadSubscriptions(params) {
unpaid: 0,
native_currency_code: bill.native_currency_code,
native_paid: 0,
native_unpaid: 0,
//native_unpaid: 0,
};
}
subscriptionData[objectGroupId].payment_info[bill.currency_code].unpaid += totalAmount;
subscriptionData[objectGroupId].payment_info[bill.currency_code].native_unpaid += totalNativeAmount;
//subscriptionData[objectGroupId].payment_info[bill.currency_code].native_unpaid += totalNativeAmount;
}
if (current.attributes.paid_dates.length > 0) {
@@ -149,15 +151,15 @@ function downloadSubscriptions(params) {
currency_code: bill.currency_code,
paid: 0,
unpaid: 0,
native_currency_code: bill.native_currency_code,
native_paid: 0,
native_unpaid: 0,
// native_currency_code: bill.native_currency_code,
// native_paid: 0,
//native_unpaid: 0,
};
}
const amount = parseFloat(currentJournal.amount) * -1;
const nativeAmount = parseFloat(currentJournal.native_amount) * -1;
// const nativeAmount = parseFloat(currentJournal.native_amount) * -1;
subscriptionData[objectGroupId].payment_info[currentJournal.currency_code].paid += amount;
subscriptionData[objectGroupId].payment_info[currentJournal.currency_code].native_paid += nativeAmount;
// subscriptionData[objectGroupId].payment_info[currentJournal.currency_code].native_paid += nativeAmount;
}
}
}
@@ -178,7 +180,7 @@ function downloadSubscriptions(params) {
export default () => ({
loading: false,
autoConversion: false,
convertToNative: false,
subscriptions: [],
startSubscriptions() {
this.loading = true;
@@ -198,7 +200,7 @@ export default () => ({
let params = {
start: format(start, 'y-MM-dd'),
end: format(end, 'y-MM-dd'),
autoConversion: this.autoConversion,
// convertToNative: this.convertToNative,
page: 1
};
downloadSubscriptions(params).then(() => {
@@ -226,9 +228,9 @@ export default () => ({
drawPieChart(groupId, groupTitle, data) {
let id = '#pie_' + groupId + '_' + data.currency_code;
//console.log(data);
const unpaidAmount = this.autoConversion ? data.native_unpaid : data.unpaid;
const paidAmount = this.autoConversion ? data.native_paid : data.paid;
const currencyCode = this.autoConversion ? data.native_currency_code : data.currency_code;
const unpaidAmount = data.unpaid;
const paidAmount = data.paid;
const currencyCode = data.currency_code;
const chartData = {
labels: [
i18next.t('firefly.paid'),
@@ -267,8 +269,8 @@ export default () => ({
},
init() {
Promise.all([getVariable('autoConversion', false)]).then((values) => {
this.autoConversion = values[0];
Promise.all([getVariable('convertToNative', false)]).then((values) => {
this.convertToNative = values[0];
afterPromises = true;
if (false === this.loading) {
@@ -285,11 +287,11 @@ export default () => ({
this.startSubscriptions();
}
});
window.store.observe('autoConversion', (newValue) => {
window.store.observe('convertToNative', (newValue) => {
if (!afterPromises) {
return;
}
this.autoConversion = newValue;
this.convertToNative = newValue;
if (false === this.loading) {
this.startSubscriptions();
}

View File

@@ -23,7 +23,7 @@ import dates from '../../pages/shared/dates.js';
import {createEmptySplit, defaultErrorSet} from "./shared/create-empty-split.js";
import {parseFromEntries} from "./shared/parse-from-entries.js";
import formatMoney from "../../util/format-money.js";
import Post from "../../api/v2/model/transaction/post.js";
import Post from "../../api/v1/model/transaction/post.js";
import {loadCurrencies} from "./shared/load-currencies.js";
import {loadBudgets} from "./shared/load-budgets.js";
import {loadPiggyBanks} from "./shared/load-piggy-banks.js";

View File

@@ -21,7 +21,7 @@
import '../../boot/bootstrap.js';
import dates from '../../pages/shared/dates.js';
import formatMoney from "../../util/format-money.js";
import Get from "../../api/v2/model/transaction/get.js";
import Get from "../../api/v1/model/transaction/get.js";
import {parseDownloadedSplits} from "./shared/parse-downloaded-splits.js";
import {addAutocomplete, getUrls} from "./shared/add-autocomplete.js";
import {
@@ -40,7 +40,7 @@ import Tags from "bootstrap5-tags";
import i18next from "i18next";
import {defaultErrorSet} from "./shared/create-empty-split.js";
import {parseFromEntries} from "./shared/parse-from-entries.js";
import Put from "../../api/v2/model/transaction/put.js";
import Put from "../../api/v1/model/transaction/put.js";
import {processAttachments} from "./shared/process-attachments.js";
import {spliceErrorsIntoTransactions} from "./shared/splice-errors-into-transactions.js";

View File

@@ -24,10 +24,8 @@ import i18next from "i18next";
import {format} from "date-fns";
import formatMoney from "../../util/format-money.js";
import '@ag-grid-community/styles/ag-grid.css';
import '@ag-grid-community/styles/ag-theme-alpine.css';
import '../../css/grid-ff3-theme.css';
import Get from "../../api/v2/model/transaction/get.js";
import Get from "../../api/v1/model/transaction/get.js";
let index = function () {
return {

View File

@@ -22,10 +22,10 @@ import Autocomplete from "bootstrap5-autocomplete";
export function getUrls() {
return {
description: '/api/v2/autocomplete/transaction-descriptions',
account: '/api/v2/autocomplete/accounts',
category: '/api/v2/autocomplete/categories',
tag: '/api/v2/autocomplete/tags',
description: '/api/v1/autocomplete/transaction-descriptions',
account: '/api/v1/autocomplete/accounts',
category: '/api/v1/autocomplete/categories',
tag: '/api/v1/autocomplete/tags',
}
}

View File

@@ -19,7 +19,7 @@
*/
import Get from "../../../api/v2/model/budget/get.js";
import Get from "../../../api/v1/model/budget/get.js";
export function loadBudgets() {
let params = {

View File

@@ -19,7 +19,7 @@
*/
import Get from "../../../api/v2/model/currency/get.js";
import Get from "../../../api/v1/model/currency/get.js";
export function loadCurrencies() {
let params = {

View File

@@ -18,7 +18,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import Get from "../../../api/v2/model/piggy-bank/get.js";
import Get from "../../../api/v1/model/piggy-bank/get.js";
export function loadPiggyBanks() {
let params = {

View File

@@ -18,7 +18,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import SubscriptionGet from "../../../api/v2/model/subscription/get.js";
import SubscriptionGet from "../../../api/v1/model/subscription/get.js";
export function loadSubscriptions() {
let params = {

View File

@@ -18,7 +18,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import AttachmentPost from "../../../api/v1/attachments/post.js";
import AttachmentPost from "../../../api/v1/model/attachment/post.js";
let uploadFiles = function (fileData) {
let count = fileData.length;

View File

@@ -21,7 +21,7 @@
import '../../boot/bootstrap.js';
import dates from "../shared/dates.js";
import i18next from "i18next";
import Get from "../../api/v2/model/transaction/get.js";
import Get from "../../api/v1/model/transaction/get.js";
import {parseDownloadedSplits} from "./shared/parse-downloaded-splits.js";
import {format} from "date-fns";
import formatMoney from "../../util/format-money.js";

View File

@@ -20,6 +20,6 @@
export function showInternalsButton() {
console.log('showInternalsButton');
// console.log('showInternalsButton');
document.querySelector('.toggle-page-internals').classList.remove('d-none');
}

View File

@@ -36,8 +36,8 @@ export default defineConfig(({command, mode, isSsrBuild, isPreview}) => {
let https = null;
if (command === 'serve') {
https = {
key: fs.readFileSync(`/sites/vm/tls-certificates/wildcard.sd.internal.key`),
cert: fs.readFileSync(`/sites/vm/tls-certificates/wildcard.sd.internal.crt`),
key: fs.readFileSync(`/vagrant/tls-certificates/wildcard.sd.internal.key`),
cert: fs.readFileSync(`/vagrant/tls-certificates/wildcard.sd.internal.crt`),
};
}
@@ -82,11 +82,13 @@ export default defineConfig(({command, mode, isSsrBuild, isPreview}) => {
server: {
origin: 'http://127.0.0.1:8000',
cors: true,
origin: 'https://firefly.sd.internal:5173',
watch: {
usePolling: true,
},
host: '10.0.0.15',
port: 5173,
host: true,
// hmr: {
// protocol: 'wss',
// },

File diff suppressed because one or more lines are too long

View File

@@ -59,7 +59,7 @@
</div>
<div class="modal-body">
<p>
Body
Buttons.
</p>
</div>
<div class="modal-footer">

View File

@@ -9,17 +9,17 @@
<div class="card-body p-0" style="position: relative;height:400px;">
<canvas id="account-chart"></canvas>
</div>
<template x-if="autoConversionAvailable">
<template x-if="convertToNativeAvailable">
<div class="card-footer text-end">
<template x-if="autoConversion">
<button type="button" @click="switchAutoConversion"
<template x-if="convertToNative">
<button type="button" @click="switchConvertToNative"
class="btn btn-outline-info btm-sm">
<span
class="fa-solid fa-comments-dollar"></span> {{ __('firefly.disable_auto_convert') }}
</button>
</template>
<template x-if="!autoConversion">
<button type="button" @click="switchAutoConversion"
<template x-if="!convertToNative">
<button type="button" @click="switchConvertToNative"
class="btn btn-outline-info btm-sm">
<span
class="fa-solid fa-comments-dollar"></span> {{ __('firefly.enable_auto_convert') }}

View File

@@ -75,7 +75,7 @@
<ul class="list-unstyled list-no-margin">
<template x-for="transaction in group.transactions">
<li>
@include('partials.elements.amount', ['autoConversion' => true,'type' => 'transaction.type','amount' => 'transaction.amount','native' => 'transaction.native_amount'])
@include('partials.elements.amount', ['convertToNative' => true,'type' => 'transaction.type','amount' => 'transaction.amount','native' => 'transaction.native_amount'])
</li>
</template>
</ul>

View File

@@ -1,5 +1,5 @@
@if($autoConversion)
<template x-if="autoConversion">
@if($convertToNative)
<template x-if="convertToNative">
<span>
<template x-if="{{ $native }}_raw < 0">
<span class="text-danger">
@@ -20,7 +20,7 @@
</template>
</span>
</template>
<template x-if="!autoConversion">
<template x-if="!convertToNative">
<span>
<template x-if="{{ $amount }}_raw < 0">

View File

@@ -337,9 +337,33 @@ Route::group(
],
static function (): void {
Route::get('overview', ['uses' => 'AccountController@overview', 'as' => 'overview']);
Route::get('dashboard', ['uses' => 'AccountController@dashboard', 'as' => 'dashboard']);
}
);
Route::group(
[
'namespace' => 'FireflyIII\Api\V1\Controllers\Chart',
'prefix' => 'v1/chart/budget',
'as' => 'api.v1.chart.budget.',
],
static function (): void {
Route::get('dashboard', ['uses' => 'BudgetController@dashboard', 'as' => 'dashboard']);
}
);
Route::group(
[
'namespace' => 'FireflyIII\Api\V1\Controllers\Chart',
'prefix' => 'v1/chart/category',
'as' => 'api.v1.chart.category.',
],
static function (): void {
Route::get('dashboard', ['uses' => 'CategoryController@dashboard', 'as' => 'dashboard']);
}
);
// DATA ROUTES
// Export data API routes
Route::group(
@@ -351,6 +375,7 @@ Route::group(
static function (): void {
Route::get('accounts', ['uses' => 'ExportController@accounts', 'as' => 'accounts']);
Route::get('bills', ['uses' => 'ExportController@bills', 'as' => 'bills']);
Route::get('subscriptions', ['uses' => 'ExportController@bills', 'as' => 'subscriptions']);
Route::get('budgets', ['uses' => 'ExportController@budgets', 'as' => 'budgets']);
Route::get('categories', ['uses' => 'ExportController@categories', 'as' => 'categories']);
Route::get('piggy-banks', ['uses' => 'ExportController@piggyBanks', 'as' => 'piggy-banks']);
@@ -556,6 +581,24 @@ Route::group(
Route::get('{bill}/transactions', ['uses' => 'ListController@transactions', 'as' => 'transactions']);
}
);
Route::group(
[
'namespace' => 'FireflyIII\Api\V1\Controllers\Models\Bill',
'prefix' => 'v1/subscriptions',
'as' => 'api.v1.subscriptions.',
],
static function (): void {
Route::get('', ['uses' => 'ShowController@index', 'as' => 'index']);
Route::post('', ['uses' => 'StoreController@store', 'as' => 'store']);
Route::get('{bill}', ['uses' => 'ShowController@show', 'as' => 'show']);
Route::put('{bill}', ['uses' => 'UpdateController@update', 'as' => 'update']);
Route::delete('{bill}', ['uses' => 'DestroyController@destroy', 'as' => 'delete']);
Route::get('{bill}/attachments', ['uses' => 'ListController@attachments', 'as' => 'attachments']);
Route::get('{bill}/rules', ['uses' => 'ListController@rules', 'as' => 'rules']);
Route::get('{bill}/transactions', ['uses' => 'ListController@transactions', 'as' => 'transactions']);
}
);
// Available Budget API routes:
Route::group(