mirror of
https://github.com/firefly-iii/firefly-iii.git
synced 2025-10-20 03:10:57 +00:00
Compare commits
137 Commits
v6.2.0-bet
...
v6.2.6
Author | SHA1 | Date | |
---|---|---|---|
|
b7dad8166d | ||
|
2da1b43c37 | ||
|
a606315884 | ||
|
295feedd77 | ||
|
d3b2748c8f | ||
|
1b4655fd70 | ||
|
05f67ef584 | ||
|
04ab7ba07d | ||
|
5806323970 | ||
|
ee260a3df7 | ||
|
7cb41fb333 | ||
|
d38adbfdc2 | ||
|
e6a6766ef1 | ||
|
a1e596491c | ||
|
9c920908a6 | ||
|
0014bffeb8 | ||
|
63c17f99b2 | ||
|
ec1e0e2807 | ||
|
2f16419a7b | ||
|
02c13859e7 | ||
|
57ec9b8e36 | ||
|
41ad35880d | ||
|
3aa946e028 | ||
|
53e46895aa | ||
|
c61389037d | ||
|
6172d60e00 | ||
|
f909f1d9ff | ||
|
55018ca046 | ||
|
19c746a865 | ||
|
503d2aa786 | ||
|
70d83ab501 | ||
|
edab602bb7 | ||
|
f9bcc4b1fa | ||
|
f3fe86167c | ||
|
2189fb46a2 | ||
|
7ff4178c8b | ||
|
fffd695ef8 | ||
|
ee592de035 | ||
|
7394e50ae2 | ||
|
f42fcff04a | ||
|
4eb3ce7c14 | ||
|
a977c567ce | ||
|
785bd7e905 | ||
|
df19f699d4 | ||
|
5e6e932e7e | ||
|
5bc397f01a | ||
|
42209e367f | ||
|
d53b1670d3 | ||
|
a6d450ba18 | ||
|
e8c1a95128 | ||
|
edb201f210 | ||
|
fe57367a8c | ||
|
134194a95b | ||
|
41c0e6fe2d | ||
|
c07914e733 | ||
|
52e2302f4f | ||
|
0a6b34b4f2 | ||
|
1e06b4dd0b | ||
|
5701f95e0b | ||
|
60d3572d37 | ||
|
ffa6e6a571 | ||
|
d6453cd735 | ||
|
fd79f9df44 | ||
|
4587340293 | ||
|
90bfdc7573 | ||
|
eca12f661f | ||
|
f85878b843 | ||
|
6499b5eaab | ||
|
7e4fece63d | ||
|
512eddf8be | ||
|
f0fa93a811 | ||
|
3c8de21709 | ||
|
81173e8340 | ||
|
35a8fa5f02 | ||
|
443036936d | ||
|
ac88007593 | ||
|
2297589dca | ||
|
6ada5fa560 | ||
|
8f6eefb5e7 | ||
|
b36a50381b | ||
|
51f84b3060 | ||
|
72132a19b0 | ||
|
065d165211 | ||
|
cabedf39b2 | ||
|
5d3806fcd4 | ||
|
01695b3342 | ||
|
71fb5fe077 | ||
|
3bec106840 | ||
|
fb01c36be1 | ||
|
26d851e69e | ||
|
28c18c046b | ||
|
318cef7e3b | ||
|
e8dc8f25be | ||
|
10ccc30240 | ||
|
5adc877d5e | ||
|
30923afb2b | ||
|
4eb6813b43 | ||
|
7521a31619 | ||
|
fc05beb452 | ||
|
1103428a83 | ||
|
d06d521bf0 | ||
|
8f64f1c0eb | ||
|
d11c232171 | ||
|
93c73248de | ||
|
5bed081ab9 | ||
|
c5188c503e | ||
|
98ffcac7b6 | ||
|
df1e81d611 | ||
|
9711170b08 | ||
|
e43264bdce | ||
|
e0643bed7a | ||
|
7f0eb3b064 | ||
|
f38e510526 | ||
|
25f99b23b2 | ||
|
44281fc8a0 | ||
|
eed3902cb7 | ||
|
94a3bb0443 | ||
|
8dcc36880e | ||
|
695bb31894 | ||
|
f8ded66869 | ||
|
8e4bdbc584 | ||
|
f7b14b01bc | ||
|
705b9bf0f2 | ||
|
f0226dbc54 | ||
|
1b1dfb0d7b | ||
|
8ed5092a76 | ||
|
d609821be6 | ||
|
cd0201074c | ||
|
1d8feec7bc | ||
|
d941472c84 | ||
|
674a118fac | ||
|
1334d793f6 | ||
|
60354c0202 | ||
|
22081d3f0a | ||
|
4b3f8fc78d | ||
|
4bd1aab86d | ||
|
60362cb60c |
12
.ci/php-cs-fixer/composer.lock
generated
12
.ci/php-cs-fixer/composer.lock
generated
@@ -406,16 +406,16 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "friendsofphp/php-cs-fixer",
|
"name": "friendsofphp/php-cs-fixer",
|
||||||
"version": "v3.68.1",
|
"version": "v3.68.5",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer.git",
|
"url": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer.git",
|
||||||
"reference": "b9db2b2ea3cdba7201067acee46f984ef2397cff"
|
"reference": "7bedb718b633355272428c60736dc97fb96daf27"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/b9db2b2ea3cdba7201067acee46f984ef2397cff",
|
"url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/7bedb718b633355272428c60736dc97fb96daf27",
|
||||||
"reference": "b9db2b2ea3cdba7201067acee46f984ef2397cff",
|
"reference": "7bedb718b633355272428c60736dc97fb96daf27",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
@@ -497,7 +497,7 @@
|
|||||||
],
|
],
|
||||||
"support": {
|
"support": {
|
||||||
"issues": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/issues",
|
"issues": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/issues",
|
||||||
"source": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/tree/v3.68.1"
|
"source": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/tree/v3.68.5"
|
||||||
},
|
},
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
@@ -505,7 +505,7 @@
|
|||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"time": "2025-01-17T09:20:36+00:00"
|
"time": "2025-01-30T17:00:50+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "psr/container",
|
"name": "psr/container",
|
||||||
|
@@ -189,7 +189,7 @@ SEND_REPORT_JOURNALS=true
|
|||||||
ENABLE_EXTERNAL_MAP=false
|
ENABLE_EXTERNAL_MAP=false
|
||||||
|
|
||||||
#
|
#
|
||||||
# Enable or disable exchange rate conversion. This function isn't used yet by Firefly III
|
# Enable or disable exchange rate conversion.
|
||||||
#
|
#
|
||||||
ENABLE_EXCHANGE_RATES=false
|
ENABLE_EXCHANGE_RATES=false
|
||||||
|
|
||||||
|
33
.github/label-actions.yml
vendored
33
.github/label-actions.yml
vendored
@@ -1,16 +1,29 @@
|
|||||||
# Configuration for Label Actions - https://github.com/dessant/label-actions
|
# Configuration for Label Actions - https://github.com/dessant/label-actions
|
||||||
|
|
||||||
# The `feature` label is added to issues
|
# The `feature` label is added to issues
|
||||||
|
fixed:
|
||||||
|
issues:
|
||||||
|
# Post a comment, `{issue-author}` is an optional placeholder
|
||||||
|
comment: |
|
||||||
|
Hi there!
|
||||||
|
|
||||||
|
This is an automatic reply. `Share and enjoy`
|
||||||
|
|
||||||
|
This issue has been marked as fixed. Thanks for reporting! A new version will be released in due time. Unfortunately, [I cannot give an estimate](https://docs.firefly-iii.org/references/faq/firefly-iii/general/#when-will-you-release-version-the-next-version), but [the roadmap](https://roadmap.firefly-iii.org/) is available for your reading pleasure.
|
||||||
|
|
||||||
|
There is no need to close the issue. It will be closed automatically.
|
||||||
|
|
||||||
|
Thank you for your contributions.
|
||||||
feature:
|
feature:
|
||||||
issues:
|
issues:
|
||||||
# Post a comment, `{issue-author}` is an optional placeholder
|
# Post a comment, `{issue-author}` is an optional placeholder
|
||||||
unlabel: feature
|
unlabel: feature
|
||||||
comment: |
|
comment: |
|
||||||
Hi there!
|
Hi there!
|
||||||
|
|
||||||
This is an automatic reply. `Share and enjoy`
|
This is an automatic reply. `Share and enjoy`
|
||||||
|
|
||||||
This issue has been marked as a feature request. The requested (new) feature will become a part of Firefly III or the data importer in due course.
|
This issue has been marked as a feature request.
|
||||||
|
|
||||||
If you come across this issue, please be aware there is NO need to reply with "+1" or "me too" or "I need this too" or whatever. Such comments are not helpful, and do not influence [the roadmap](https://roadmap.firefly-iii.org/). Your comment may be :skull: deleted. You can subscribe to this issue to get updates.
|
If you come across this issue, please be aware there is NO need to reply with "+1" or "me too" or "I need this too" or whatever. Such comments are not helpful, and do not influence [the roadmap](https://roadmap.firefly-iii.org/). Your comment may be :skull: deleted. You can subscribe to this issue to get updates.
|
||||||
|
|
||||||
@@ -20,13 +33,13 @@ epic:
|
|||||||
issues:
|
issues:
|
||||||
# Post a comment, `{issue-author}` is an optional placeholder
|
# Post a comment, `{issue-author}` is an optional placeholder
|
||||||
comment: |
|
comment: |
|
||||||
Hi there!
|
Hi there!
|
||||||
|
|
||||||
This is an automatic reply. `Share and enjoy`
|
This is an automatic reply. `Share and enjoy`
|
||||||
|
|
||||||
This issue has been marked as an epic. In epics, large amounts of works are collected that will be part of a major new feature. If you have more ideas that could be a part of this epic, feel free to reply.
|
This issue has been marked as an epic. In epics, large amounts of works are collected that will be part of a major new feature. If you have more ideas that could be a part of this epic, feel free to reply.
|
||||||
|
|
||||||
*However*, please be aware there is NO need to reply with "+1" or "me too" or "I need this too" or whatever. Such comments are not helpful, and do not influence [the roadmap](https://roadmap.firefly-iii.org/). Your comment may be :skull: deleted.
|
*However*, please be aware there is NO need to reply with "+1" or "me too" or "I need this too" or whatever. Such comments are not helpful, and do not influence [the roadmap](https://roadmap.firefly-iii.org/). Your comment may be :skull: deleted.
|
||||||
|
|
||||||
If you are merely interested in this epic's progress, you can subscribe to this issue to get updates.
|
If you are merely interested in this epic's progress, you can subscribe to this issue to get updates.
|
||||||
|
|
||||||
@@ -37,11 +50,11 @@ enhancement:
|
|||||||
issues:
|
issues:
|
||||||
# Post a comment, `{issue-author}` is an optional placeholder
|
# Post a comment, `{issue-author}` is an optional placeholder
|
||||||
comment: |
|
comment: |
|
||||||
Hi there!
|
Hi there!
|
||||||
|
|
||||||
This is an automatic reply. `Share and enjoy`
|
This is an automatic reply. `Share and enjoy`
|
||||||
|
|
||||||
This issue has been marked as an enhancement. The requested enhancement to an existing feature will become a part of Firefly III or the data importer in due course.
|
This issue has been marked as an enhancement.
|
||||||
|
|
||||||
If you come across this issue, please be aware there is NO need to reply with "+1" or "me too" or "I need this too" or whatever. Such comments are not helpful, and do not influence [the roadmap](https://roadmap.firefly-iii.org/). Your comment may be :skull: deleted. You can subscribe to this issue to get updates.
|
If you come across this issue, please be aware there is NO need to reply with "+1" or "me too" or "I need this too" or whatever. Such comments are not helpful, and do not influence [the roadmap](https://roadmap.firefly-iii.org/). Your comment may be :skull: deleted. You can subscribe to this issue to get updates.
|
||||||
|
|
||||||
@@ -51,7 +64,7 @@ triage:
|
|||||||
issues:
|
issues:
|
||||||
# Post a comment, `{issue-author}` is an optional placeholder
|
# Post a comment, `{issue-author}` is an optional placeholder
|
||||||
comment: |
|
comment: |
|
||||||
Hi there!
|
Hi there!
|
||||||
|
|
||||||
This is an automatic reply. `Share and enjoy`
|
This is an automatic reply. `Share and enjoy`
|
||||||
|
|
||||||
@@ -62,7 +75,7 @@ triage:
|
|||||||
needs-moar-debug:
|
needs-moar-debug:
|
||||||
issues:
|
issues:
|
||||||
comment: |
|
comment: |
|
||||||
Hi there!
|
Hi there!
|
||||||
|
|
||||||
This is an automatic reply. `Share and enjoy`
|
This is an automatic reply. `Share and enjoy`
|
||||||
|
|
||||||
@@ -80,7 +93,7 @@ needs-moar-debug:
|
|||||||
needs-moar-logs:
|
needs-moar-logs:
|
||||||
issues:
|
issues:
|
||||||
comment: |
|
comment: |
|
||||||
Hi there!
|
Hi there!
|
||||||
|
|
||||||
This is an automatic reply. `Share and enjoy`
|
This is an automatic reply. `Share and enjoy`
|
||||||
|
|
||||||
@@ -96,7 +109,7 @@ needs-moar-logs:
|
|||||||
v2-layout-issue:
|
v2-layout-issue:
|
||||||
issues:
|
issues:
|
||||||
comment: |
|
comment: |
|
||||||
Hi there!
|
Hi there!
|
||||||
|
|
||||||
This is an automatic reply. `Share and enjoy`
|
This is an automatic reply. `Share and enjoy`
|
||||||
|
|
||||||
|
2
.github/workflows/closed-issues.yml
vendored
2
.github/workflows/closed-issues.yml
vendored
@@ -8,7 +8,7 @@ jobs:
|
|||||||
command_and_close:
|
command_and_close:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: aws-actions/closed-issue-message@v1
|
- uses: aws-actions/closed-issue-message@v2
|
||||||
with:
|
with:
|
||||||
message: |
|
message: |
|
||||||
Hi there! This is an automatic reply. `Share and enjoy`
|
Hi there! This is an automatic reply. `Share and enjoy`
|
||||||
|
@@ -3,6 +3,9 @@
|
|||||||
Over time, many people have contributed to Firefly III. Their efforts are not always visible, but always remembered and appreciated.
|
Over time, many people have contributed to Firefly III. Their efforts are not always visible, but always remembered and appreciated.
|
||||||
Please find below all the people who contributed to the Firefly III code. Their names are mentioned in the year of their first contribution.
|
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
|
||||||
|
- SoftBrix
|
||||||
|
|
||||||
## 2024
|
## 2024
|
||||||
- Sobuno
|
- Sobuno
|
||||||
- TasneemTantawy
|
- TasneemTantawy
|
||||||
|
@@ -34,6 +34,7 @@ use FireflyIII\Support\Facades\Steam;
|
|||||||
use FireflyIII\Support\Http\Api\AccountFilter;
|
use FireflyIII\Support\Http\Api\AccountFilter;
|
||||||
use FireflyIII\User;
|
use FireflyIII\User;
|
||||||
use Illuminate\Http\JsonResponse;
|
use Illuminate\Http\JsonResponse;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class AccountController
|
* Class AccountController
|
||||||
@@ -41,7 +42,8 @@ use Illuminate\Http\JsonResponse;
|
|||||||
class AccountController extends Controller
|
class AccountController extends Controller
|
||||||
{
|
{
|
||||||
use AccountFilter;
|
use AccountFilter;
|
||||||
protected array $accepts = ['application/json'];
|
// this array only exists to test if the constructor will use it properly.
|
||||||
|
protected array $accepts = ['application/json', 'application/vnd.api+json'];
|
||||||
|
|
||||||
/** @var array<int, string> */
|
/** @var array<int, string> */
|
||||||
private array $balanceTypes;
|
private array $balanceTypes;
|
||||||
@@ -82,12 +84,17 @@ class AccountController extends Controller
|
|||||||
$return = [];
|
$return = [];
|
||||||
$result = $this->repository->searchAccount((string) $query, $types, $this->parameters->get('limit'));
|
$result = $this->repository->searchAccount((string) $query, $types, $this->parameters->get('limit'));
|
||||||
|
|
||||||
|
// set date to subday + end-of-day for account balance. so it is at $date 23:59:59
|
||||||
|
$date->subDay()->endOfDay();
|
||||||
|
|
||||||
/** @var Account $account */
|
/** @var Account $account */
|
||||||
foreach ($result as $account) {
|
foreach ($result as $account) {
|
||||||
$nameWithBalance = $account->name;
|
$nameWithBalance = $account->name;
|
||||||
$currency = $this->repository->getAccountCurrency($account) ?? $this->nativeCurrency;
|
$currency = $this->repository->getAccountCurrency($account) ?? $this->nativeCurrency;
|
||||||
$useCurrency = $currency;
|
$useCurrency = $currency;
|
||||||
if (in_array($account->accountType->type, $this->balanceTypes, true)) {
|
if (in_array($account->accountType->type, $this->balanceTypes, true)) {
|
||||||
|
// this one is correct.
|
||||||
|
Log::debug(sprintf('accounts: Call finalAccountBalance with date/time "%s"', $date->toIso8601String()));
|
||||||
$balance = Steam::finalAccountBalance($account, $date);
|
$balance = Steam::finalAccountBalance($account, $date);
|
||||||
$key = $this->convertToNative && $currency->id !== $this->nativeCurrency->id ? 'native_balance' : 'balance';
|
$key = $this->convertToNative && $currency->id !== $this->nativeCurrency->id ? 'native_balance' : 'balance';
|
||||||
$useCurrency = $this->convertToNative && $currency->id !== $this->nativeCurrency->id ? $this->nativeCurrency : $currency;
|
$useCurrency = $this->convertToNative && $currency->id !== $this->nativeCurrency->id ? $this->nativeCurrency : $currency;
|
||||||
@@ -100,15 +107,20 @@ class AccountController extends Controller
|
|||||||
}
|
}
|
||||||
|
|
||||||
$return[] = [
|
$return[] = [
|
||||||
'id' => (string) $account->id,
|
'id' => (string) $account->id,
|
||||||
'name' => $account->name,
|
'name' => $account->name,
|
||||||
'name_with_balance' => $nameWithBalance,
|
'name_with_balance' => $nameWithBalance,
|
||||||
'type' => $account->accountType->type,
|
'type' => $account->accountType->type,
|
||||||
'currency_id' => (string) $useCurrency->id,
|
'currency_id' => (string) $useCurrency->id,
|
||||||
'currency_name' => $useCurrency->name,
|
'currency_name' => $useCurrency->name,
|
||||||
'currency_code' => $useCurrency->code,
|
'currency_code' => $useCurrency->code,
|
||||||
'currency_symbol' => $useCurrency->symbol,
|
'currency_symbol' => $useCurrency->symbol,
|
||||||
'currency_decimal_places' => $useCurrency->decimal_places,
|
'currency_decimal_places' => $useCurrency->decimal_places,
|
||||||
|
'account_currency_id' => (string) $currency->id,
|
||||||
|
'account_currency_name' => $currency->name,
|
||||||
|
'account_currency_code' => $currency->code,
|
||||||
|
'account_currency_symbol' => $currency->symbol,
|
||||||
|
'account_currency_decimal_places' => $currency->decimal_places,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -26,6 +26,7 @@ namespace FireflyIII\Api\V1\Controllers\Autocomplete;
|
|||||||
|
|
||||||
use FireflyIII\Api\V1\Controllers\Controller;
|
use FireflyIII\Api\V1\Controllers\Controller;
|
||||||
use FireflyIII\Api\V1\Requests\Autocomplete\AutocompleteRequest;
|
use FireflyIII\Api\V1\Requests\Autocomplete\AutocompleteRequest;
|
||||||
|
use FireflyIII\Enums\UserRoleEnum;
|
||||||
use FireflyIII\Models\TransactionJournal;
|
use FireflyIII\Models\TransactionJournal;
|
||||||
use FireflyIII\Repositories\Journal\JournalRepositoryInterface;
|
use FireflyIII\Repositories\Journal\JournalRepositoryInterface;
|
||||||
use FireflyIII\Repositories\TransactionGroup\TransactionGroupRepositoryInterface;
|
use FireflyIII\Repositories\TransactionGroup\TransactionGroupRepositoryInterface;
|
||||||
@@ -41,6 +42,8 @@ class TransactionController extends Controller
|
|||||||
private TransactionGroupRepositoryInterface $groupRepository;
|
private TransactionGroupRepositoryInterface $groupRepository;
|
||||||
private JournalRepositoryInterface $repository;
|
private JournalRepositoryInterface $repository;
|
||||||
|
|
||||||
|
protected array $acceptedRoles = [UserRoleEnum::READ_ONLY];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TransactionController constructor.
|
* TransactionController constructor.
|
||||||
*/
|
*/
|
||||||
@@ -51,10 +54,12 @@ class TransactionController extends Controller
|
|||||||
function ($request, $next) {
|
function ($request, $next) {
|
||||||
/** @var User $user */
|
/** @var User $user */
|
||||||
$user = auth()->user();
|
$user = auth()->user();
|
||||||
|
$userGroup = $this->validateUserGroup($request);
|
||||||
$this->repository = app(JournalRepositoryInterface::class);
|
$this->repository = app(JournalRepositoryInterface::class);
|
||||||
$this->groupRepository = app(TransactionGroupRepositoryInterface::class);
|
$this->groupRepository = app(TransactionGroupRepositoryInterface::class);
|
||||||
$this->repository->setUser($user);
|
$this->repository->setUser($user);
|
||||||
$this->groupRepository->setUser($user);
|
$this->groupRepository->setUser($user);
|
||||||
|
$this->groupRepository->setUserGroup($userGroup);
|
||||||
|
|
||||||
return $next($request);
|
return $next($request);
|
||||||
}
|
}
|
||||||
|
@@ -32,6 +32,7 @@ use FireflyIII\Exceptions\FireflyException;
|
|||||||
use FireflyIII\Models\Account;
|
use FireflyIII\Models\Account;
|
||||||
use FireflyIII\Models\Preference;
|
use FireflyIII\Models\Preference;
|
||||||
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
|
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
|
||||||
|
use FireflyIII\Support\Facades\Steam;
|
||||||
use FireflyIII\Support\Http\Api\ApiSupport;
|
use FireflyIII\Support\Http\Api\ApiSupport;
|
||||||
use FireflyIII\User;
|
use FireflyIII\User;
|
||||||
use Illuminate\Http\JsonResponse;
|
use Illuminate\Http\JsonResponse;
|
||||||
@@ -80,6 +81,10 @@ class AccountController extends Controller
|
|||||||
/** @var Carbon $end */
|
/** @var Carbon $end */
|
||||||
$end = $dates['end'];
|
$end = $dates['end'];
|
||||||
|
|
||||||
|
// set dates to end of day + start of day:
|
||||||
|
$start->startOfDay();
|
||||||
|
$end->endOfDay();
|
||||||
|
|
||||||
// user's preferences
|
// user's preferences
|
||||||
$defaultSet = $this->repository->getAccountsByType([AccountTypeEnum::ASSET->value])->pluck('id')->toArray();
|
$defaultSet = $this->repository->getAccountsByType([AccountTypeEnum::ASSET->value])->pluck('id')->toArray();
|
||||||
|
|
||||||
@@ -113,7 +118,7 @@ class AccountController extends Controller
|
|||||||
];
|
];
|
||||||
// TODO this code is also present in the V2 chart account controller so this method is due to be deprecated.
|
// TODO this code is also present in the V2 chart account controller so this method is due to be deprecated.
|
||||||
$currentStart = clone $start;
|
$currentStart = clone $start;
|
||||||
$range = app('steam')->finalAccountBalanceInRange($account, $start, clone $end, $this->convertToNative);
|
$range = Steam::finalAccountBalanceInRange($account, $start, clone $end, $this->convertToNative);
|
||||||
$previous = array_values($range)[0][$field];
|
$previous = array_values($range)[0][$field];
|
||||||
while ($currentStart <= $end) {
|
while ($currentStart <= $end) {
|
||||||
$format = $currentStart->format('Y-m-d');
|
$format = $currentStart->format('Y-m-d');
|
||||||
|
@@ -31,6 +31,7 @@ use FireflyIII\Models\Preference;
|
|||||||
use FireflyIII\Models\TransactionCurrency;
|
use FireflyIII\Models\TransactionCurrency;
|
||||||
use FireflyIII\Support\Facades\Amount;
|
use FireflyIII\Support\Facades\Amount;
|
||||||
use FireflyIII\Support\Facades\Steam;
|
use FireflyIII\Support\Facades\Steam;
|
||||||
|
use FireflyIII\Support\Http\Api\ValidatesUserGroupTrait;
|
||||||
use FireflyIII\Transformers\V2\AbstractTransformer;
|
use FireflyIII\Transformers\V2\AbstractTransformer;
|
||||||
use FireflyIII\User;
|
use FireflyIII\User;
|
||||||
use Illuminate\Database\Eloquent\Model;
|
use Illuminate\Database\Eloquent\Model;
|
||||||
@@ -59,6 +60,7 @@ abstract class Controller extends BaseController
|
|||||||
use AuthorizesRequests;
|
use AuthorizesRequests;
|
||||||
use DispatchesJobs;
|
use DispatchesJobs;
|
||||||
use ValidatesRequests;
|
use ValidatesRequests;
|
||||||
|
use ValidatesUserGroupTrait;
|
||||||
|
|
||||||
protected const string CONTENT_TYPE = 'application/vnd.api+json';
|
protected const string CONTENT_TYPE = 'application/vnd.api+json';
|
||||||
protected const string JSON_CONTENT_TYPE = 'application/json';
|
protected const string JSON_CONTENT_TYPE = 'application/json';
|
||||||
@@ -67,7 +69,7 @@ abstract class Controller extends BaseController
|
|||||||
protected array $allowedSort;
|
protected array $allowedSort;
|
||||||
protected ParameterBag $parameters;
|
protected ParameterBag $parameters;
|
||||||
protected bool $convertToNative = false;
|
protected bool $convertToNative = false;
|
||||||
protected array $accepts = ['application/json'];
|
protected array $accepts = ['application/json', 'application/vnd.api+json'];
|
||||||
protected TransactionCurrency $nativeCurrency;
|
protected TransactionCurrency $nativeCurrency;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -57,11 +57,11 @@ class IndexController extends Controller
|
|||||||
|
|
||||||
public function index(): JsonResponse
|
public function index(): JsonResponse
|
||||||
{
|
{
|
||||||
$piggies = $this->repository->getAll();
|
$entries = $this->repository->getAll();
|
||||||
$pageSize = $this->parameters->get('limit');
|
$pageSize = $this->parameters->get('limit');
|
||||||
$count = $piggies->count();
|
$count = $entries->count();
|
||||||
$piggies = $piggies->slice(($this->parameters->get('page') - 1) * $pageSize, $pageSize);
|
$entries = $entries->slice(($this->parameters->get('page') - 1) * $pageSize, $pageSize);
|
||||||
$paginator = new LengthAwarePaginator($piggies, $count, $pageSize, $this->parameters->get('page'));
|
$paginator = new LengthAwarePaginator($entries, $count, $pageSize, $this->parameters->get('page'));
|
||||||
$transformer = new ExchangeRateTransformer();
|
$transformer = new ExchangeRateTransformer();
|
||||||
$transformer->setParameters($this->parameters); // give params to transformer
|
$transformer->setParameters($this->parameters); // give params to transformer
|
||||||
|
|
||||||
|
@@ -26,6 +26,7 @@ namespace FireflyIII\Api\V1\Controllers\Models\Transaction;
|
|||||||
|
|
||||||
use FireflyIII\Api\V1\Controllers\Controller;
|
use FireflyIII\Api\V1\Controllers\Controller;
|
||||||
use FireflyIII\Api\V1\Requests\Models\Transaction\StoreRequest;
|
use FireflyIII\Api\V1\Requests\Models\Transaction\StoreRequest;
|
||||||
|
use FireflyIII\Enums\UserRoleEnum;
|
||||||
use FireflyIII\Events\StoredTransactionGroup;
|
use FireflyIII\Events\StoredTransactionGroup;
|
||||||
use FireflyIII\Exceptions\DuplicateTransactionException;
|
use FireflyIII\Exceptions\DuplicateTransactionException;
|
||||||
use FireflyIII\Exceptions\FireflyException;
|
use FireflyIII\Exceptions\FireflyException;
|
||||||
@@ -37,6 +38,7 @@ use FireflyIII\Transformers\TransactionGroupTransformer;
|
|||||||
use FireflyIII\User;
|
use FireflyIII\User;
|
||||||
use Illuminate\Http\JsonResponse;
|
use Illuminate\Http\JsonResponse;
|
||||||
use Illuminate\Support\Facades\Log;
|
use Illuminate\Support\Facades\Log;
|
||||||
|
use Illuminate\Support\Facades\Validator;
|
||||||
use Illuminate\Validation\ValidationException;
|
use Illuminate\Validation\ValidationException;
|
||||||
use League\Fractal\Resource\Item;
|
use League\Fractal\Resource\Item;
|
||||||
|
|
||||||
@@ -49,6 +51,8 @@ class StoreController extends Controller
|
|||||||
|
|
||||||
private TransactionGroupRepositoryInterface $groupRepository;
|
private TransactionGroupRepositoryInterface $groupRepository;
|
||||||
|
|
||||||
|
protected array $acceptedRoles = [UserRoleEnum::MANAGE_TRANSACTIONS];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TransactionController constructor.
|
* TransactionController constructor.
|
||||||
*/
|
*/
|
||||||
@@ -59,9 +63,11 @@ class StoreController extends Controller
|
|||||||
function ($request, $next) {
|
function ($request, $next) {
|
||||||
/** @var User $admin */
|
/** @var User $admin */
|
||||||
$admin = auth()->user();
|
$admin = auth()->user();
|
||||||
|
$userGroup = $this->validateUserGroup($request);
|
||||||
|
|
||||||
$this->groupRepository = app(TransactionGroupRepositoryInterface::class);
|
$this->groupRepository = app(TransactionGroupRepositoryInterface::class);
|
||||||
$this->groupRepository->setUser($admin);
|
$this->groupRepository->setUser($admin);
|
||||||
|
$this->groupRepository->setUserGroup($userGroup);
|
||||||
|
|
||||||
return $next($request);
|
return $next($request);
|
||||||
}
|
}
|
||||||
@@ -79,61 +85,58 @@ class StoreController extends Controller
|
|||||||
public function store(StoreRequest $request): JsonResponse
|
public function store(StoreRequest $request): JsonResponse
|
||||||
{
|
{
|
||||||
app('log')->debug('Now in API StoreController::store()');
|
app('log')->debug('Now in API StoreController::store()');
|
||||||
$data = $request->getAll();
|
$data = $request->getAll();
|
||||||
$data['user'] = auth()->user()->id;
|
$data['user'] = auth()->user();
|
||||||
|
$data['user_group'] = $this->userGroup;
|
||||||
|
|
||||||
Log::channel('audit')
|
Log::channel('audit')->info('Store new transaction over API.', $data);
|
||||||
->info('Store new transaction over API.', $data)
|
|
||||||
;
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$transactionGroup = $this->groupRepository->store($data);
|
$transactionGroup = $this->groupRepository->store($data);
|
||||||
} catch (DuplicateTransactionException $e) {
|
} catch (DuplicateTransactionException $e) {
|
||||||
app('log')->warning('Caught a duplicate transaction. Return error message.');
|
app('log')->warning('Caught a duplicate transaction. Return error message.');
|
||||||
$validator = \Validator::make(
|
$validator = Validator::make(['transactions' => [['description' => $e->getMessage()]]], ['transactions.0.description' => new IsDuplicateTransaction()]);
|
||||||
['transactions' => [['description' => $e->getMessage()]]],
|
|
||||||
['transactions.0.description' => new IsDuplicateTransaction()]
|
|
||||||
);
|
|
||||||
|
|
||||||
throw new ValidationException($validator);
|
throw new ValidationException($validator);
|
||||||
} catch (FireflyException $e) {
|
} catch (FireflyException $e) {
|
||||||
app('log')->warning('Caught an exception. Return error message.');
|
app('log')->warning('Caught an exception. Return error message.');
|
||||||
app('log')->error($e->getMessage());
|
app('log')->error($e->getMessage());
|
||||||
$message = sprintf('Internal exception: %s', $e->getMessage());
|
$message = sprintf('Internal exception: %s', $e->getMessage());
|
||||||
$validator = \Validator::make(['transactions' => [['description' => $message]]], ['transactions.0.description' => new IsDuplicateTransaction()]);
|
$validator = Validator::make(['transactions' => [['description' => $message]]], ['transactions.0.description' => new IsDuplicateTransaction()]);
|
||||||
|
|
||||||
throw new ValidationException($validator);
|
throw new ValidationException($validator);
|
||||||
}
|
}
|
||||||
app('preferences')->mark();
|
app('preferences')->mark();
|
||||||
$applyRules = $data['apply_rules'] ?? true;
|
$applyRules = $data['apply_rules'] ?? true;
|
||||||
$fireWebhooks = $data['fire_webhooks'] ?? true;
|
$fireWebhooks = $data['fire_webhooks'] ?? true;
|
||||||
event(new StoredTransactionGroup($transactionGroup, $applyRules, $fireWebhooks));
|
event(new StoredTransactionGroup($transactionGroup, $applyRules, $fireWebhooks));
|
||||||
|
|
||||||
$manager = $this->getManager();
|
$manager = $this->getManager();
|
||||||
|
|
||||||
/** @var User $admin */
|
/** @var User $admin */
|
||||||
$admin = auth()->user();
|
$admin = auth()->user();
|
||||||
|
|
||||||
// use new group collector:
|
// use new group collector:
|
||||||
/** @var GroupCollectorInterface $collector */
|
/** @var GroupCollectorInterface $collector */
|
||||||
$collector = app(GroupCollectorInterface::class);
|
$collector = app(GroupCollectorInterface::class);
|
||||||
$collector
|
$collector
|
||||||
->setUser($admin)
|
->setUser($admin)
|
||||||
|
->setUserGroup($this->userGroup)
|
||||||
// filter on transaction group.
|
// filter on transaction group.
|
||||||
->setTransactionGroup($transactionGroup)
|
->setTransactionGroup($transactionGroup)
|
||||||
// all info needed for the API:
|
// all info needed for the API:
|
||||||
->withAPIInformation()
|
->withAPIInformation()
|
||||||
;
|
;
|
||||||
|
|
||||||
$selectedGroup = $collector->getGroups()->first();
|
$selectedGroup = $collector->getGroups()->first();
|
||||||
if (null === $selectedGroup) {
|
if (null === $selectedGroup) {
|
||||||
throw new FireflyException('200032: Cannot find transaction. Possibly, a rule deleted this transaction after its creation.');
|
throw new FireflyException('200032: Cannot find transaction. Possibly, a rule deleted this transaction after its creation.');
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @var TransactionGroupTransformer $transformer */
|
/** @var TransactionGroupTransformer $transformer */
|
||||||
$transformer = app(TransactionGroupTransformer::class);
|
$transformer = app(TransactionGroupTransformer::class);
|
||||||
$transformer->setParameters($this->parameters);
|
$transformer->setParameters($this->parameters);
|
||||||
$resource = new Item($selectedGroup, $transformer, 'transactions');
|
$resource = new Item($selectedGroup, $transformer, 'transactions');
|
||||||
|
|
||||||
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', self::CONTENT_TYPE);
|
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', self::CONTENT_TYPE);
|
||||||
}
|
}
|
||||||
|
@@ -72,13 +72,6 @@ class UpdateController extends Controller
|
|||||||
{
|
{
|
||||||
app('log')->debug('Now in update routine for transaction group');
|
app('log')->debug('Now in update routine for transaction group');
|
||||||
$data = $request->getAll();
|
$data = $request->getAll();
|
||||||
|
|
||||||
// Fixes 8750.
|
|
||||||
$transactions = $data['transactions'] ?? [];
|
|
||||||
foreach ($transactions as $index => $info) {
|
|
||||||
unset($data['transactions'][$index]['type']);
|
|
||||||
}
|
|
||||||
|
|
||||||
$transactionGroup = $this->groupRepository->update($transactionGroup, $data);
|
$transactionGroup = $this->groupRepository->update($transactionGroup, $data);
|
||||||
$manager = $this->getManager();
|
$manager = $this->getManager();
|
||||||
|
|
||||||
|
@@ -236,7 +236,7 @@ class ListController extends Controller
|
|||||||
// get list of budgets. Count it and split it.
|
// get list of budgets. Count it and split it.
|
||||||
/** @var RecurringRepositoryInterface $recurringRepos */
|
/** @var RecurringRepositoryInterface $recurringRepos */
|
||||||
$recurringRepos = app(RecurringRepositoryInterface::class);
|
$recurringRepos = app(RecurringRepositoryInterface::class);
|
||||||
$unfiltered = $recurringRepos->getAll();
|
$unfiltered = $recurringRepos->get();
|
||||||
|
|
||||||
// filter selection
|
// filter selection
|
||||||
$collection = $unfiltered->filter(
|
$collection = $unfiltered->filter(
|
||||||
|
@@ -31,6 +31,7 @@ use FireflyIII\Models\Account;
|
|||||||
use FireflyIII\Models\TransactionCurrency;
|
use FireflyIII\Models\TransactionCurrency;
|
||||||
use FireflyIII\Repositories\UserGroups\Account\AccountRepositoryInterface;
|
use FireflyIII\Repositories\UserGroups\Account\AccountRepositoryInterface;
|
||||||
use FireflyIII\Support\Chart\ChartData;
|
use FireflyIII\Support\Chart\ChartData;
|
||||||
|
use FireflyIII\Support\Facades\Steam;
|
||||||
use FireflyIII\Support\Http\Api\CleansChartData;
|
use FireflyIII\Support\Http\Api\CleansChartData;
|
||||||
use FireflyIII\Support\Http\Api\CollectsAccountsFromFilter;
|
use FireflyIII\Support\Http\Api\CollectsAccountsFromFilter;
|
||||||
use FireflyIII\Support\Http\Api\ValidatesUserGroupTrait;
|
use FireflyIII\Support\Http\Api\ValidatesUserGroupTrait;
|
||||||
@@ -118,7 +119,7 @@ class AccountController extends Controller
|
|||||||
'native_entries' => [],
|
'native_entries' => [],
|
||||||
];
|
];
|
||||||
$currentStart = clone $params['start'];
|
$currentStart = clone $params['start'];
|
||||||
$range = app('steam')->finalAccountBalanceInRange($account, $params['start'], clone $params['end'], $this->convertToNative);
|
$range = Steam::finalAccountBalanceInRange($account, $params['start'], clone $params['end'], $this->convertToNative);
|
||||||
|
|
||||||
$previous = array_values($range)[0]['balance'];
|
$previous = array_values($range)[0]['balance'];
|
||||||
$previousNative = array_values($range)[0]['native_balance'];
|
$previousNative = array_values($range)[0]['native_balance'];
|
||||||
|
@@ -21,25 +21,6 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
declare(strict_types=1);
|
declare(strict_types=1);
|
||||||
/*
|
|
||||||
* ConvertDatesToUTC.php
|
|
||||||
* Copyright (c) 2024 james@firefly-iii.org.
|
|
||||||
*
|
|
||||||
* This file is part of Firefly III (https://github.com/firefly-iii).
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU Affero General Public License as
|
|
||||||
* published by the Free Software Foundation, either version 3 of the
|
|
||||||
* License, or (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU Affero General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Affero General Public License
|
|
||||||
* along with this program. If not, see https://www.gnu.org/licenses/.
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace FireflyIII\Console\Commands\Correction;
|
namespace FireflyIII\Console\Commands\Correction;
|
||||||
|
|
||||||
|
@@ -25,6 +25,7 @@ declare(strict_types=1);
|
|||||||
namespace FireflyIII\Console\Commands\Correction;
|
namespace FireflyIII\Console\Commands\Correction;
|
||||||
|
|
||||||
use FireflyIII\Console\Commands\ShowsFriendlyMessages;
|
use FireflyIII\Console\Commands\ShowsFriendlyMessages;
|
||||||
|
use FireflyIII\Enums\TransactionTypeEnum;
|
||||||
use FireflyIII\Models\AutoBudget;
|
use FireflyIII\Models\AutoBudget;
|
||||||
use FireflyIII\Models\AvailableBudget;
|
use FireflyIII\Models\AvailableBudget;
|
||||||
use FireflyIII\Models\Bill;
|
use FireflyIII\Models\Bill;
|
||||||
@@ -33,8 +34,14 @@ use FireflyIII\Models\CurrencyExchangeRate;
|
|||||||
use FireflyIII\Models\PiggyBank;
|
use FireflyIII\Models\PiggyBank;
|
||||||
use FireflyIII\Models\RecurrenceTransaction;
|
use FireflyIII\Models\RecurrenceTransaction;
|
||||||
use FireflyIII\Models\RuleTrigger;
|
use FireflyIII\Models\RuleTrigger;
|
||||||
|
use FireflyIII\Models\Transaction;
|
||||||
|
use FireflyIII\Models\TransactionJournal;
|
||||||
|
use FireflyIII\Models\TransactionType;
|
||||||
|
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
|
||||||
|
use FireflyIII\Support\Facades\Amount;
|
||||||
use Illuminate\Console\Command;
|
use Illuminate\Console\Command;
|
||||||
use Illuminate\Support\Facades\DB;
|
use Illuminate\Support\Facades\DB;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
|
|
||||||
class CorrectsAmounts extends Command
|
class CorrectsAmounts extends Command
|
||||||
{
|
{
|
||||||
@@ -45,6 +52,8 @@ class CorrectsAmounts extends Command
|
|||||||
|
|
||||||
public function handle(): int
|
public function handle(): int
|
||||||
{
|
{
|
||||||
|
// transfers must not have foreign currency info if both accounts have the same currency.
|
||||||
|
$this->correctTransfers();
|
||||||
// auto budgets must be positive
|
// auto budgets must be positive
|
||||||
$this->fixAutoBudgets();
|
$this->fixAutoBudgets();
|
||||||
// available budgets must be positive
|
// available budgets must be positive
|
||||||
@@ -62,6 +71,7 @@ class CorrectsAmounts extends Command
|
|||||||
// rule_triggers must be positive or zero (amount_less, amount_more, amount_is)
|
// rule_triggers must be positive or zero (amount_less, amount_more, amount_is)
|
||||||
$this->fixRuleTriggers();
|
$this->fixRuleTriggers();
|
||||||
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -182,4 +192,63 @@ class CorrectsAmounts extends Command
|
|||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function correctTransfers(): void
|
||||||
|
{
|
||||||
|
/** @var AccountRepositoryInterface $repository */
|
||||||
|
$repository = app(AccountRepositoryInterface::class);
|
||||||
|
$type = TransactionType::where('type', TransactionTypeEnum::TRANSFER->value)->first();
|
||||||
|
$journals = TransactionJournal::where('transaction_type_id', $type->id)->get();
|
||||||
|
|
||||||
|
/** @var TransactionJournal $journal */
|
||||||
|
foreach ($journals as $journal) {
|
||||||
|
$repository->setUser($journal->user);
|
||||||
|
$native = Amount::getNativeCurrencyByUserGroup($journal->userGroup);
|
||||||
|
|
||||||
|
/** @var null|Transaction $source */
|
||||||
|
$source = $journal->transactions()->where('amount', '<', 0)->first();
|
||||||
|
|
||||||
|
/** @var null|Transaction $destination */
|
||||||
|
$destination = $journal->transactions()->where('amount', '>', 0)->first();
|
||||||
|
if (null === $source || null === $destination) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (null === $source->foreign_currency_id || null === $destination->foreign_currency_id) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$sourceAccount = $source->account;
|
||||||
|
$destAccount = $destination->account;
|
||||||
|
if (null === $sourceAccount || null === $destAccount) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$sourceCurrency = $repository->getAccountCurrency($sourceAccount) ?? $native;
|
||||||
|
$destCurrency = $repository->getAccountCurrency($destAccount) ?? $native;
|
||||||
|
|
||||||
|
if ($sourceCurrency->id === $destCurrency->id) {
|
||||||
|
Log::debug('Both accounts have the same currency. Removing foreign currency info.');
|
||||||
|
$source->foreign_currency_id = null;
|
||||||
|
$source->foreign_amount = null;
|
||||||
|
$source->save();
|
||||||
|
$destination->foreign_currency_id = null;
|
||||||
|
$destination->foreign_amount = null;
|
||||||
|
$destination->save();
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// validate source
|
||||||
|
if ($destCurrency->id !== $source->foreign_currency_id) {
|
||||||
|
Log::debug(sprintf('Journal #%d: Transaction #%d refers to "%s" but should refer to "%s".', $journal->id, $source->id, $source->foreignCurrency->code, $destCurrency->code));
|
||||||
|
$source->foreign_currency_id = $destCurrency->id;
|
||||||
|
$source->save();
|
||||||
|
}
|
||||||
|
|
||||||
|
// validate destination:
|
||||||
|
if ($sourceCurrency->id !== $destination->foreign_currency_id) {
|
||||||
|
Log::debug(sprintf('Journal #%d: Transaction #%d refers to "%s" but should refer to "%s".', $journal->id, $destination->id, $destination->foreignCurrency->code, $sourceCurrency->code));
|
||||||
|
$destination->foreign_currency_id = $sourceCurrency->id;
|
||||||
|
$destination->save();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -102,7 +102,14 @@ class CorrectsNativeAmounts extends Command
|
|||||||
{
|
{
|
||||||
$set = $userGroup->accounts()->where(function (EloquentBuilder $q): void {
|
$set = $userGroup->accounts()->where(function (EloquentBuilder $q): void {
|
||||||
$q->whereNotNull('virtual_balance');
|
$q->whereNotNull('virtual_balance');
|
||||||
$q->orWhere('virtual_balance', '!=', '');
|
|
||||||
|
// this needs a different piece of code for postgres.
|
||||||
|
if ('pgsql' === config('database.default')) {
|
||||||
|
$q->orWhere(DB::raw('CAST(virtual_balance AS TEXT)'), '!=', '');
|
||||||
|
}
|
||||||
|
if ('pgsql' !== config('database.default')) {
|
||||||
|
$q->orWhere('virtual_balance', '!=', '');
|
||||||
|
}
|
||||||
})->get();
|
})->get();
|
||||||
|
|
||||||
/** @var Account $account */
|
/** @var Account $account */
|
||||||
@@ -218,7 +225,6 @@ class CorrectsNativeAmounts extends Command
|
|||||||
$set = DB::table('transactions')
|
$set = DB::table('transactions')
|
||||||
->join('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id')
|
->join('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id')
|
||||||
->where('transaction_journals.user_group_id', $userGroup->id)
|
->where('transaction_journals.user_group_id', $userGroup->id)
|
||||||
|
|
||||||
->where(function (DatabaseBuilder $q1) use ($currency): void {
|
->where(function (DatabaseBuilder $q1) use ($currency): void {
|
||||||
$q1->where(function (DatabaseBuilder $q2) use ($currency): void {
|
$q1->where(function (DatabaseBuilder $q2) use ($currency): void {
|
||||||
$q2->whereNot('transactions.transaction_currency_id', $currency->id)->whereNull('transactions.foreign_currency_id');
|
$q2->whereNot('transactions.transaction_currency_id', $currency->id)->whereNull('transactions.foreign_currency_id');
|
||||||
|
@@ -21,25 +21,6 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
declare(strict_types=1);
|
declare(strict_types=1);
|
||||||
/*
|
|
||||||
* AddTimezonesToDates.php
|
|
||||||
* Copyright (c) 2024 james@firefly-iii.org.
|
|
||||||
*
|
|
||||||
* This file is part of Firefly III (https://github.com/firefly-iii).
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU Affero General Public License as
|
|
||||||
* published by the Free Software Foundation, either version 3 of the
|
|
||||||
* License, or (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU Affero General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Affero General Public License
|
|
||||||
* along with this program. If not, see https://www.gnu.org/licenses/.
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace FireflyIII\Console\Commands\Correction;
|
namespace FireflyIII\Console\Commands\Correction;
|
||||||
|
|
||||||
|
@@ -57,7 +57,7 @@ class ExportsData extends Command
|
|||||||
{--export-tags : Create a file with all your tags and some meta data.}
|
{--export-tags : Create a file with all your tags and some meta data.}
|
||||||
{--export-recurring : Create a file with all your recurring transactions and some meta data.}
|
{--export-recurring : Create a file with all your recurring transactions and some meta data.}
|
||||||
{--export-rules : Create a file with all your rules and some meta data.}
|
{--export-rules : Create a file with all your rules and some meta data.}
|
||||||
{--export-bills : Create a file with all your bills and some meta data.}
|
{--export-subscriptions : Create a file with all your subscriptions and some meta data.}
|
||||||
{--export-piggies : Create a file with all your piggy banks and some meta data.}
|
{--export-piggies : Create a file with all your piggy banks and some meta data.}
|
||||||
{--force : Force overwriting of previous exports if found.}';
|
{--force : Force overwriting of previous exports if found.}';
|
||||||
private AccountRepositoryInterface $accountRepository;
|
private AccountRepositoryInterface $accountRepository;
|
||||||
@@ -106,7 +106,7 @@ class ExportsData extends Command
|
|||||||
$exporter->setExportTags($options['export']['tags']);
|
$exporter->setExportTags($options['export']['tags']);
|
||||||
$exporter->setExportRecurring($options['export']['recurring']);
|
$exporter->setExportRecurring($options['export']['recurring']);
|
||||||
$exporter->setExportRules($options['export']['rules']);
|
$exporter->setExportRules($options['export']['rules']);
|
||||||
$exporter->setExportBills($options['export']['bills']);
|
$exporter->setExportBills($options['export']['subscriptions']);
|
||||||
$exporter->setExportPiggies($options['export']['piggies']);
|
$exporter->setExportPiggies($options['export']['piggies']);
|
||||||
$data = $exporter->export();
|
$data = $exporter->export();
|
||||||
if (0 === count($data)) {
|
if (0 === count($data)) {
|
||||||
@@ -157,7 +157,7 @@ class ExportsData extends Command
|
|||||||
'tags' => $this->option('export-tags'),
|
'tags' => $this->option('export-tags'),
|
||||||
'recurring' => $this->option('export-recurring'),
|
'recurring' => $this->option('export-recurring'),
|
||||||
'rules' => $this->option('export-rules'),
|
'rules' => $this->option('export-rules'),
|
||||||
'bills' => $this->option('export-bills'),
|
'bills' => $this->option('export-subscriptions'),
|
||||||
'piggies' => $this->option('export-piggies'),
|
'piggies' => $this->option('export-piggies'),
|
||||||
],
|
],
|
||||||
'start' => $start,
|
'start' => $start,
|
||||||
|
@@ -26,6 +26,7 @@ namespace FireflyIII\Factory;
|
|||||||
|
|
||||||
use FireflyIII\Models\Location;
|
use FireflyIII\Models\Location;
|
||||||
use FireflyIII\Models\Tag;
|
use FireflyIII\Models\Tag;
|
||||||
|
use FireflyIII\Models\UserGroup;
|
||||||
use FireflyIII\User;
|
use FireflyIII\User;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -34,6 +35,7 @@ use FireflyIII\User;
|
|||||||
class TagFactory
|
class TagFactory
|
||||||
{
|
{
|
||||||
private User $user;
|
private User $user;
|
||||||
|
private UserGroup $userGroup;
|
||||||
|
|
||||||
public function findOrCreate(string $tag): ?Tag
|
public function findOrCreate(string $tag): ?Tag
|
||||||
{
|
{
|
||||||
@@ -101,6 +103,12 @@ class TagFactory
|
|||||||
|
|
||||||
public function setUser(User $user): void
|
public function setUser(User $user): void
|
||||||
{
|
{
|
||||||
$this->user = $user;
|
$this->user = $user;
|
||||||
|
$this->userGroup = $user->userGroup;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setUserGroup(UserGroup $userGroup): void
|
||||||
|
{
|
||||||
|
$this->userGroup = $userGroup;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -31,7 +31,6 @@ use FireflyIII\Models\TransactionCurrency;
|
|||||||
use FireflyIII\Models\TransactionJournal;
|
use FireflyIII\Models\TransactionJournal;
|
||||||
use FireflyIII\Rules\UniqueIban;
|
use FireflyIII\Rules\UniqueIban;
|
||||||
use FireflyIII\Services\Internal\Update\AccountUpdateService;
|
use FireflyIII\Services\Internal\Update\AccountUpdateService;
|
||||||
use FireflyIII\User;
|
|
||||||
use Illuminate\Database\QueryException;
|
use Illuminate\Database\QueryException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -216,12 +215,4 @@ class TransactionFactory
|
|||||||
{
|
{
|
||||||
$this->reconciled = $reconciled;
|
$this->reconciled = $reconciled;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @SuppressWarnings("PHPMD.UnusedFormalParameter")
|
|
||||||
*/
|
|
||||||
public function setUser(User $user): void
|
|
||||||
{
|
|
||||||
// empty function.
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@@ -27,6 +27,7 @@ namespace FireflyIII\Factory;
|
|||||||
use FireflyIII\Exceptions\DuplicateTransactionException;
|
use FireflyIII\Exceptions\DuplicateTransactionException;
|
||||||
use FireflyIII\Exceptions\FireflyException;
|
use FireflyIII\Exceptions\FireflyException;
|
||||||
use FireflyIII\Models\TransactionGroup;
|
use FireflyIII\Models\TransactionGroup;
|
||||||
|
use FireflyIII\Models\UserGroup;
|
||||||
use FireflyIII\User;
|
use FireflyIII\User;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -36,6 +37,7 @@ class TransactionGroupFactory
|
|||||||
{
|
{
|
||||||
private TransactionJournalFactory $journalFactory;
|
private TransactionJournalFactory $journalFactory;
|
||||||
private User $user;
|
private User $user;
|
||||||
|
private UserGroup $userGroup;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TransactionGroupFactory constructor.
|
* TransactionGroupFactory constructor.
|
||||||
@@ -54,7 +56,8 @@ class TransactionGroupFactory
|
|||||||
public function create(array $data): TransactionGroup
|
public function create(array $data): TransactionGroup
|
||||||
{
|
{
|
||||||
app('log')->debug('Now in TransactionGroupFactory::create()');
|
app('log')->debug('Now in TransactionGroupFactory::create()');
|
||||||
$this->journalFactory->setUser($this->user);
|
$this->journalFactory->setUser($data['user']);
|
||||||
|
$this->journalFactory->setUserGroup($data['user_group']);
|
||||||
$this->journalFactory->setErrorOnHash($data['error_if_duplicate_hash'] ?? false);
|
$this->journalFactory->setErrorOnHash($data['error_if_duplicate_hash'] ?? false);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -76,7 +79,7 @@ class TransactionGroupFactory
|
|||||||
|
|
||||||
$group = new TransactionGroup();
|
$group = new TransactionGroup();
|
||||||
$group->user()->associate($this->user);
|
$group->user()->associate($this->user);
|
||||||
$group->userGroup()->associate($data['user_group'] ?? $this->user->userGroup);
|
$group->userGroup()->associate($data['user_group']);
|
||||||
$group->title = $title;
|
$group->title = $title;
|
||||||
$group->save();
|
$group->save();
|
||||||
|
|
||||||
@@ -92,4 +95,9 @@ class TransactionGroupFactory
|
|||||||
{
|
{
|
||||||
$this->user = $user;
|
$this->user = $user;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function setUserGroup(UserGroup $userGroup): void
|
||||||
|
{
|
||||||
|
$this->userGroup = $userGroup;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -34,6 +34,7 @@ use FireflyIII\Models\Transaction;
|
|||||||
use FireflyIII\Models\TransactionCurrency;
|
use FireflyIII\Models\TransactionCurrency;
|
||||||
use FireflyIII\Models\TransactionJournal;
|
use FireflyIII\Models\TransactionJournal;
|
||||||
use FireflyIII\Models\TransactionJournalMeta;
|
use FireflyIII\Models\TransactionJournalMeta;
|
||||||
|
use FireflyIII\Models\UserGroup;
|
||||||
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
|
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
|
||||||
use FireflyIII\Repositories\Bill\BillRepositoryInterface;
|
use FireflyIII\Repositories\Bill\BillRepositoryInterface;
|
||||||
use FireflyIII\Repositories\Budget\BudgetRepositoryInterface;
|
use FireflyIII\Repositories\Budget\BudgetRepositoryInterface;
|
||||||
@@ -69,6 +70,7 @@ class TransactionJournalFactory
|
|||||||
private PiggyBankRepositoryInterface $piggyRepository;
|
private PiggyBankRepositoryInterface $piggyRepository;
|
||||||
private TransactionTypeRepositoryInterface $typeRepository;
|
private TransactionTypeRepositoryInterface $typeRepository;
|
||||||
private User $user;
|
private User $user;
|
||||||
|
private UserGroup $userGroup;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor.
|
* Constructor.
|
||||||
@@ -176,7 +178,6 @@ class TransactionJournalFactory
|
|||||||
if (true === FireflyConfig::get('utc', false)->data) {
|
if (true === FireflyConfig::get('utc', false)->data) {
|
||||||
$carbon->setTimezone('UTC');
|
$carbon->setTimezone('UTC');
|
||||||
}
|
}
|
||||||
// $carbon->setTimezone('UTC');
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// validate source and destination using a new Validator.
|
// validate source and destination using a new Validator.
|
||||||
@@ -228,7 +229,7 @@ class TransactionJournalFactory
|
|||||||
$journal = TransactionJournal::create(
|
$journal = TransactionJournal::create(
|
||||||
[
|
[
|
||||||
'user_id' => $this->user->id,
|
'user_id' => $this->user->id,
|
||||||
'user_group_id' => $this->user->user_group_id,
|
'user_group_id' => $this->userGroup->id,
|
||||||
'transaction_type_id' => $type->id,
|
'transaction_type_id' => $type->id,
|
||||||
'bill_id' => $billId,
|
'bill_id' => $billId,
|
||||||
'transaction_currency_id' => $currency->id,
|
'transaction_currency_id' => $currency->id,
|
||||||
@@ -244,7 +245,6 @@ class TransactionJournalFactory
|
|||||||
|
|
||||||
/** Create two transactions. */
|
/** Create two transactions. */
|
||||||
$transactionFactory = app(TransactionFactory::class);
|
$transactionFactory = app(TransactionFactory::class);
|
||||||
$transactionFactory->setUser($this->user);
|
|
||||||
$transactionFactory->setJournal($journal);
|
$transactionFactory->setJournal($journal);
|
||||||
$transactionFactory->setAccount($sourceAccount);
|
$transactionFactory->setAccount($sourceAccount);
|
||||||
$transactionFactory->setCurrency($currency);
|
$transactionFactory->setCurrency($currency);
|
||||||
@@ -263,7 +263,6 @@ class TransactionJournalFactory
|
|||||||
|
|
||||||
/** @var TransactionFactory $transactionFactory */
|
/** @var TransactionFactory $transactionFactory */
|
||||||
$transactionFactory = app(TransactionFactory::class);
|
$transactionFactory = app(TransactionFactory::class);
|
||||||
$transactionFactory->setUser($this->user);
|
|
||||||
$transactionFactory->setJournal($journal);
|
$transactionFactory->setJournal($journal);
|
||||||
$transactionFactory->setAccount($destinationAccount);
|
$transactionFactory->setAccount($destinationAccount);
|
||||||
$transactionFactory->setAccountInformation($destInfo);
|
$transactionFactory->setAccountInformation($destInfo);
|
||||||
@@ -404,7 +403,8 @@ class TransactionJournalFactory
|
|||||||
*/
|
*/
|
||||||
public function setUser(User $user): void
|
public function setUser(User $user): void
|
||||||
{
|
{
|
||||||
$this->user = $user;
|
$this->user = $user;
|
||||||
|
$this->userGroup = $user->userGroup;
|
||||||
$this->currencyRepository->setUser($this->user);
|
$this->currencyRepository->setUser($this->user);
|
||||||
$this->tagFactory->setUser($user);
|
$this->tagFactory->setUser($user);
|
||||||
$this->billRepository->setUser($this->user);
|
$this->billRepository->setUser($this->user);
|
||||||
@@ -414,6 +414,18 @@ class TransactionJournalFactory
|
|||||||
$this->accountRepository->setUser($this->user);
|
$this->accountRepository->setUser($this->user);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function setUserGroup(UserGroup $userGroup): void
|
||||||
|
{
|
||||||
|
$this->userGroup = $userGroup;
|
||||||
|
$this->currencyRepository->setUserGroup($userGroup);
|
||||||
|
$this->tagFactory->setUserGroup($userGroup);
|
||||||
|
$this->billRepository->setUserGroup($userGroup);
|
||||||
|
$this->budgetRepository->setUserGroup($userGroup);
|
||||||
|
$this->categoryRepository->setUserGroup($userGroup);
|
||||||
|
$this->piggyRepository->setUserGroup($userGroup);
|
||||||
|
$this->accountRepository->setUserGroup($userGroup);
|
||||||
|
}
|
||||||
|
|
||||||
private function reconciliationSanityCheck(?Account $sourceAccount, ?Account $destinationAccount): array
|
private function reconciliationSanityCheck(?Account $sourceAccount, ?Account $destinationAccount): array
|
||||||
{
|
{
|
||||||
app('log')->debug(sprintf('Now in %s', __METHOD__));
|
app('log')->debug(sprintf('Now in %s', __METHOD__));
|
||||||
|
@@ -33,6 +33,7 @@ use FireflyIII\Repositories\Account\AccountRepositoryInterface;
|
|||||||
use FireflyIII\Repositories\Journal\JournalRepositoryInterface;
|
use FireflyIII\Repositories\Journal\JournalRepositoryInterface;
|
||||||
use FireflyIII\Support\Facades\Steam;
|
use FireflyIII\Support\Facades\Steam;
|
||||||
use Illuminate\Support\Collection;
|
use Illuminate\Support\Collection;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class MonthReportGenerator.
|
* Class MonthReportGenerator.
|
||||||
@@ -52,7 +53,9 @@ class MonthReportGenerator implements ReportGeneratorInterface
|
|||||||
{
|
{
|
||||||
$auditData = [];
|
$auditData = [];
|
||||||
$dayBefore = clone $this->start;
|
$dayBefore = clone $this->start;
|
||||||
$dayBefore->subDay();
|
|
||||||
|
// set date to subday + end-of-day for account balance. so it is at $date 23:59:59
|
||||||
|
$dayBefore->subDay()->endOfDay();
|
||||||
|
|
||||||
/** @var Account $account */
|
/** @var Account $account */
|
||||||
foreach ($this->accounts as $account) {
|
foreach ($this->accounts as $account) {
|
||||||
@@ -133,6 +136,8 @@ class MonthReportGenerator implements ReportGeneratorInterface
|
|||||||
;
|
;
|
||||||
$journals = $collector->getExtractedJournals();
|
$journals = $collector->getExtractedJournals();
|
||||||
$journals = array_reverse($journals, true);
|
$journals = array_reverse($journals, true);
|
||||||
|
// this call is correct.
|
||||||
|
Log::debug(sprintf('getAuditReport: Call finalAccountBalance with date/time "%s"', $date->toIso8601String()));
|
||||||
$dayBeforeBalance = Steam::finalAccountBalance($account, $date);
|
$dayBeforeBalance = Steam::finalAccountBalance($account, $date);
|
||||||
$startBalance = $dayBeforeBalance['balance'];
|
$startBalance = $dayBeforeBalance['balance'];
|
||||||
$defaultCurrency = app('amount')->getNativeCurrencyByUserGroup($account->user->userGroup);
|
$defaultCurrency = app('amount')->getNativeCurrencyByUserGroup($account->user->userGroup);
|
||||||
@@ -167,6 +172,8 @@ class MonthReportGenerator implements ReportGeneratorInterface
|
|||||||
$journals[$index]['invoice_date'] = $journalRepository->getMetaDateById($journal['transaction_journal_id'], 'invoice_date');
|
$journals[$index]['invoice_date'] = $journalRepository->getMetaDateById($journal['transaction_journal_id'], 'invoice_date');
|
||||||
}
|
}
|
||||||
$locale = app('steam')->getLocale();
|
$locale = app('steam')->getLocale();
|
||||||
|
// call is correct.
|
||||||
|
Log::debug(sprintf('getAuditReport end: Call finalAccountBalance with date/time "%s"', $this->end->toIso8601String()));
|
||||||
|
|
||||||
return [
|
return [
|
||||||
'journals' => $journals,
|
'journals' => $journals,
|
||||||
|
@@ -61,8 +61,12 @@ class PreferencesEventHandler
|
|||||||
$this->resetTransactions($event->userGroup);
|
$this->resetTransactions($event->userGroup);
|
||||||
// fire laravel command to recalculate them all.
|
// fire laravel command to recalculate them all.
|
||||||
if (Amount::convertToNative()) {
|
if (Amount::convertToNative()) {
|
||||||
|
Log::debug('Will now convert to native.');
|
||||||
Artisan::call('correction:recalculate-native-amounts');
|
Artisan::call('correction:recalculate-native-amounts');
|
||||||
|
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
Log::debug('Will NOT convert to native.');
|
||||||
}
|
}
|
||||||
|
|
||||||
private function resetPiggyBanks(UserGroup $userGroup): void
|
private function resetPiggyBanks(UserGroup $userGroup): void
|
||||||
|
@@ -38,10 +38,17 @@ use Illuminate\Support\Collection;
|
|||||||
*/
|
*/
|
||||||
class StoredGroupEventHandler
|
class StoredGroupEventHandler
|
||||||
{
|
{
|
||||||
|
public function runAllHandlers(StoredTransactionGroup $event): void
|
||||||
|
{
|
||||||
|
$this->processRules($event);
|
||||||
|
$this->recalculateCredit($event);
|
||||||
|
$this->triggerWebhooks($event);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This method grabs all the users rules and processes them.
|
* This method grabs all the users rules and processes them.
|
||||||
*/
|
*/
|
||||||
public function processRules(StoredTransactionGroup $storedGroupEvent): void
|
private function processRules(StoredTransactionGroup $storedGroupEvent): void
|
||||||
{
|
{
|
||||||
if (false === $storedGroupEvent->applyRules) {
|
if (false === $storedGroupEvent->applyRules) {
|
||||||
app('log')->info(sprintf('Will not run rules on group #%d', $storedGroupEvent->transactionGroup->id));
|
app('log')->info(sprintf('Will not run rules on group #%d', $storedGroupEvent->transactionGroup->id));
|
||||||
@@ -76,7 +83,7 @@ class StoredGroupEventHandler
|
|||||||
$newRuleEngine->fire();
|
$newRuleEngine->fire();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function recalculateCredit(StoredTransactionGroup $event): void
|
private function recalculateCredit(StoredTransactionGroup $event): void
|
||||||
{
|
{
|
||||||
$group = $event->transactionGroup;
|
$group = $event->transactionGroup;
|
||||||
|
|
||||||
@@ -89,7 +96,7 @@ class StoredGroupEventHandler
|
|||||||
/**
|
/**
|
||||||
* This method processes all webhooks that respond to the "stored transaction group" trigger (100)
|
* This method processes all webhooks that respond to the "stored transaction group" trigger (100)
|
||||||
*/
|
*/
|
||||||
public function triggerWebhooks(StoredTransactionGroup $storedGroupEvent): void
|
private function triggerWebhooks(StoredTransactionGroup $storedGroupEvent): void
|
||||||
{
|
{
|
||||||
app('log')->debug(__METHOD__);
|
app('log')->debug(__METHOD__);
|
||||||
$group = $storedGroupEvent->transactionGroup;
|
$group = $storedGroupEvent->transactionGroup;
|
||||||
|
@@ -41,10 +41,19 @@ use Illuminate\Support\Collection;
|
|||||||
*/
|
*/
|
||||||
class UpdatedGroupEventHandler
|
class UpdatedGroupEventHandler
|
||||||
{
|
{
|
||||||
|
public function runAllHandlers(UpdatedTransactionGroup $event): void
|
||||||
|
{
|
||||||
|
$this->unifyAccounts($event);
|
||||||
|
$this->processRules($event);
|
||||||
|
$this->recalculateCredit($event);
|
||||||
|
$this->triggerWebhooks($event);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This method will check all the rules when a journal is updated.
|
* This method will check all the rules when a journal is updated.
|
||||||
*/
|
*/
|
||||||
public function processRules(UpdatedTransactionGroup $updatedGroupEvent): void
|
private function processRules(UpdatedTransactionGroup $updatedGroupEvent): void
|
||||||
{
|
{
|
||||||
if (false === $updatedGroupEvent->applyRules) {
|
if (false === $updatedGroupEvent->applyRules) {
|
||||||
app('log')->info(sprintf('Will not run rules on group #%d', $updatedGroupEvent->transactionGroup->id));
|
app('log')->info(sprintf('Will not run rules on group #%d', $updatedGroupEvent->transactionGroup->id));
|
||||||
@@ -76,7 +85,7 @@ class UpdatedGroupEventHandler
|
|||||||
$newRuleEngine->fire();
|
$newRuleEngine->fire();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function recalculateCredit(UpdatedTransactionGroup $event): void
|
private function recalculateCredit(UpdatedTransactionGroup $event): void
|
||||||
{
|
{
|
||||||
$group = $event->transactionGroup;
|
$group = $event->transactionGroup;
|
||||||
|
|
||||||
@@ -86,7 +95,7 @@ class UpdatedGroupEventHandler
|
|||||||
$object->recalculate();
|
$object->recalculate();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function triggerWebhooks(UpdatedTransactionGroup $updatedGroupEvent): void
|
private function triggerWebhooks(UpdatedTransactionGroup $updatedGroupEvent): void
|
||||||
{
|
{
|
||||||
app('log')->debug(__METHOD__);
|
app('log')->debug(__METHOD__);
|
||||||
$group = $updatedGroupEvent->transactionGroup;
|
$group = $updatedGroupEvent->transactionGroup;
|
||||||
|
@@ -25,7 +25,9 @@ declare(strict_types=1);
|
|||||||
namespace FireflyIII\Handlers\Observer;
|
namespace FireflyIII\Handlers\Observer;
|
||||||
|
|
||||||
use FireflyIII\Models\Account;
|
use FireflyIII\Models\Account;
|
||||||
|
use FireflyIII\Models\Attachment;
|
||||||
use FireflyIII\Models\PiggyBank;
|
use FireflyIII\Models\PiggyBank;
|
||||||
|
use FireflyIII\Repositories\Attachment\AttachmentRepositoryInterface;
|
||||||
use FireflyIII\Repositories\UserGroups\Account\AccountRepositoryInterface;
|
use FireflyIII\Repositories\UserGroups\Account\AccountRepositoryInterface;
|
||||||
use FireflyIII\Support\Facades\Amount;
|
use FireflyIII\Support\Facades\Amount;
|
||||||
use FireflyIII\Support\Http\Api\ExchangeRateConverter;
|
use FireflyIII\Support\Http\Api\ExchangeRateConverter;
|
||||||
@@ -52,6 +54,7 @@ class AccountObserver
|
|||||||
$currency = $repository->getAccountCurrency($account);
|
$currency = $repository->getAccountCurrency($account);
|
||||||
if (null !== $currency && $currency->id !== $userCurrency->id && '' !== (string) $account->virtual_balance && 0 !== bccomp($account->virtual_balance, '0')) {
|
if (null !== $currency && $currency->id !== $userCurrency->id && '' !== (string) $account->virtual_balance && 0 !== bccomp($account->virtual_balance, '0')) {
|
||||||
$converter = new ExchangeRateConverter();
|
$converter = new ExchangeRateConverter();
|
||||||
|
$converter->setUserGroup($account->user->userGroup);
|
||||||
$converter->setIgnoreSettings(true);
|
$converter->setIgnoreSettings(true);
|
||||||
$account->native_virtual_balance = $converter->convert($currency, $userCurrency, today(), $account->virtual_balance);
|
$account->native_virtual_balance = $converter->convert($currency, $userCurrency, today(), $account->virtual_balance);
|
||||||
|
|
||||||
@@ -72,12 +75,17 @@ class AccountObserver
|
|||||||
// app('log')->debug('Observe "deleting" of an account.');
|
// app('log')->debug('Observe "deleting" of an account.');
|
||||||
$account->accountMeta()->delete();
|
$account->accountMeta()->delete();
|
||||||
|
|
||||||
|
$repository = app(AttachmentRepositoryInterface::class);
|
||||||
|
$repository->setUser($account->user);
|
||||||
|
|
||||||
/** @var PiggyBank $piggy */
|
/** @var PiggyBank $piggy */
|
||||||
foreach ($account->piggyBanks()->get() as $piggy) {
|
foreach ($account->piggyBanks()->get() as $piggy) {
|
||||||
$piggy->accounts()->detach($account);
|
$piggy->accounts()->detach($account);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @var Attachment $attachment */
|
||||||
foreach ($account->attachments()->get() as $attachment) {
|
foreach ($account->attachments()->get() as $attachment) {
|
||||||
$attachment->delete();
|
$repository->destroy($attachment);
|
||||||
}
|
}
|
||||||
foreach ($account->transactions()->get() as $transaction) {
|
foreach ($account->transactions()->get() as $transaction) {
|
||||||
$transaction->delete();
|
$transaction->delete();
|
||||||
|
@@ -52,6 +52,7 @@ class AutoBudgetObserver
|
|||||||
$autoBudget->native_amount = null;
|
$autoBudget->native_amount = null;
|
||||||
if ($autoBudget->transactionCurrency->id !== $userCurrency->id) {
|
if ($autoBudget->transactionCurrency->id !== $userCurrency->id) {
|
||||||
$converter = new ExchangeRateConverter();
|
$converter = new ExchangeRateConverter();
|
||||||
|
$converter->setUserGroup($autoBudget->budget->user->userGroup);
|
||||||
$converter->setIgnoreSettings(true);
|
$converter->setIgnoreSettings(true);
|
||||||
$autoBudget->native_amount = $converter->convert($autoBudget->transactionCurrency, $userCurrency, today(), $autoBudget->amount);
|
$autoBudget->native_amount = $converter->convert($autoBudget->transactionCurrency, $userCurrency, today(), $autoBudget->amount);
|
||||||
}
|
}
|
||||||
|
@@ -23,7 +23,9 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace FireflyIII\Handlers\Observer;
|
namespace FireflyIII\Handlers\Observer;
|
||||||
|
|
||||||
|
use FireflyIII\Models\Attachment;
|
||||||
use FireflyIII\Models\Bill;
|
use FireflyIII\Models\Bill;
|
||||||
|
use FireflyIII\Repositories\Attachment\AttachmentRepositoryInterface;
|
||||||
use FireflyIII\Support\Facades\Amount;
|
use FireflyIII\Support\Facades\Amount;
|
||||||
use FireflyIII\Support\Http\Api\ExchangeRateConverter;
|
use FireflyIII\Support\Http\Api\ExchangeRateConverter;
|
||||||
use Illuminate\Support\Facades\Log;
|
use Illuminate\Support\Facades\Log;
|
||||||
@@ -41,9 +43,13 @@ class BillObserver
|
|||||||
|
|
||||||
public function deleting(Bill $bill): void
|
public function deleting(Bill $bill): void
|
||||||
{
|
{
|
||||||
|
$repository = app(AttachmentRepositoryInterface::class);
|
||||||
|
$repository->setUser($bill->user);
|
||||||
|
|
||||||
// app('log')->debug('Observe "deleting" of a bill.');
|
// app('log')->debug('Observe "deleting" of a bill.');
|
||||||
|
/** @var Attachment $attachment */
|
||||||
foreach ($bill->attachments()->get() as $attachment) {
|
foreach ($bill->attachments()->get() as $attachment) {
|
||||||
$attachment->delete();
|
$repository->destroy($attachment);
|
||||||
}
|
}
|
||||||
$bill->notes()->delete();
|
$bill->notes()->delete();
|
||||||
}
|
}
|
||||||
@@ -64,6 +70,7 @@ class BillObserver
|
|||||||
$bill->native_amount_max = null;
|
$bill->native_amount_max = null;
|
||||||
if ($bill->transactionCurrency->id !== $userCurrency->id) {
|
if ($bill->transactionCurrency->id !== $userCurrency->id) {
|
||||||
$converter = new ExchangeRateConverter();
|
$converter = new ExchangeRateConverter();
|
||||||
|
$converter->setUserGroup($bill->user->userGroup);
|
||||||
$converter->setIgnoreSettings(true);
|
$converter->setIgnoreSettings(true);
|
||||||
$bill->native_amount_min = $converter->convert($bill->transactionCurrency, $userCurrency, today(), $bill->amount_min);
|
$bill->native_amount_min = $converter->convert($bill->transactionCurrency, $userCurrency, today(), $bill->amount_min);
|
||||||
$bill->native_amount_max = $converter->convert($bill->transactionCurrency, $userCurrency, today(), $bill->amount_max);
|
$bill->native_amount_max = $converter->convert($bill->transactionCurrency, $userCurrency, today(), $bill->amount_max);
|
||||||
|
@@ -54,6 +54,7 @@ class BudgetLimitObserver
|
|||||||
$budgetLimit->native_amount = null;
|
$budgetLimit->native_amount = null;
|
||||||
if ($budgetLimit->transactionCurrency->id !== $userCurrency->id) {
|
if ($budgetLimit->transactionCurrency->id !== $userCurrency->id) {
|
||||||
$converter = new ExchangeRateConverter();
|
$converter = new ExchangeRateConverter();
|
||||||
|
$converter->setUserGroup($budgetLimit->budget->user->userGroup);
|
||||||
$converter->setIgnoreSettings(true);
|
$converter->setIgnoreSettings(true);
|
||||||
$budgetLimit->native_amount = $converter->convert($budgetLimit->transactionCurrency, $userCurrency, today(), $budgetLimit->amount);
|
$budgetLimit->native_amount = $converter->convert($budgetLimit->transactionCurrency, $userCurrency, today(), $budgetLimit->amount);
|
||||||
}
|
}
|
||||||
|
@@ -23,8 +23,10 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace FireflyIII\Handlers\Observer;
|
namespace FireflyIII\Handlers\Observer;
|
||||||
|
|
||||||
|
use FireflyIII\Models\Attachment;
|
||||||
use FireflyIII\Models\Budget;
|
use FireflyIII\Models\Budget;
|
||||||
use FireflyIII\Models\BudgetLimit;
|
use FireflyIII\Models\BudgetLimit;
|
||||||
|
use FireflyIII\Repositories\Attachment\AttachmentRepositoryInterface;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class BudgetObserver
|
* Class BudgetObserver
|
||||||
@@ -34,8 +36,13 @@ class BudgetObserver
|
|||||||
public function deleting(Budget $budget): void
|
public function deleting(Budget $budget): void
|
||||||
{
|
{
|
||||||
app('log')->debug('Observe "deleting" of a budget.');
|
app('log')->debug('Observe "deleting" of a budget.');
|
||||||
|
|
||||||
|
$repository = app(AttachmentRepositoryInterface::class);
|
||||||
|
$repository->setUser($budget->user);
|
||||||
|
|
||||||
|
/** @var Attachment $attachment */
|
||||||
foreach ($budget->attachments()->get() as $attachment) {
|
foreach ($budget->attachments()->get() as $attachment) {
|
||||||
$attachment->delete();
|
$repository->destroy($attachment);
|
||||||
}
|
}
|
||||||
$budgetLimits = $budget->budgetlimits()->get();
|
$budgetLimits = $budget->budgetlimits()->get();
|
||||||
|
|
||||||
|
@@ -23,7 +23,9 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace FireflyIII\Handlers\Observer;
|
namespace FireflyIII\Handlers\Observer;
|
||||||
|
|
||||||
|
use FireflyIII\Models\Attachment;
|
||||||
use FireflyIII\Models\Category;
|
use FireflyIII\Models\Category;
|
||||||
|
use FireflyIII\Repositories\Attachment\AttachmentRepositoryInterface;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class CategoryObserver
|
* Class CategoryObserver
|
||||||
@@ -33,8 +35,13 @@ class CategoryObserver
|
|||||||
public function deleting(Category $category): void
|
public function deleting(Category $category): void
|
||||||
{
|
{
|
||||||
app('log')->debug('Observe "deleting" of a category.');
|
app('log')->debug('Observe "deleting" of a category.');
|
||||||
|
|
||||||
|
$repository = app(AttachmentRepositoryInterface::class);
|
||||||
|
$repository->setUser($category->user);
|
||||||
|
|
||||||
|
/** @var Attachment $attachment */
|
||||||
foreach ($category->attachments()->get() as $attachment) {
|
foreach ($category->attachments()->get() as $attachment) {
|
||||||
$attachment->delete();
|
$repository->destroy($attachment);
|
||||||
}
|
}
|
||||||
$category->notes()->delete();
|
$category->notes()->delete();
|
||||||
}
|
}
|
||||||
|
@@ -52,6 +52,7 @@ class PiggyBankEventObserver
|
|||||||
$event->native_amount = null;
|
$event->native_amount = null;
|
||||||
if ($event->piggyBank->transactionCurrency->id !== $userCurrency->id) {
|
if ($event->piggyBank->transactionCurrency->id !== $userCurrency->id) {
|
||||||
$converter = new ExchangeRateConverter();
|
$converter = new ExchangeRateConverter();
|
||||||
|
$converter->setUserGroup($event->piggyBank->accounts()->first()->user->userGroup);
|
||||||
$converter->setIgnoreSettings(true);
|
$converter->setIgnoreSettings(true);
|
||||||
$event->native_amount = $converter->convert($event->piggyBank->transactionCurrency, $userCurrency, today(), $event->amount);
|
$event->native_amount = $converter->convert($event->piggyBank->transactionCurrency, $userCurrency, today(), $event->amount);
|
||||||
}
|
}
|
||||||
|
@@ -24,7 +24,9 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace FireflyIII\Handlers\Observer;
|
namespace FireflyIII\Handlers\Observer;
|
||||||
|
|
||||||
|
use FireflyIII\Models\Attachment;
|
||||||
use FireflyIII\Models\PiggyBank;
|
use FireflyIII\Models\PiggyBank;
|
||||||
|
use FireflyIII\Repositories\Attachment\AttachmentRepositoryInterface;
|
||||||
use FireflyIII\Support\Http\Api\ExchangeRateConverter;
|
use FireflyIII\Support\Http\Api\ExchangeRateConverter;
|
||||||
use Illuminate\Support\Facades\Log;
|
use Illuminate\Support\Facades\Log;
|
||||||
|
|
||||||
@@ -46,8 +48,12 @@ class PiggyBankObserver
|
|||||||
{
|
{
|
||||||
app('log')->debug('Observe "deleting" of a piggy bank.');
|
app('log')->debug('Observe "deleting" of a piggy bank.');
|
||||||
|
|
||||||
|
$repository = app(AttachmentRepositoryInterface::class);
|
||||||
|
$repository->setUser($piggyBank->accounts()->first()->user);
|
||||||
|
|
||||||
|
/** @var Attachment $attachment */
|
||||||
foreach ($piggyBank->attachments()->get() as $attachment) {
|
foreach ($piggyBank->attachments()->get() as $attachment) {
|
||||||
$attachment->delete();
|
$repository->destroy($attachment);
|
||||||
}
|
}
|
||||||
|
|
||||||
$piggyBank->piggyBankEvents()->delete();
|
$piggyBank->piggyBankEvents()->delete();
|
||||||
|
@@ -23,7 +23,9 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace FireflyIII\Handlers\Observer;
|
namespace FireflyIII\Handlers\Observer;
|
||||||
|
|
||||||
|
use FireflyIII\Models\Attachment;
|
||||||
use FireflyIII\Models\Recurrence;
|
use FireflyIII\Models\Recurrence;
|
||||||
|
use FireflyIII\Repositories\Attachment\AttachmentRepositoryInterface;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class RecurrenceObserver
|
* Class RecurrenceObserver
|
||||||
@@ -33,8 +35,13 @@ class RecurrenceObserver
|
|||||||
public function deleting(Recurrence $recurrence): void
|
public function deleting(Recurrence $recurrence): void
|
||||||
{
|
{
|
||||||
app('log')->debug('Observe "deleting" of a recurrence.');
|
app('log')->debug('Observe "deleting" of a recurrence.');
|
||||||
|
|
||||||
|
$repository = app(AttachmentRepositoryInterface::class);
|
||||||
|
$repository->setUser($recurrence->user);
|
||||||
|
|
||||||
|
/** @var Attachment $attachment */
|
||||||
foreach ($recurrence->attachments()->get() as $attachment) {
|
foreach ($recurrence->attachments()->get() as $attachment) {
|
||||||
$attachment->delete();
|
$repository->destroy($attachment);
|
||||||
}
|
}
|
||||||
|
|
||||||
$recurrence->recurrenceRepetitions()->delete();
|
$recurrence->recurrenceRepetitions()->delete();
|
||||||
|
@@ -23,7 +23,9 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace FireflyIII\Handlers\Observer;
|
namespace FireflyIII\Handlers\Observer;
|
||||||
|
|
||||||
|
use FireflyIII\Models\Attachment;
|
||||||
use FireflyIII\Models\Tag;
|
use FireflyIII\Models\Tag;
|
||||||
|
use FireflyIII\Repositories\Attachment\AttachmentRepositoryInterface;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class TagObserver
|
* Class TagObserver
|
||||||
@@ -34,8 +36,12 @@ class TagObserver
|
|||||||
{
|
{
|
||||||
app('log')->debug('Observe "deleting" of a tag.');
|
app('log')->debug('Observe "deleting" of a tag.');
|
||||||
|
|
||||||
|
$repository = app(AttachmentRepositoryInterface::class);
|
||||||
|
$repository->setUser($tag->user);
|
||||||
|
|
||||||
|
/** @var Attachment $attachment */
|
||||||
foreach ($tag->attachments()->get() as $attachment) {
|
foreach ($tag->attachments()->get() as $attachment) {
|
||||||
$attachment->delete();
|
$repository->destroy($attachment);
|
||||||
}
|
}
|
||||||
|
|
||||||
$tag->locations()->delete();
|
$tag->locations()->delete();
|
||||||
|
@@ -23,7 +23,9 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace FireflyIII\Handlers\Observer;
|
namespace FireflyIII\Handlers\Observer;
|
||||||
|
|
||||||
|
use FireflyIII\Models\Attachment;
|
||||||
use FireflyIII\Models\TransactionJournal;
|
use FireflyIII\Models\TransactionJournal;
|
||||||
|
use FireflyIII\Repositories\Attachment\AttachmentRepositoryInterface;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class TransactionJournalObserver
|
* Class TransactionJournalObserver
|
||||||
@@ -34,14 +36,20 @@ class TransactionJournalObserver
|
|||||||
{
|
{
|
||||||
app('log')->debug('Observe "deleting" of a transaction journal.');
|
app('log')->debug('Observe "deleting" of a transaction journal.');
|
||||||
|
|
||||||
|
$repository = app(AttachmentRepositoryInterface::class);
|
||||||
|
$repository->setUser($transactionJournal->user);
|
||||||
|
|
||||||
|
|
||||||
// to make sure the listener doesn't get back to use and loop
|
// to make sure the listener doesn't get back to use and loop
|
||||||
TransactionJournal::withoutEvents(static function () use ($transactionJournal): void {
|
TransactionJournal::withoutEvents(static function () use ($transactionJournal): void {
|
||||||
foreach ($transactionJournal->transactions()->get() as $transaction) {
|
foreach ($transactionJournal->transactions()->get() as $transaction) {
|
||||||
$transaction->delete();
|
$transaction->delete();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/** @var Attachment $attachment */
|
||||||
foreach ($transactionJournal->attachments()->get() as $attachment) {
|
foreach ($transactionJournal->attachments()->get() as $attachment) {
|
||||||
$attachment->delete();
|
$repository->destroy($attachment);
|
||||||
}
|
}
|
||||||
$transactionJournal->locations()->delete();
|
$transactionJournal->locations()->delete();
|
||||||
$transactionJournal->sourceJournalLinks()->delete();
|
$transactionJournal->sourceJournalLinks()->delete();
|
||||||
|
@@ -258,7 +258,12 @@ trait AccountCollection
|
|||||||
if (null === $account) {
|
if (null === $account) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
$balance = Steam::finalAccountBalance($account, $transaction['date']);
|
// the balance must be found BEFORE the transaction date.
|
||||||
|
// so sub one second. This is not perfect, but works well enough.
|
||||||
|
$date = clone $transaction['date'];
|
||||||
|
$date->subSecond();
|
||||||
|
Log::debug(sprintf('accountBalanceIs: Call finalAccountBalance with date/time "%s"', $date->toIso8601String()));
|
||||||
|
$balance = Steam::finalAccountBalance($account, $date);
|
||||||
$result = bccomp($balance['balance'], $value);
|
$result = bccomp($balance['balance'], $value);
|
||||||
Log::debug(sprintf('"%s" vs "%s" is %d', $balance['balance'], $value, $result));
|
Log::debug(sprintf('"%s" vs "%s" is %d', $balance['balance'], $value, $result));
|
||||||
|
|
||||||
|
@@ -167,6 +167,7 @@ trait MetaCollection
|
|||||||
$this->joinMetaDataTables();
|
$this->joinMetaDataTables();
|
||||||
$this->query->where('journal_meta.name', '=', 'external_id');
|
$this->query->where('journal_meta.name', '=', 'external_id');
|
||||||
$this->query->where('journal_meta.data', '!=', sprintf('%s', json_encode($externalId)));
|
$this->query->where('journal_meta.data', '!=', sprintf('%s', json_encode($externalId)));
|
||||||
|
$this->query->whereNull('journal_meta.deleted_at');
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
@@ -405,6 +406,7 @@ trait MetaCollection
|
|||||||
$this->joinMetaDataTables();
|
$this->joinMetaDataTables();
|
||||||
$this->query->where('journal_meta.name', '=', 'internal_reference');
|
$this->query->where('journal_meta.name', '=', 'internal_reference');
|
||||||
$this->query->whereLike('journal_meta.data', sprintf('%%%s%%', $internalReference));
|
$this->query->whereLike('journal_meta.data', sprintf('%%%s%%', $internalReference));
|
||||||
|
$this->query->whereNull('journal_meta.deleted_at');
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
@@ -417,6 +419,7 @@ trait MetaCollection
|
|||||||
$this->joinMetaDataTables();
|
$this->joinMetaDataTables();
|
||||||
$this->query->where('journal_meta.name', '=', 'internal_reference');
|
$this->query->where('journal_meta.name', '=', 'internal_reference');
|
||||||
$this->query->whereNotLike('journal_meta.data', sprintf('%%%s%%', $internalReference));
|
$this->query->whereNotLike('journal_meta.data', sprintf('%%%s%%', $internalReference));
|
||||||
|
$this->query->whereNull('journal_meta.deleted_at');
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
@@ -429,6 +432,7 @@ trait MetaCollection
|
|||||||
$this->joinMetaDataTables();
|
$this->joinMetaDataTables();
|
||||||
$this->query->where('journal_meta.name', '=', 'internal_reference');
|
$this->query->where('journal_meta.name', '=', 'internal_reference');
|
||||||
$this->query->whereNotLike('journal_meta.data', sprintf('%%%s"', $internalReference));
|
$this->query->whereNotLike('journal_meta.data', sprintf('%%%s"', $internalReference));
|
||||||
|
$this->query->whereNull('journal_meta.deleted_at');
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
@@ -441,6 +445,7 @@ trait MetaCollection
|
|||||||
$this->joinMetaDataTables();
|
$this->joinMetaDataTables();
|
||||||
$this->query->where('journal_meta.name', '=', 'internal_reference');
|
$this->query->where('journal_meta.name', '=', 'internal_reference');
|
||||||
$this->query->whereLike('journal_meta.data', sprintf('"%s%%', $internalReference));
|
$this->query->whereLike('journal_meta.data', sprintf('"%s%%', $internalReference));
|
||||||
|
$this->query->whereNull('journal_meta.deleted_at');
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
@@ -453,6 +458,7 @@ trait MetaCollection
|
|||||||
$this->joinMetaDataTables();
|
$this->joinMetaDataTables();
|
||||||
$this->query->where('journal_meta.name', '=', 'internal_reference');
|
$this->query->where('journal_meta.name', '=', 'internal_reference');
|
||||||
$this->query->whereLike('journal_meta.data', sprintf('%%%s"', $internalReference));
|
$this->query->whereLike('journal_meta.data', sprintf('%%%s"', $internalReference));
|
||||||
|
$this->query->whereNull('journal_meta.deleted_at');
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
@@ -465,6 +471,7 @@ trait MetaCollection
|
|||||||
$this->joinMetaDataTables();
|
$this->joinMetaDataTables();
|
||||||
$this->query->where('journal_meta.name', '=', 'internal_reference');
|
$this->query->where('journal_meta.name', '=', 'internal_reference');
|
||||||
$this->query->whereLike('journal_meta.data', sprintf('"%s%%', $internalReference));
|
$this->query->whereLike('journal_meta.data', sprintf('"%s%%', $internalReference));
|
||||||
|
$this->query->whereNull('journal_meta.deleted_at');
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
@@ -697,6 +704,7 @@ trait MetaCollection
|
|||||||
$this->joinMetaDataTables();
|
$this->joinMetaDataTables();
|
||||||
$this->query->where('journal_meta.name', '=', 'external_id');
|
$this->query->where('journal_meta.name', '=', 'external_id');
|
||||||
$this->query->where('journal_meta.data', '=', sprintf('%s', json_encode($externalId)));
|
$this->query->where('journal_meta.data', '=', sprintf('%s', json_encode($externalId)));
|
||||||
|
$this->query->whereNull('journal_meta.deleted_at');
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
@@ -706,6 +714,7 @@ trait MetaCollection
|
|||||||
$this->joinMetaDataTables();
|
$this->joinMetaDataTables();
|
||||||
$this->query->where('journal_meta.name', '=', 'external_url');
|
$this->query->where('journal_meta.name', '=', 'external_url');
|
||||||
$this->query->where('journal_meta.data', '=', json_encode($url));
|
$this->query->where('journal_meta.data', '=', json_encode($url));
|
||||||
|
$this->query->whereNull('journal_meta.deleted_at');
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
@@ -718,6 +727,7 @@ trait MetaCollection
|
|||||||
$this->joinMetaDataTables();
|
$this->joinMetaDataTables();
|
||||||
$this->query->where('journal_meta.name', '=', 'internal_reference');
|
$this->query->where('journal_meta.name', '=', 'internal_reference');
|
||||||
$this->query->where('journal_meta.data', '=', sprintf('%s', json_encode($internalReference)));
|
$this->query->where('journal_meta.data', '=', sprintf('%s', json_encode($internalReference)));
|
||||||
|
$this->query->whereNull('journal_meta.deleted_at');
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
@@ -727,6 +737,7 @@ trait MetaCollection
|
|||||||
$this->joinMetaDataTables();
|
$this->joinMetaDataTables();
|
||||||
$this->query->where('journal_meta.name', '=', 'recurrence_id');
|
$this->query->where('journal_meta.name', '=', 'recurrence_id');
|
||||||
$this->query->where('journal_meta.data', '=', sprintf('%s', json_encode($recurringId)));
|
$this->query->where('journal_meta.data', '=', sprintf('%s', json_encode($recurringId)));
|
||||||
|
$this->query->whereNull('journal_meta.deleted_at');
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
@@ -862,6 +873,7 @@ trait MetaCollection
|
|||||||
$this->joinMetaDataTables();
|
$this->joinMetaDataTables();
|
||||||
$this->query->where('journal_meta.name', '=', 'external_id');
|
$this->query->where('journal_meta.name', '=', 'external_id');
|
||||||
$this->query->whereNotNull('journal_meta.data');
|
$this->query->whereNotNull('journal_meta.data');
|
||||||
|
$this->query->whereNull('journal_meta.deleted_at');
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
@@ -871,6 +883,7 @@ trait MetaCollection
|
|||||||
$this->joinMetaDataTables();
|
$this->joinMetaDataTables();
|
||||||
$this->query->where('journal_meta.name', '=', 'external_url');
|
$this->query->where('journal_meta.name', '=', 'external_url');
|
||||||
$this->query->whereNotNull('journal_meta.data');
|
$this->query->whereNotNull('journal_meta.data');
|
||||||
|
$this->query->whereNull('journal_meta.deleted_at');
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
@@ -915,10 +928,13 @@ trait MetaCollection
|
|||||||
$q1->where(static function (Builder $q2): void {
|
$q1->where(static function (Builder $q2): void {
|
||||||
$q2->where('journal_meta.name', '=', 'external_id');
|
$q2->where('journal_meta.name', '=', 'external_id');
|
||||||
$q2->whereNull('journal_meta.data');
|
$q2->whereNull('journal_meta.data');
|
||||||
|
$q2->whereNull('journal_meta.deleted_at');
|
||||||
})->orWhere(static function (Builder $q3): void {
|
})->orWhere(static function (Builder $q3): void {
|
||||||
$q3->where('journal_meta.name', '!=', 'external_id');
|
$q3->where('journal_meta.name', '!=', 'external_id');
|
||||||
|
$q3->whereNull('journal_meta.deleted_at');
|
||||||
})->orWhere(static function (Builder $q4): void {
|
})->orWhere(static function (Builder $q4): void {
|
||||||
$q4->whereNull('journal_meta.name');
|
$q4->whereNull('journal_meta.name');
|
||||||
|
$q4->whereNull('journal_meta.deleted_at');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -933,10 +949,13 @@ trait MetaCollection
|
|||||||
$q1->where(static function (Builder $q2): void {
|
$q1->where(static function (Builder $q2): void {
|
||||||
$q2->where('journal_meta.name', '=', 'external_url');
|
$q2->where('journal_meta.name', '=', 'external_url');
|
||||||
$q2->whereNull('journal_meta.data');
|
$q2->whereNull('journal_meta.data');
|
||||||
|
$q2->whereNull('journal_meta.deleted_at');
|
||||||
})->orWhere(static function (Builder $q3): void {
|
})->orWhere(static function (Builder $q3): void {
|
||||||
$q3->where('journal_meta.name', '!=', 'external_url');
|
$q3->where('journal_meta.name', '!=', 'external_url');
|
||||||
|
$q3->whereNull('journal_meta.deleted_at');
|
||||||
})->orWhere(static function (Builder $q4): void {
|
})->orWhere(static function (Builder $q4): void {
|
||||||
$q4->whereNull('journal_meta.name');
|
$q4->whereNull('journal_meta.name');
|
||||||
|
$q4->whereNull('journal_meta.deleted_at');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@@ -100,7 +100,7 @@ class GroupCollector implements GroupCollectorInterface
|
|||||||
'category_id',
|
'category_id',
|
||||||
'budget_id',
|
'budget_id',
|
||||||
];
|
];
|
||||||
$this->stringFields = ['amount', 'foreign_amount'];
|
$this->stringFields = ['amount', 'foreign_amount', 'native_amount', 'native_foreign_amount'];
|
||||||
$this->total = 0;
|
$this->total = 0;
|
||||||
$this->fields = [
|
$this->fields = [
|
||||||
// group
|
// group
|
||||||
@@ -710,10 +710,13 @@ class GroupCollector implements GroupCollectorInterface
|
|||||||
foreach ($groups as $groudId => $group) {
|
foreach ($groups as $groudId => $group) {
|
||||||
/** @var array $transaction */
|
/** @var array $transaction */
|
||||||
foreach ($group['transactions'] as $transaction) {
|
foreach ($group['transactions'] as $transaction) {
|
||||||
$currencyId = (int) $transaction['currency_id'];
|
$currencyId = (int) $transaction['currency_id'];
|
||||||
if (null === $transaction['amount']) {
|
if (null === $transaction['amount']) {
|
||||||
throw new FireflyException(sprintf('Amount is NULL for a transaction in group #%d, please investigate.', $groudId));
|
throw new FireflyException(sprintf('Amount is NULL for a transaction in group #%d, please investigate.', $groudId));
|
||||||
}
|
}
|
||||||
|
$nativeAmount = (string) ('' === $transaction['native_amount'] ? '0' : $transaction['native_amount']);
|
||||||
|
$nativeForeignAmount = (string) ('' === $transaction['native_foreign_amount'] ? '0' : $transaction['native_foreign_amount']);
|
||||||
|
$foreignAmount = (string) ('' === $transaction['foreign_amount'] ? '0' : $transaction['foreign_amount']);
|
||||||
|
|
||||||
// set default:
|
// set default:
|
||||||
if (!array_key_exists($currencyId, $groups[$groudId]['sums'])) {
|
if (!array_key_exists($currencyId, $groups[$groudId]['sums'])) {
|
||||||
@@ -722,11 +725,13 @@ class GroupCollector implements GroupCollectorInterface
|
|||||||
$groups[$groudId]['sums'][$currencyId]['currency_symbol'] = $transaction['currency_symbol'];
|
$groups[$groudId]['sums'][$currencyId]['currency_symbol'] = $transaction['currency_symbol'];
|
||||||
$groups[$groudId]['sums'][$currencyId]['currency_decimal_places'] = $transaction['currency_decimal_places'];
|
$groups[$groudId]['sums'][$currencyId]['currency_decimal_places'] = $transaction['currency_decimal_places'];
|
||||||
$groups[$groudId]['sums'][$currencyId]['amount'] = '0';
|
$groups[$groudId]['sums'][$currencyId]['amount'] = '0';
|
||||||
|
$groups[$groudId]['sums'][$currencyId]['native_amount'] = '0';
|
||||||
}
|
}
|
||||||
$groups[$groudId]['sums'][$currencyId]['amount'] = bcadd($groups[$groudId]['sums'][$currencyId]['amount'], $transaction['amount']);
|
$groups[$groudId]['sums'][$currencyId]['amount'] = bcadd($groups[$groudId]['sums'][$currencyId]['amount'], $transaction['amount']);
|
||||||
|
$groups[$groudId]['sums'][$currencyId]['native_amount'] = bcadd($groups[$groudId]['sums'][$currencyId]['native_amount'], $nativeAmount);
|
||||||
|
|
||||||
if (null !== $transaction['foreign_amount'] && null !== $transaction['foreign_currency_id']) {
|
if (null !== $transaction['foreign_amount'] && null !== $transaction['foreign_currency_id']) {
|
||||||
$currencyId = (int) $transaction['foreign_currency_id'];
|
$currencyId = (int) $transaction['foreign_currency_id'];
|
||||||
|
|
||||||
// set default:
|
// set default:
|
||||||
if (!array_key_exists($currencyId, $groups[$groudId]['sums'])) {
|
if (!array_key_exists($currencyId, $groups[$groudId]['sums'])) {
|
||||||
@@ -735,8 +740,10 @@ class GroupCollector implements GroupCollectorInterface
|
|||||||
$groups[$groudId]['sums'][$currencyId]['currency_symbol'] = $transaction['foreign_currency_symbol'];
|
$groups[$groudId]['sums'][$currencyId]['currency_symbol'] = $transaction['foreign_currency_symbol'];
|
||||||
$groups[$groudId]['sums'][$currencyId]['currency_decimal_places'] = $transaction['foreign_currency_decimal_places'];
|
$groups[$groudId]['sums'][$currencyId]['currency_decimal_places'] = $transaction['foreign_currency_decimal_places'];
|
||||||
$groups[$groudId]['sums'][$currencyId]['amount'] = '0';
|
$groups[$groudId]['sums'][$currencyId]['amount'] = '0';
|
||||||
|
$groups[$groudId]['sums'][$currencyId]['native_amount'] = '0';
|
||||||
}
|
}
|
||||||
$groups[$groudId]['sums'][$currencyId]['amount'] = bcadd($groups[$groudId]['sums'][$currencyId]['amount'], $transaction['foreign_amount']);
|
$groups[$groudId]['sums'][$currencyId]['amount'] = bcadd($groups[$groudId]['sums'][$currencyId]['amount'], $foreignAmount);
|
||||||
|
$groups[$groudId]['sums'][$currencyId]['native_amount'] = bcadd($groups[$groudId]['sums'][$currencyId]['amount'], $nativeForeignAmount);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -79,6 +79,7 @@ class NetWorth implements NetWorthInterface
|
|||||||
Log::debug(sprintf('Now in byAccounts("%s", "%s")', $ids, $date->format('Y-m-d H:i:s')));
|
Log::debug(sprintf('Now in byAccounts("%s", "%s")', $ids, $date->format('Y-m-d H:i:s')));
|
||||||
$default = Amount::getNativeCurrency();
|
$default = Amount::getNativeCurrency();
|
||||||
$netWorth = [];
|
$netWorth = [];
|
||||||
|
Log::debug(sprintf('NetWorth: finalAccountsBalance("%s")', $date->format('Y-m-d H:i:s')));
|
||||||
$balances = Steam::finalAccountsBalance($accounts, $date);
|
$balances = Steam::finalAccountsBalance($accounts, $date);
|
||||||
|
|
||||||
/** @var Account $account */
|
/** @var Account $account */
|
||||||
@@ -159,6 +160,7 @@ class NetWorth implements NetWorthInterface
|
|||||||
*/
|
*/
|
||||||
$accounts = $this->getAccounts();
|
$accounts = $this->getAccounts();
|
||||||
$return = [];
|
$return = [];
|
||||||
|
Log::debug(sprintf('SumNetWorth: finalAccountsBalance("%s")', $date->format('Y-m-d H:i:s')));
|
||||||
$balances = Steam::finalAccountsBalance($accounts, $date);
|
$balances = Steam::finalAccountsBalance($accounts, $date);
|
||||||
foreach ($accounts as $account) {
|
foreach ($accounts as $account) {
|
||||||
$currency = $this->getRepository()->getAccountCurrency($account);
|
$currency = $this->getRepository()->getAccountCurrency($account);
|
||||||
|
@@ -33,6 +33,7 @@ use FireflyIII\Support\Http\Controllers\BasicDataSupport;
|
|||||||
use Illuminate\Contracts\View\Factory;
|
use Illuminate\Contracts\View\Factory;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Illuminate\Pagination\LengthAwarePaginator;
|
use Illuminate\Pagination\LengthAwarePaginator;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
use Illuminate\View\View;
|
use Illuminate\View\View;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -90,9 +91,11 @@ class IndexController extends Controller
|
|||||||
$start->subDay();
|
$start->subDay();
|
||||||
|
|
||||||
$ids = $accounts->pluck('id')->toArray();
|
$ids = $accounts->pluck('id')->toArray();
|
||||||
$startBalances = app('steam')->finalAccountsBalance($accounts, $start);
|
Log::debug(sprintf('inactive start: finalAccountsBalance("%s")', $start->format('Y-m-d H:i:s')));
|
||||||
$endBalances = app('steam')->finalAccountsBalance($accounts, $end);
|
Log::debug(sprintf('inactive end: finalAccountsBalance("%s")', $end->format('Y-m-d H:i:s')));
|
||||||
$activities = app('steam')->getLastActivities($ids);
|
$startBalances = Steam::finalAccountsBalance($accounts, $start);
|
||||||
|
$endBalances = Steam::finalAccountsBalance($accounts, $end);
|
||||||
|
$activities = Steam::getLastActivities($ids);
|
||||||
|
|
||||||
|
|
||||||
$accounts->each(
|
$accounts->each(
|
||||||
@@ -102,7 +105,7 @@ class IndexController extends Controller
|
|||||||
$account->startBalances = Steam::filterAccountBalance($startBalances[$account->id] ?? [], $account, $this->convertToNative, $currency);
|
$account->startBalances = Steam::filterAccountBalance($startBalances[$account->id] ?? [], $account, $this->convertToNative, $currency);
|
||||||
$account->endBalances = Steam::filterAccountBalance($endBalances[$account->id] ?? [], $account, $this->convertToNative, $currency);
|
$account->endBalances = Steam::filterAccountBalance($endBalances[$account->id] ?? [], $account, $this->convertToNative, $currency);
|
||||||
$account->differences = $this->subtract($account->startBalances, $account->endBalances);
|
$account->differences = $this->subtract($account->startBalances, $account->endBalances);
|
||||||
$account->interest = app('steam')->bcround($this->repository->getMetaValue($account, 'interest'), 4);
|
$account->interest = Steam::bcround($this->repository->getMetaValue($account, 'interest'), 4);
|
||||||
$account->interestPeriod = (string) trans(sprintf('firefly.interest_calc_%s', $this->repository->getMetaValue($account, 'interest_period')));
|
$account->interestPeriod = (string) trans(sprintf('firefly.interest_calc_%s', $this->repository->getMetaValue($account, 'interest_period')));
|
||||||
$account->accountTypeString = (string) trans(sprintf('firefly.account_type_%s', $account->accountType->type));
|
$account->accountTypeString = (string) trans(sprintf('firefly.account_type_%s', $account->accountType->type));
|
||||||
$account->current_debt = '0';
|
$account->current_debt = '0';
|
||||||
@@ -153,9 +156,11 @@ class IndexController extends Controller
|
|||||||
$start->subDay();
|
$start->subDay();
|
||||||
|
|
||||||
$ids = $accounts->pluck('id')->toArray();
|
$ids = $accounts->pluck('id')->toArray();
|
||||||
$startBalances = app('steam')->finalAccountsBalance($accounts, $start);
|
Log::debug(sprintf('index start: finalAccountsBalance("%s")', $start->format('Y-m-d H:i:s')));
|
||||||
$endBalances = app('steam')->finalAccountsBalance($accounts, $end);
|
Log::debug(sprintf('index end: finalAccountsBalance("%s")', $end->format('Y-m-d H:i:s')));
|
||||||
$activities = app('steam')->getLastActivities($ids);
|
$startBalances = Steam::finalAccountsBalance($accounts, $start);
|
||||||
|
$endBalances = Steam::finalAccountsBalance($accounts, $end);
|
||||||
|
$activities = Steam::getLastActivities($ids);
|
||||||
|
|
||||||
|
|
||||||
$accounts->each(
|
$accounts->each(
|
||||||
@@ -168,7 +173,7 @@ class IndexController extends Controller
|
|||||||
$account->endBalances = Steam::filterAccountBalance($endBalances[$account->id] ?? [], $account, $this->convertToNative, $currency);
|
$account->endBalances = Steam::filterAccountBalance($endBalances[$account->id] ?? [], $account, $this->convertToNative, $currency);
|
||||||
$account->differences = $this->subtract($account->startBalances, $account->endBalances);
|
$account->differences = $this->subtract($account->startBalances, $account->endBalances);
|
||||||
$account->lastActivityDate = $this->isInArrayDate($activities, $account->id);
|
$account->lastActivityDate = $this->isInArrayDate($activities, $account->id);
|
||||||
$account->interest = app('steam')->bcround($interest, 4);
|
$account->interest = Steam::bcround($interest, 4);
|
||||||
$account->interestPeriod = (string) trans(
|
$account->interestPeriod = (string) trans(
|
||||||
sprintf('firefly.interest_calc_%s', $this->repository->getMetaValue($account, 'interest_period'))
|
sprintf('firefly.interest_calc_%s', $this->repository->getMetaValue($account, 'interest_period'))
|
||||||
);
|
);
|
||||||
|
@@ -39,6 +39,7 @@ use FireflyIII\User;
|
|||||||
use Illuminate\Contracts\View\Factory;
|
use Illuminate\Contracts\View\Factory;
|
||||||
use Illuminate\Http\RedirectResponse;
|
use Illuminate\Http\RedirectResponse;
|
||||||
use Illuminate\Routing\Redirector;
|
use Illuminate\Routing\Redirector;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
use Illuminate\View\View;
|
use Illuminate\View\View;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -108,11 +109,17 @@ class ReconcileController extends Controller
|
|||||||
if ($end->lt($start)) {
|
if ($end->lt($start)) {
|
||||||
[$start, $end] = [$end, $start];
|
[$start, $end] = [$end, $start];
|
||||||
}
|
}
|
||||||
|
// move dates to end of day and start of day:
|
||||||
|
$start->startOfDay();
|
||||||
|
$end->endOfDay();
|
||||||
|
|
||||||
$startDate = clone $start;
|
$startDate = clone $start;
|
||||||
$startDate->subDay();
|
$startDate->subDay()->endOfDay(); // this is correct, subday endofday ends at 23:59:59
|
||||||
$startBalance = Steam::finalAccountBalance($account, $startDate)['balance'];
|
// both are validated and are correct.
|
||||||
$endBalance = Steam::finalAccountBalance($account, $end)['balance'];
|
Log::debug(sprintf('reconcile: Call finalAccountBalance with date/time "%s"', $startDate->toIso8601String()));
|
||||||
|
Log::debug(sprintf('reconcile2: Call finalAccountBalance with date/time "%s"', $end->toIso8601String()));
|
||||||
|
$startBalance = Steam::bcround(Steam::finalAccountBalance($account, $startDate)['balance'], $currency->decimal_places);
|
||||||
|
$endBalance = Steam::bcround(Steam::finalAccountBalance($account, $end)['balance'], $currency->decimal_places);
|
||||||
$subTitleIcon = config(sprintf('firefly.subIconsByIdentifier.%s', $account->accountType->type));
|
$subTitleIcon = config(sprintf('firefly.subIconsByIdentifier.%s', $account->accountType->type));
|
||||||
$subTitle = (string) trans('firefly.reconcile_account', ['account' => $account->name]);
|
$subTitle = (string) trans('firefly.reconcile_account', ['account' => $account->name]);
|
||||||
|
|
||||||
|
@@ -37,6 +37,7 @@ use Illuminate\Http\RedirectResponse;
|
|||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Illuminate\Routing\Redirector;
|
use Illuminate\Routing\Redirector;
|
||||||
use Illuminate\Support\Collection;
|
use Illuminate\Support\Collection;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
use Illuminate\View\View;
|
use Illuminate\View\View;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -93,6 +94,11 @@ class ShowController extends Controller
|
|||||||
if ($end->lt($start)) {
|
if ($end->lt($start)) {
|
||||||
[$start, $end] = [$end, $start];
|
[$start, $end] = [$end, $start];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// make sure dates are end of day and start of day:
|
||||||
|
$start->startOfDay();
|
||||||
|
$end->endOfDay();
|
||||||
|
|
||||||
$location = $this->repository->getLocation($account);
|
$location = $this->repository->getLocation($account);
|
||||||
$attachments = $this->repository->getAttachments($account);
|
$attachments = $this->repository->getAttachments($account);
|
||||||
$today = today(config('app.timezone'));
|
$today = today(config('app.timezone'));
|
||||||
@@ -115,12 +121,7 @@ class ShowController extends Controller
|
|||||||
|
|
||||||
/** @var GroupCollectorInterface $collector */
|
/** @var GroupCollectorInterface $collector */
|
||||||
$collector = app(GroupCollectorInterface::class);
|
$collector = app(GroupCollectorInterface::class);
|
||||||
$collector
|
$collector->setAccounts(new Collection([$account]))->setLimit($pageSize)->setPage($page)->withAccountInformation()->withCategoryInformation()->setRange($start, $end);
|
||||||
->setAccounts(new Collection([$account]))
|
|
||||||
->setLimit($pageSize)
|
|
||||||
->setPage($page)->withAccountInformation()->withCategoryInformation()
|
|
||||||
->setRange($start, $end)
|
|
||||||
;
|
|
||||||
|
|
||||||
// this search will not include transaction groups where this asset account (or liability)
|
// this search will not include transaction groups where this asset account (or liability)
|
||||||
// is just part of ONE of the journals. To force this:
|
// is just part of ONE of the journals. To force this:
|
||||||
@@ -130,7 +131,14 @@ class ShowController extends Controller
|
|||||||
|
|
||||||
$groups->setPath(route('accounts.show', [$account->id, $start->format('Y-m-d'), $end->format('Y-m-d')]));
|
$groups->setPath(route('accounts.show', [$account->id, $start->format('Y-m-d'), $end->format('Y-m-d')]));
|
||||||
$showAll = false;
|
$showAll = false;
|
||||||
$balances = Steam::filterAccountBalance(Steam::finalAccountBalance($account, $end), $account, $this->convertToNative, $accountCurrency);
|
// correct
|
||||||
|
$now = today()->endOfDay();
|
||||||
|
if ($now->gt($end) || $now->lt($start)) {
|
||||||
|
$now = $end;
|
||||||
|
}
|
||||||
|
|
||||||
|
Log::debug(sprintf('show: Call finalAccountBalance with date/time "%s"', $now->toIso8601String()));
|
||||||
|
$balances = Steam::filterAccountBalance(Steam::finalAccountBalance($account, $now), $account, $this->convertToNative, $accountCurrency);
|
||||||
|
|
||||||
return view(
|
return view(
|
||||||
'accounts.show',
|
'accounts.show',
|
||||||
@@ -181,6 +189,8 @@ class ShowController extends Controller
|
|||||||
$subTitle = (string) trans('firefly.all_journals_for_account', ['name' => $account->name]);
|
$subTitle = (string) trans('firefly.all_journals_for_account', ['name' => $account->name]);
|
||||||
$periods = new Collection();
|
$periods = new Collection();
|
||||||
|
|
||||||
|
$end->endOfDay();
|
||||||
|
|
||||||
/** @var GroupCollectorInterface $collector */
|
/** @var GroupCollectorInterface $collector */
|
||||||
$collector = app(GroupCollectorInterface::class);
|
$collector = app(GroupCollectorInterface::class);
|
||||||
$collector->setAccounts(new Collection([$account]))->setLimit($pageSize)->setPage($page)->withAccountInformation()->withCategoryInformation();
|
$collector->setAccounts(new Collection([$account]))->setLimit($pageSize)->setPage($page)->withAccountInformation()->withCategoryInformation();
|
||||||
@@ -193,6 +203,8 @@ class ShowController extends Controller
|
|||||||
$groups->setPath(route('accounts.show.all', [$account->id]));
|
$groups->setPath(route('accounts.show.all', [$account->id]));
|
||||||
$chartUrl = route('chart.account.period', [$account->id, $start->format('Y-m-d'), $end->format('Y-m-d')]);
|
$chartUrl = route('chart.account.period', [$account->id, $start->format('Y-m-d'), $end->format('Y-m-d')]);
|
||||||
$showAll = true;
|
$showAll = true;
|
||||||
|
// correct
|
||||||
|
Log::debug(sprintf('showAll: Call finalAccountBalance with date/time "%s"', $end->toIso8601String()));
|
||||||
$balances = Steam::filterAccountBalance(Steam::finalAccountBalance($account, $end), $account, $this->convertToNative, $accountCurrency);
|
$balances = Steam::filterAccountBalance(Steam::finalAccountBalance($account, $end), $account, $this->convertToNative, $accountCurrency);
|
||||||
|
|
||||||
return view(
|
return view(
|
||||||
|
@@ -109,8 +109,10 @@ class AccountController extends Controller
|
|||||||
$accountNames = $this->extractNames($accounts);
|
$accountNames = $this->extractNames($accounts);
|
||||||
|
|
||||||
// grab all balances
|
// grab all balances
|
||||||
$startBalances = app('steam')->finalAccountsBalance($accounts, $start);
|
Log::debug(sprintf('expenseAccounts: finalAccountsBalance("%s")', $start->format('Y-m-d H:i:s')));
|
||||||
$endBalances = app('steam')->finalAccountsBalance($accounts, $end);
|
Log::debug(sprintf('expenseAccounts: finalAccountsBalance("%s")', $end->format('Y-m-d H:i:s')));
|
||||||
|
$startBalances = Steam::finalAccountsBalance($accounts, $start);
|
||||||
|
$endBalances = Steam::finalAccountsBalance($accounts, $end);
|
||||||
|
|
||||||
// loop the accounts, then check for balance and currency info.
|
// loop the accounts, then check for balance and currency info.
|
||||||
foreach ($accounts as $account) {
|
foreach ($accounts as $account) {
|
||||||
@@ -139,6 +141,7 @@ class AccountController extends Controller
|
|||||||
}
|
}
|
||||||
// Log::debug(sprintf('Will process expense array "%s" with amount %s', $key, $endBalance));
|
// Log::debug(sprintf('Will process expense array "%s" with amount %s', $key, $endBalance));
|
||||||
$searchCode = $this->convertToNative ? $this->defaultCurrency->code : $key;
|
$searchCode = $this->convertToNative ? $this->defaultCurrency->code : $key;
|
||||||
|
$searchCode = 'balance' === $searchCode || 'native_balance' === $searchCode ? $this->defaultCurrency->code : $searchCode;
|
||||||
// Log::debug(sprintf('Search code is %s', $searchCode));
|
// Log::debug(sprintf('Search code is %s', $searchCode));
|
||||||
// see if there is an accompanying start amount.
|
// see if there is an accompanying start amount.
|
||||||
// grab the difference and find the currency.
|
// grab the difference and find the currency.
|
||||||
@@ -334,7 +337,7 @@ class AccountController extends Controller
|
|||||||
$start = clone session('start', today(config('app.timezone'))->startOfMonth());
|
$start = clone session('start', today(config('app.timezone'))->startOfMonth());
|
||||||
$end = clone session('end', today(config('app.timezone'))->endOfMonth());
|
$end = clone session('end', today(config('app.timezone'))->endOfMonth());
|
||||||
$defaultSet = $repository->getAccountsByType([AccountTypeEnum::DEFAULT->value, AccountTypeEnum::ASSET->value])->pluck('id')->toArray();
|
$defaultSet = $repository->getAccountsByType([AccountTypeEnum::DEFAULT->value, AccountTypeEnum::ASSET->value])->pluck('id')->toArray();
|
||||||
Log::debug('Default set is ', $defaultSet);
|
// Log::debug('Default set is ', $defaultSet);
|
||||||
$frontpage = app('preferences')->get('frontpageAccounts', $defaultSet);
|
$frontpage = app('preferences')->get('frontpageAccounts', $defaultSet);
|
||||||
$frontpageArray = !is_array($frontpage->data) ? [] : $frontpage->data;
|
$frontpageArray = !is_array($frontpage->data) ? [] : $frontpage->data;
|
||||||
Log::debug('Frontpage preference set is ', $frontpageArray);
|
Log::debug('Frontpage preference set is ', $frontpageArray);
|
||||||
@@ -344,6 +347,9 @@ class AccountController extends Controller
|
|||||||
}
|
}
|
||||||
$accounts = $repository->getAccountsById($frontpageArray);
|
$accounts = $repository->getAccountsById($frontpageArray);
|
||||||
|
|
||||||
|
// move to end of day for $end.
|
||||||
|
$end->endOfDay();
|
||||||
|
|
||||||
return response()->json($this->accountBalanceChart($accounts, $start, $end));
|
return response()->json($this->accountBalanceChart($accounts, $start, $end));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -416,8 +422,10 @@ class AccountController extends Controller
|
|||||||
*/
|
*/
|
||||||
public function period(Account $account, Carbon $start, Carbon $end): JsonResponse
|
public function period(Account $account, Carbon $start, Carbon $end): JsonResponse
|
||||||
{
|
{
|
||||||
Log::debug(sprintf('Now in period("%s", "%s")', $start->format('Y-m-d'), $end->format('Y-m-d')));
|
$start->startOfDay();
|
||||||
$chartData = [];
|
$end->endOfDay();
|
||||||
|
// TODO not sure if these date ranges will work as expected.
|
||||||
|
Log::debug(sprintf('Now in period("%s", "%s")', $start->format('Y-m-d H:i:s'), $end->format('Y-m-d H:i:s')));
|
||||||
$cache = new CacheProperties();
|
$cache = new CacheProperties();
|
||||||
$cache->addProperty('chart.account.period');
|
$cache->addProperty('chart.account.period');
|
||||||
$cache->addProperty($start);
|
$cache->addProperty($start);
|
||||||
@@ -431,7 +439,7 @@ class AccountController extends Controller
|
|||||||
// collect and filter balances for the entire period.
|
// collect and filter balances for the entire period.
|
||||||
$step = $this->calculateStep($start, $end);
|
$step = $this->calculateStep($start, $end);
|
||||||
Log::debug(sprintf('Step is %s', $step));
|
Log::debug(sprintf('Step is %s', $step));
|
||||||
$locale = app('steam')->getLocale();
|
$locale = Steam::getLocale();
|
||||||
$return = [];
|
$return = [];
|
||||||
|
|
||||||
// fix for issue https://github.com/firefly-iii/firefly-iii/issues/8041
|
// fix for issue https://github.com/firefly-iii/firefly-iii/issues/8041
|
||||||
@@ -442,14 +450,11 @@ class AccountController extends Controller
|
|||||||
$format = (string) trans('config.month_and_day_js', [], $locale);
|
$format = (string) trans('config.month_and_day_js', [], $locale);
|
||||||
$accountCurrency = $this->accountRepository->getAccountCurrency($account);
|
$accountCurrency = $this->accountRepository->getAccountCurrency($account);
|
||||||
|
|
||||||
Log::debug('One');
|
|
||||||
$range = Steam::finalAccountBalanceInRange($account, $start, $end, $this->convertToNative);
|
$range = Steam::finalAccountBalanceInRange($account, $start, $end, $this->convertToNative);
|
||||||
Log::debug('Two');
|
|
||||||
$range = Steam::filterAccountBalances($range, $account, $this->convertToNative, $accountCurrency);
|
$range = Steam::filterAccountBalances($range, $account, $this->convertToNative, $accountCurrency);
|
||||||
Log::debug('Three');
|
|
||||||
|
|
||||||
// temp, get end balance.
|
// temp, get end balance.
|
||||||
Log::debug('temp get end balance');
|
Log::debug(sprintf('period: Call finalAccountBalance with date/time "%s"', $end->toIso8601String()));
|
||||||
Steam::finalAccountBalance($account, $end);
|
Steam::finalAccountBalance($account, $end);
|
||||||
Log::debug('END temp get end balance done');
|
Log::debug('END temp get end balance done');
|
||||||
|
|
||||||
@@ -462,25 +467,32 @@ class AccountController extends Controller
|
|||||||
Log::debug('Balances exist at:');
|
Log::debug('Balances exist at:');
|
||||||
foreach ($range as $key => $value) {
|
foreach ($range as $key => $value) {
|
||||||
$newRange[] = ['date' => $key, 'info' => $value];
|
$newRange[] = ['date' => $key, 'info' => $value];
|
||||||
Log::debug(sprintf(' - %s', $key));
|
Log::debug(sprintf('%d - %s (%s)', count($newRange) - 1, $key, json_encode($value)));
|
||||||
}
|
}
|
||||||
$carbon = Carbon::createFromFormat('Y-m-d', $newRange[0]['date']);
|
$carbon = Carbon::createFromFormat('Y-m-d', $newRange[0]['date'])->endOfDay();
|
||||||
|
Log::debug(sprintf('Start of loop, $carbon is %s', $carbon->format('Y-m-d H:i:s')));
|
||||||
while ($end->gte($current)) {
|
while ($end->gte($current)) {
|
||||||
$momentBalance = $previous;
|
$momentBalance = $previous;
|
||||||
$theDate = $current->format('Y-m-d');
|
// $theDate = $current->format('Y-m-d');
|
||||||
while ($carbon->lte($current) && array_key_exists($expectedIndex, $newRange)) {
|
Log::debug(sprintf('Now at %s, with momentBalance %s', $current->format('Y-m-d H:i:s'), json_encode($momentBalance)));
|
||||||
$momentBalance = $newRange[$expectedIndex]['info'];
|
|
||||||
Log::debug(sprintf('Expected index is %d!, date is %s, current is %s', $expectedIndex, $carbon->format('Y-m-d'), $current->format('Y-m-d')));
|
|
||||||
$carbon = Carbon::createFromFormat('Y-m-d', $newRange[$expectedIndex]['date']);
|
|
||||||
++$expectedIndex;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
// loop over the array with balances, find one that is earlier or on the same day.
|
||||||
|
while ($carbon->lte($current) && array_key_exists($expectedIndex, $newRange)) {
|
||||||
|
Log::debug(sprintf('[a] Expected index is %d, $carbon is %s, current is %s', $expectedIndex, $carbon->format('Y-m-d H:i:s'), $current->format('Y-m-d H:i:s')));
|
||||||
|
|
||||||
|
// grab the balance from that particular $expectedIndex
|
||||||
|
$momentBalance = $newRange[$expectedIndex]['info'];
|
||||||
|
++$expectedIndex;
|
||||||
|
|
||||||
|
// make new carbon based on the next found date. this should stop the loop.
|
||||||
|
if (array_key_exists($expectedIndex, $newRange)) {
|
||||||
|
$carbon = Carbon::createFromFormat('Y-m-d', $newRange[$expectedIndex]['date'])->endOfDay();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Log::debug(sprintf('momentBalance is now %s', json_encode($momentBalance)));
|
||||||
$return = $this->updateChartKeys($return, $momentBalance);
|
$return = $this->updateChartKeys($return, $momentBalance);
|
||||||
$previous = $momentBalance;
|
$previous = $momentBalance;
|
||||||
|
|
||||||
Log::debug(sprintf('Now at %s', $theDate), $momentBalance);
|
|
||||||
|
|
||||||
|
|
||||||
// process each balance thing.
|
// process each balance thing.
|
||||||
foreach ($momentBalance as $key => $amount) {
|
foreach ($momentBalance as $key => $amount) {
|
||||||
$label = $current->isoFormat($format);
|
$label = $current->isoFormat($format);
|
||||||
@@ -489,15 +501,13 @@ class AccountController extends Controller
|
|||||||
$current = app('navigation')->addPeriod($current, $step, 0);
|
$current = app('navigation')->addPeriod($current, $step, 0);
|
||||||
// here too, to fix #8041, the data is corrected to the end of the period.
|
// here too, to fix #8041, the data is corrected to the end of the period.
|
||||||
$current = app('navigation')->endOfX($current, $step, null);
|
$current = app('navigation')->endOfX($current, $step, null);
|
||||||
Log::debug(sprintf('Next moment is %s', $current->format('Y-m-d')));
|
|
||||||
|
|
||||||
}
|
}
|
||||||
Log::debug('End of chart loop.');
|
Log::debug('End of chart loop.');
|
||||||
// second loop (yes) to create nice array with info! Yay!
|
// second loop (yes) to create nice array with info! Yay!
|
||||||
$chartData = [];
|
$chartData = [];
|
||||||
|
|
||||||
foreach ($return as $key => $info) {
|
foreach ($return as $key => $info) {
|
||||||
if (3 === strlen($key)) {
|
if ('balance' !== $key && 'native_balance' !== $key) {
|
||||||
// assume it's a currency:
|
// assume it's a currency:
|
||||||
$setCurrency = $this->currencyRepository->findByCode($key);
|
$setCurrency = $this->currencyRepository->findByCode($key);
|
||||||
$info['currency_symbol'] = $setCurrency->symbol;
|
$info['currency_symbol'] = $setCurrency->symbol;
|
||||||
@@ -567,8 +577,10 @@ class AccountController extends Controller
|
|||||||
$accountNames = $this->extractNames($accounts);
|
$accountNames = $this->extractNames($accounts);
|
||||||
|
|
||||||
// grab all balances
|
// grab all balances
|
||||||
$startBalances = app('steam')->finalAccountsBalance($accounts, $start);
|
Log::debug(sprintf('revAccounts: finalAccountsBalance("%s")', $start->format('Y-m-d H:i:s')));
|
||||||
$endBalances = app('steam')->finalAccountsBalance($accounts, $end);
|
Log::debug(sprintf('revAccounts: finalAccountsBalance("%s")', $end->format('Y-m-d H:i:s')));
|
||||||
|
$startBalances = Steam::finalAccountsBalance($accounts, $start);
|
||||||
|
$endBalances = Steam::finalAccountsBalance($accounts, $end);
|
||||||
|
|
||||||
|
|
||||||
// loop the accounts, then check for balance and currency info.
|
// loop the accounts, then check for balance and currency info.
|
||||||
@@ -598,6 +610,7 @@ class AccountController extends Controller
|
|||||||
}
|
}
|
||||||
// Log::debug(sprintf('Will process expense array "%s" with amount %s', $key, $endBalance));
|
// Log::debug(sprintf('Will process expense array "%s" with amount %s', $key, $endBalance));
|
||||||
$searchCode = $this->convertToNative ? $this->defaultCurrency->code : $key;
|
$searchCode = $this->convertToNative ? $this->defaultCurrency->code : $key;
|
||||||
|
$searchCode = 'balance' === $searchCode || 'native_balance' === $searchCode ? $this->defaultCurrency->code : $searchCode;
|
||||||
// Log::debug(sprintf('Search code is %s', $searchCode));
|
// Log::debug(sprintf('Search code is %s', $searchCode));
|
||||||
// see if there is an accompanying start amount.
|
// see if there is an accompanying start amount.
|
||||||
// grab the difference and find the currency.
|
// grab the difference and find the currency.
|
||||||
|
@@ -168,15 +168,14 @@ class BudgetController extends Controller
|
|||||||
}
|
}
|
||||||
$locale = app('steam')->getLocale();
|
$locale = app('steam')->getLocale();
|
||||||
$entries = [];
|
$entries = [];
|
||||||
$amount = $budgetLimit->amount;
|
$amount = $budgetLimit->amount ?? '0';
|
||||||
$budgetCollection = new Collection([$budget]);
|
$budgetCollection = new Collection([$budget]);
|
||||||
$currency = $budgetLimit->transactionCurrency;
|
$currency = $budgetLimit->transactionCurrency;
|
||||||
if ($this->convertToNative) {
|
if ($this->convertToNative) {
|
||||||
$amount = $budgetLimit->native_amount;
|
$amount = $budgetLimit->native_amount ?? '0';
|
||||||
$currency = $this->defaultCurrency;
|
$currency = $this->defaultCurrency;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
while ($start <= $end) {
|
while ($start <= $end) {
|
||||||
$current = clone $start;
|
$current = clone $start;
|
||||||
$expenses = $this->opsRepository->sumExpenses($current, $current, null, $budgetCollection, $budgetLimit->transactionCurrency);
|
$expenses = $this->opsRepository->sumExpenses($current, $current, null, $budgetCollection, $budgetLimit->transactionCurrency);
|
||||||
|
@@ -100,7 +100,10 @@ class ReportController extends Controller
|
|||||||
|
|
||||||
while ($current < $end) {
|
while ($current < $end) {
|
||||||
// get balances by date, grouped by currency.
|
// get balances by date, grouped by currency.
|
||||||
$result = $helper->byAccounts($filtered, $current);
|
$balanceCurrent = clone $current;
|
||||||
|
$balanceCurrent->subDay()->endOfDay(); // go to correct moment.
|
||||||
|
Log::debug(sprintf('Call byAccounts("%s")', $balanceCurrent->format('Y-m-d H:i:s')));
|
||||||
|
$result = $helper->byAccounts($filtered, $balanceCurrent);
|
||||||
|
|
||||||
// loop result, add to array.
|
// loop result, add to array.
|
||||||
/** @var array $netWorthItem */
|
/** @var array $netWorthItem */
|
||||||
|
@@ -259,7 +259,7 @@ class DebugController extends Controller
|
|||||||
$system = $this->getSystemInformation();
|
$system = $this->getSystemInformation();
|
||||||
$docker = $this->getBuildInfo();
|
$docker = $this->getBuildInfo();
|
||||||
$app = $this->getAppInfo();
|
$app = $this->getAppInfo();
|
||||||
$user = $this->getuserInfo();
|
$user = $this->getUserInfo();
|
||||||
|
|
||||||
return (string) view('partials.debug-table', compact('system', 'docker', 'app', 'user'));
|
return (string) view('partials.debug-table', compact('system', 'docker', 'app', 'user'));
|
||||||
}
|
}
|
||||||
@@ -381,6 +381,7 @@ class DebugController extends Controller
|
|||||||
'user_count' => User::count(),
|
'user_count' => User::count(),
|
||||||
'user_flags' => $userFlags,
|
'user_flags' => $userFlags,
|
||||||
'user_agent' => $userAgent,
|
'user_agent' => $userAgent,
|
||||||
|
'native' => Amount::getNativeCurrency(),
|
||||||
'convert_to_native' => Amount::convertToNative(),
|
'convert_to_native' => Amount::convertToNative(),
|
||||||
'locale_attempts' => $localeAttempts,
|
'locale_attempts' => $localeAttempts,
|
||||||
'locale' => Steam::getLocale(),
|
'locale' => Steam::getLocale(),
|
||||||
|
@@ -27,6 +27,7 @@ use FireflyIII\Exceptions\FireflyException;
|
|||||||
use FireflyIII\Http\Controllers\Controller;
|
use FireflyIII\Http\Controllers\Controller;
|
||||||
use FireflyIII\Models\PiggyBank;
|
use FireflyIII\Models\PiggyBank;
|
||||||
use FireflyIII\Repositories\PiggyBank\PiggyBankRepositoryInterface;
|
use FireflyIII\Repositories\PiggyBank\PiggyBankRepositoryInterface;
|
||||||
|
use FireflyIII\Support\Facades\Amount;
|
||||||
use Illuminate\Http\JsonResponse;
|
use Illuminate\Http\JsonResponse;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -41,12 +42,16 @@ class FrontpageController extends Controller
|
|||||||
*/
|
*/
|
||||||
public function piggyBanks(PiggyBankRepositoryInterface $repository): JsonResponse
|
public function piggyBanks(PiggyBankRepositoryInterface $repository): JsonResponse
|
||||||
{
|
{
|
||||||
$set = $repository->getPiggyBanks();
|
$set = $repository->getPiggyBanks();
|
||||||
$info = [];
|
$info = [];
|
||||||
|
$native = Amount::getNativeCurrency();
|
||||||
|
$convertToNative = Amount::convertToNative();
|
||||||
|
|
||||||
|
|
||||||
/** @var PiggyBank $piggyBank */
|
/** @var PiggyBank $piggyBank */
|
||||||
foreach ($set as $piggyBank) {
|
foreach ($set as $piggyBank) {
|
||||||
$amount = $repository->getCurrentAmount($piggyBank);
|
$amount = $repository->getCurrentAmount($piggyBank);
|
||||||
|
$nativeAmount = $repository->getCurrentNativeAmount($piggyBank);
|
||||||
if (1 === bccomp($amount, '0')) {
|
if (1 === bccomp($amount, '0')) {
|
||||||
// percentage!
|
// percentage!
|
||||||
$pct = 0;
|
$pct = 0;
|
||||||
@@ -55,11 +60,19 @@ class FrontpageController extends Controller
|
|||||||
}
|
}
|
||||||
|
|
||||||
$entry = [
|
$entry = [
|
||||||
'id' => $piggyBank->id,
|
'id' => $piggyBank->id,
|
||||||
'name' => $piggyBank->name,
|
'name' => $piggyBank->name,
|
||||||
'amount' => $amount,
|
'amount' => $amount,
|
||||||
'target' => $piggyBank->target_amount,
|
'native_amount' => $nativeAmount,
|
||||||
'percentage' => $pct,
|
'target' => $piggyBank->target_amount,
|
||||||
|
'native_target' => $piggyBank->native_target_amount,
|
||||||
|
'percentage' => $pct,
|
||||||
|
// currency:
|
||||||
|
'currency_symbol' => $piggyBank->transactionCurrency->symbol,
|
||||||
|
'currency_decimal_places' => $piggyBank->transactionCurrency->decimal_places,
|
||||||
|
'native_currency_symbol' => $native->symbol,
|
||||||
|
'native_currency_decimal_places' => $native->decimal_places,
|
||||||
|
|
||||||
];
|
];
|
||||||
|
|
||||||
$info[] = $entry;
|
$info[] = $entry;
|
||||||
@@ -74,11 +87,10 @@ class FrontpageController extends Controller
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
$html = '';
|
||||||
$html = '';
|
|
||||||
if (0 !== count($info)) {
|
if (0 !== count($info)) {
|
||||||
try {
|
try {
|
||||||
$html = view('json.piggy-banks', compact('info'))->render();
|
$html = view('json.piggy-banks', compact('info', 'convertToNative', 'native'))->render();
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
app('log')->error(sprintf('Cannot render json.piggy-banks: %s', $e->getMessage()));
|
app('log')->error(sprintf('Cannot render json.piggy-banks: %s', $e->getMessage()));
|
||||||
app('log')->error($e->getTraceAsString());
|
app('log')->error($e->getTraceAsString());
|
||||||
|
@@ -189,20 +189,29 @@ class ReconcileController extends Controller
|
|||||||
if ($end->lt($start)) {
|
if ($end->lt($start)) {
|
||||||
[$end, $start] = [$start, $end];
|
[$end, $start] = [$start, $end];
|
||||||
}
|
}
|
||||||
|
$start->endOfDay();
|
||||||
|
$end->endOfDay();
|
||||||
$startDate = clone $start;
|
$startDate = clone $start;
|
||||||
$startDate->subDay();
|
$startDate->subDay();
|
||||||
$end->endOfDay();
|
|
||||||
|
|
||||||
$currency = $this->accountRepos->getAccountCurrency($account) ?? $this->defaultCurrency;
|
$currency = $this->accountRepos->getAccountCurrency($account) ?? $this->defaultCurrency;
|
||||||
$startBalance = Steam::finalAccountBalance($account, $startDate)['balance'];
|
// correct
|
||||||
$endBalance = Steam::finalAccountBalance($account, $end)['balance'];
|
Log::debug(sprintf('transactions: Call finalAccountBalance with date/time "%s"', $startDate->toIso8601String()));
|
||||||
|
Log::debug(sprintf('transactions2: Call finalAccountBalance with date/time "%s"', $end->toIso8601String()));
|
||||||
|
$startBalance = Steam::bcround(Steam::finalAccountBalance($account, $startDate)['balance'], $currency->decimal_places);
|
||||||
|
$endBalance = Steam::bcround(Steam::finalAccountBalance($account, $end)['balance'], $currency->decimal_places);
|
||||||
|
|
||||||
// get the transactions
|
// get the transactions
|
||||||
$selectionStart = clone $start;
|
$selectionStart = clone $start;
|
||||||
|
$selectionStart->startOfDay();
|
||||||
$selectionStart->subDays(3);
|
$selectionStart->subDays(3);
|
||||||
$selectionEnd = clone $end;
|
$selectionEnd = clone $end;
|
||||||
|
$selectionEnd->endOfDay();
|
||||||
$selectionEnd->addDays(3);
|
$selectionEnd->addDays(3);
|
||||||
|
|
||||||
|
// to make sure the bar is in the right place:
|
||||||
|
$start->startOfDay();
|
||||||
|
|
||||||
// grab transactions:
|
// grab transactions:
|
||||||
/** @var GroupCollectorInterface $collector */
|
/** @var GroupCollectorInterface $collector */
|
||||||
$collector = app(GroupCollectorInterface::class);
|
$collector = app(GroupCollectorInterface::class);
|
||||||
|
@@ -68,14 +68,16 @@ class AmountController extends Controller
|
|||||||
*/
|
*/
|
||||||
public function add(PiggyBank $piggyBank)
|
public function add(PiggyBank $piggyBank)
|
||||||
{
|
{
|
||||||
|
/** @var Carbon $date */
|
||||||
|
$date = session('end', today(config('app.timezone')));
|
||||||
$accounts = [];
|
$accounts = [];
|
||||||
$total = '0';
|
$total = '0';
|
||||||
$totalSaved = $this->piggyRepos->getCurrentAmount($piggyBank);
|
$totalSaved = $this->piggyRepos->getCurrentAmount($piggyBank);
|
||||||
$leftToSave = bcsub($piggyBank->target_amount, $totalSaved);
|
|
||||||
foreach ($piggyBank->accounts as $account) {
|
foreach ($piggyBank->accounts as $account) {
|
||||||
$leftOnAccount = $this->piggyRepos->leftOnAccount($piggyBank, $account, today(config('app.timezone'))->endOfDay());
|
$leftOnAccount = $this->piggyRepos->leftOnAccount($piggyBank, $account, $date);
|
||||||
$savedSoFar = $this->piggyRepos->getCurrentAmount($piggyBank, $account);
|
$savedSoFar = $this->piggyRepos->getCurrentAmount($piggyBank, $account);
|
||||||
$maxAmount = 0 === bccomp($piggyBank->target_amount, '0') ? $leftToSave : min($leftOnAccount, $leftToSave);
|
$leftToSave = bcsub($piggyBank->target_amount, $savedSoFar);
|
||||||
|
$maxAmount = 0 === bccomp($piggyBank->target_amount, '0') ? $leftOnAccount : min($leftOnAccount, $leftToSave);
|
||||||
$accounts[] = [
|
$accounts[] = [
|
||||||
'account' => $account,
|
'account' => $account,
|
||||||
'left_on_account' => $leftOnAccount,
|
'left_on_account' => $leftOnAccount,
|
||||||
@@ -105,12 +107,13 @@ class AmountController extends Controller
|
|||||||
$leftOnAccount = $this->piggyRepos->leftOnAccount($piggyBank, $account, $date);
|
$leftOnAccount = $this->piggyRepos->leftOnAccount($piggyBank, $account, $date);
|
||||||
$savedSoFar = $this->piggyRepos->getCurrentAmount($piggyBank, $account);
|
$savedSoFar = $this->piggyRepos->getCurrentAmount($piggyBank, $account);
|
||||||
$leftToSave = bcsub($piggyBank->target_amount, $savedSoFar);
|
$leftToSave = bcsub($piggyBank->target_amount, $savedSoFar);
|
||||||
|
$maxAmount = 0 === bccomp($piggyBank->target_amount, '0') ? $leftOnAccount : min($leftOnAccount, $leftToSave);
|
||||||
$accounts[] = [
|
$accounts[] = [
|
||||||
'account' => $account,
|
'account' => $account,
|
||||||
'left_on_account' => $leftOnAccount,
|
'left_on_account' => $leftOnAccount,
|
||||||
'saved_so_far' => $savedSoFar,
|
'saved_so_far' => $savedSoFar,
|
||||||
'left_to_save' => $leftToSave,
|
'left_to_save' => $leftToSave,
|
||||||
'max_amount' => 0 === bccomp($piggyBank->target_amount, '0') ? $leftOnAccount : min($leftOnAccount, $leftToSave),
|
'max_amount' => $maxAmount,
|
||||||
];
|
];
|
||||||
$total = bcadd($total, $leftOnAccount);
|
$total = bcadd($total, $leftOnAccount);
|
||||||
}
|
}
|
||||||
|
29
app/Http/Controllers/Preferences/NotificationsController.php
Normal file
29
app/Http/Controllers/Preferences/NotificationsController.php
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* NotificationsController.php
|
||||||
|
* Copyright (c) 2025 james@firefly-iii.org.
|
||||||
|
*
|
||||||
|
* This file is part of Firefly III (https://github.com/firefly-iii).
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as
|
||||||
|
* published by the Free Software Foundation, either version 3 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see https://www.gnu.org/licenses/.
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace FireflyIII\Http\Controllers\Preferences;
|
||||||
|
|
||||||
|
use FireflyIII\Http\Controllers\Controller;
|
||||||
|
|
||||||
|
class NotificationsController extends Controller {}
|
@@ -120,7 +120,7 @@ class PreferencesController extends Controller
|
|||||||
$pushoverUserToken = (string) Preferences::getEncrypted('pushover_user_token', '')->data;
|
$pushoverUserToken = (string) Preferences::getEncrypted('pushover_user_token', '')->data;
|
||||||
$ntfyServer = Preferences::getEncrypted('ntfy_server', 'https://ntfy.sh')->data;
|
$ntfyServer = Preferences::getEncrypted('ntfy_server', 'https://ntfy.sh')->data;
|
||||||
$ntfyTopic = (string) Preferences::getEncrypted('ntfy_topic', '')->data;
|
$ntfyTopic = (string) Preferences::getEncrypted('ntfy_topic', '')->data;
|
||||||
$ntfyAuth = Preferences::get('ntfy_auth', false)->data;
|
$ntfyAuth = '1' === Preferences::get('ntfy_auth', false)->data;
|
||||||
$ntfyUser = Preferences::getEncrypted('ntfy_user', '')->data;
|
$ntfyUser = Preferences::getEncrypted('ntfy_user', '')->data;
|
||||||
$ntfyPass = (string) Preferences::getEncrypted('ntfy_pass', '')->data;
|
$ntfyPass = (string) Preferences::getEncrypted('ntfy_pass', '')->data;
|
||||||
$channels = config('notifications.channels');
|
$channels = config('notifications.channels');
|
||||||
@@ -264,6 +264,7 @@ class PreferencesController extends Controller
|
|||||||
if ($convertToNative && !$this->convertToNative) {
|
if ($convertToNative && !$this->convertToNative) {
|
||||||
// set to true!
|
// set to true!
|
||||||
Log::debug('User sets convertToNative to true.');
|
Log::debug('User sets convertToNative to true.');
|
||||||
|
Preferences::set('convert_to_native', $convertToNative);
|
||||||
event(new UserGroupChangedDefaultCurrency(auth()->user()->userGroup));
|
event(new UserGroupChangedDefaultCurrency(auth()->user()->userGroup));
|
||||||
}
|
}
|
||||||
Preferences::set('convert_to_native', $convertToNative);
|
Preferences::set('convert_to_native', $convertToNative);
|
||||||
|
@@ -83,6 +83,8 @@ class ReportController extends Controller
|
|||||||
return view('error')->with('message', (string) trans('firefly.end_after_start_date'));
|
return view('error')->with('message', (string) trans('firefly.end_after_start_date'));
|
||||||
}
|
}
|
||||||
$this->repository->cleanupBudgets();
|
$this->repository->cleanupBudgets();
|
||||||
|
$start->endOfDay(); // end of day so the final balance is at the end of that day.
|
||||||
|
$end->endOfDay();
|
||||||
|
|
||||||
app('view')->share(
|
app('view')->share(
|
||||||
'subTitle',
|
'subTitle',
|
||||||
@@ -114,6 +116,8 @@ class ReportController extends Controller
|
|||||||
return view('error')->with('message', (string) trans('firefly.end_after_start_date'));
|
return view('error')->with('message', (string) trans('firefly.end_after_start_date'));
|
||||||
}
|
}
|
||||||
$this->repository->cleanupBudgets();
|
$this->repository->cleanupBudgets();
|
||||||
|
$start->endOfDay(); // end of day so the final balance is at the end of that day.
|
||||||
|
$end->endOfDay();
|
||||||
|
|
||||||
app('view')->share(
|
app('view')->share(
|
||||||
'subTitle',
|
'subTitle',
|
||||||
@@ -146,6 +150,8 @@ class ReportController extends Controller
|
|||||||
return view('error')->with('message', (string) trans('firefly.end_after_start_date'));
|
return view('error')->with('message', (string) trans('firefly.end_after_start_date'));
|
||||||
}
|
}
|
||||||
$this->repository->cleanupBudgets();
|
$this->repository->cleanupBudgets();
|
||||||
|
$start->endOfDay(); // end of day so the final balance is at the end of that day.
|
||||||
|
$end->endOfDay();
|
||||||
|
|
||||||
app('view')->share(
|
app('view')->share(
|
||||||
'subTitle',
|
'subTitle',
|
||||||
@@ -179,6 +185,8 @@ class ReportController extends Controller
|
|||||||
}
|
}
|
||||||
|
|
||||||
$this->repository->cleanupBudgets();
|
$this->repository->cleanupBudgets();
|
||||||
|
$start->endOfDay(); // end of day so the final balance is at the end of that day.
|
||||||
|
$end->endOfDay();
|
||||||
|
|
||||||
app('view')->share(
|
app('view')->share(
|
||||||
'subTitle',
|
'subTitle',
|
||||||
@@ -211,6 +219,8 @@ class ReportController extends Controller
|
|||||||
}
|
}
|
||||||
|
|
||||||
$this->repository->cleanupBudgets();
|
$this->repository->cleanupBudgets();
|
||||||
|
$start->endOfDay(); // end of day so the final balance is at the end of that day.
|
||||||
|
$end->endOfDay();
|
||||||
|
|
||||||
app('view')->share(
|
app('view')->share(
|
||||||
'subTitle',
|
'subTitle',
|
||||||
@@ -367,6 +377,8 @@ class ReportController extends Controller
|
|||||||
return view('error')->with('message', (string) trans('firefly.end_after_start_date'));
|
return view('error')->with('message', (string) trans('firefly.end_after_start_date'));
|
||||||
}
|
}
|
||||||
$this->repository->cleanupBudgets();
|
$this->repository->cleanupBudgets();
|
||||||
|
$start->endOfDay(); // end of day so the final balance is at the end of that day.
|
||||||
|
$end->endOfDay();
|
||||||
|
|
||||||
app('view')->share(
|
app('view')->share(
|
||||||
'subTitle',
|
'subTitle',
|
||||||
|
@@ -43,6 +43,7 @@ use Illuminate\Contracts\View\Factory;
|
|||||||
use Illuminate\Http\RedirectResponse;
|
use Illuminate\Http\RedirectResponse;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Illuminate\Routing\Redirector;
|
use Illuminate\Routing\Redirector;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
use Illuminate\View\View;
|
use Illuminate\View\View;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -223,7 +224,9 @@ class ConvertController extends Controller
|
|||||||
// group accounts:
|
// group accounts:
|
||||||
/** @var Account $account */
|
/** @var Account $account */
|
||||||
foreach ($accountList as $account) {
|
foreach ($accountList as $account) {
|
||||||
$balance = Steam::finalAccountBalance($account, today()->endOfDay())['balance'];
|
$date = today()->endOfDay();
|
||||||
|
Log::debug(sprintf('getLiabilities: Call finalAccountBalance with date/time "%s"', $date->toIso8601String()));
|
||||||
|
$balance = Steam::finalAccountBalance($account, $date)['balance'];
|
||||||
$currency = $this->accountRepository->getAccountCurrency($account) ?? $this->defaultCurrency;
|
$currency = $this->accountRepository->getAccountCurrency($account) ?? $this->defaultCurrency;
|
||||||
$role = 'l_'.$account->accountType->type;
|
$role = 'l_'.$account->accountType->type;
|
||||||
$key = (string) trans('firefly.opt_group_'.$role);
|
$key = (string) trans('firefly.opt_group_'.$role);
|
||||||
@@ -245,7 +248,9 @@ class ConvertController extends Controller
|
|||||||
// group accounts:
|
// group accounts:
|
||||||
/** @var Account $account */
|
/** @var Account $account */
|
||||||
foreach ($accountList as $account) {
|
foreach ($accountList as $account) {
|
||||||
$balance = Steam::finalAccountBalance($account, today()->endOfDay())['balance'];
|
$date = today()->endOfDay();
|
||||||
|
Log::debug(sprintf('getAssetAccounts: Call finalAccountBalance with date/time "%s"', $date->toIso8601String()));
|
||||||
|
$balance = Steam::finalAccountBalance($account, $date)['balance'];
|
||||||
$currency = $this->accountRepository->getAccountCurrency($account) ?? $this->defaultCurrency;
|
$currency = $this->accountRepository->getAccountCurrency($account) ?? $this->defaultCurrency;
|
||||||
$role = (string) $this->accountRepository->getMetaValue($account, 'account_role');
|
$role = (string) $this->accountRepository->getMetaValue($account, 'account_role');
|
||||||
if ('' === $role) {
|
if ('' === $role) {
|
||||||
|
@@ -419,9 +419,7 @@ class CreateRecurringTransactions implements ShouldQueue
|
|||||||
/** @var RecurrenceTransaction $transaction */
|
/** @var RecurrenceTransaction $transaction */
|
||||||
foreach ($transactions as $index => $transaction) {
|
foreach ($transactions as $index => $transaction) {
|
||||||
$single = [
|
$single = [
|
||||||
'type' => null === $transaction?->transactionType?->type ?
|
'type' => null === $transaction?->transactionType?->type ? strtolower($recurrence->transactionType->type) : strtolower($transaction->transactionType->type), // @phpstan-ignore-line
|
||||||
strtolower($recurrence->transactionType->type) :
|
|
||||||
strtolower($transaction->transactionType->type),
|
|
||||||
'date' => $date,
|
'date' => $date,
|
||||||
'user' => $recurrence->user_id,
|
'user' => $recurrence->user_id,
|
||||||
'currency_id' => $transaction->transaction_currency_id,
|
'currency_id' => $transaction->transaction_currency_id,
|
||||||
|
@@ -112,6 +112,11 @@ class TransactionJournal extends Model
|
|||||||
return $this->belongsTo(User::class);
|
return $this->belongsTo(User::class);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function userGroup(): BelongsTo
|
||||||
|
{
|
||||||
|
return $this->belongsTo(UserGroup::class);
|
||||||
|
}
|
||||||
|
|
||||||
public function attachments(): MorphMany
|
public function attachments(): MorphMany
|
||||||
{
|
{
|
||||||
return $this->morphMany(Attachment::class, 'attachable');
|
return $this->morphMany(Attachment::class, 'attachable');
|
||||||
|
@@ -28,6 +28,7 @@ use FireflyIII\Exceptions\FireflyException;
|
|||||||
use FireflyIII\Support\Facades\FireflyConfig;
|
use FireflyIII\Support\Facades\FireflyConfig;
|
||||||
use FireflyIII\Support\Facades\Preferences;
|
use FireflyIII\Support\Facades\Preferences;
|
||||||
use FireflyIII\User;
|
use FireflyIII\User;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
|
|
||||||
class ReturnsSettings
|
class ReturnsSettings
|
||||||
{
|
{
|
||||||
@@ -42,6 +43,7 @@ class ReturnsSettings
|
|||||||
|
|
||||||
private static function getNtfySettings(string $type, ?User $user): array
|
private static function getNtfySettings(string $type, ?User $user): array
|
||||||
{
|
{
|
||||||
|
Log::debug(sprintf('Getting Ntfy settings for %s and user #%d', $type, $user?->id));
|
||||||
$settings = [
|
$settings = [
|
||||||
'ntfy_server' => 'https://ntfy.sh',
|
'ntfy_server' => 'https://ntfy.sh',
|
||||||
'ntfy_topic' => '',
|
'ntfy_topic' => '',
|
||||||
@@ -56,6 +58,7 @@ class ReturnsSettings
|
|||||||
$settings['ntfy_auth'] = Preferences::getForUser($user, 'ntfy_auth', false)->data;
|
$settings['ntfy_auth'] = Preferences::getForUser($user, 'ntfy_auth', false)->data;
|
||||||
$settings['ntfy_user'] = Preferences::getEncryptedForUser($user, 'ntfy_user', '')->data;
|
$settings['ntfy_user'] = Preferences::getEncryptedForUser($user, 'ntfy_user', '')->data;
|
||||||
$settings['ntfy_pass'] = Preferences::getEncryptedForUser($user, 'ntfy_pass', '')->data;
|
$settings['ntfy_pass'] = Preferences::getEncryptedForUser($user, 'ntfy_pass', '')->data;
|
||||||
|
Log::debug(sprintf('Auth is %s, user = "%s"', var_export($settings['ntfy_auth'], true), $settings['ntfy_user']));
|
||||||
}
|
}
|
||||||
if ('owner' === $type) {
|
if ('owner' === $type) {
|
||||||
$settings['ntfy_server'] = FireflyConfig::getEncrypted('ntfy_server', 'https://ntfy.sh')->data;
|
$settings['ntfy_server'] = FireflyConfig::getEncrypted('ntfy_server', 'https://ntfy.sh')->data;
|
||||||
@@ -63,6 +66,7 @@ class ReturnsSettings
|
|||||||
$settings['ntfy_auth'] = FireflyConfig::get('ntfy_auth', false)->data;
|
$settings['ntfy_auth'] = FireflyConfig::get('ntfy_auth', false)->data;
|
||||||
$settings['ntfy_user'] = FireflyConfig::getEncrypted('ntfy_user', '')->data;
|
$settings['ntfy_user'] = FireflyConfig::getEncrypted('ntfy_user', '')->data;
|
||||||
$settings['ntfy_pass'] = FireflyConfig::getEncrypted('ntfy_pass', '')->data;
|
$settings['ntfy_pass'] = FireflyConfig::getEncrypted('ntfy_pass', '')->data;
|
||||||
|
Log::debug(sprintf('Auth is %s, user = "%s"', var_export($settings['ntfy_auth'], true), $settings['ntfy_user']));
|
||||||
}
|
}
|
||||||
|
|
||||||
// overrule config.
|
// overrule config.
|
||||||
@@ -74,7 +78,9 @@ class ReturnsSettings
|
|||||||
config(['ntfy-notification-channel.authentication.enabled' => true]);
|
config(['ntfy-notification-channel.authentication.enabled' => true]);
|
||||||
config(['ntfy-notification-channel.authentication.username' => $settings['ntfy_user']]);
|
config(['ntfy-notification-channel.authentication.username' => $settings['ntfy_user']]);
|
||||||
config(['ntfy-notification-channel.authentication.password' => $settings['ntfy_pass']]);
|
config(['ntfy-notification-channel.authentication.password' => $settings['ntfy_pass']]);
|
||||||
|
Log::debug('Authentication enabled for Ntfy.');
|
||||||
}
|
}
|
||||||
|
Log::debug('Return ntfy settings.');
|
||||||
|
|
||||||
return $settings;
|
return $settings;
|
||||||
}
|
}
|
||||||
|
@@ -23,9 +23,6 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace FireflyIII\Providers;
|
namespace FireflyIII\Providers;
|
||||||
|
|
||||||
use Barryvdh\Debugbar\DataCollector\QueryCollector;
|
|
||||||
use Barryvdh\Debugbar\Facades\Debugbar;
|
|
||||||
use DebugBar\DebugBarException;
|
|
||||||
use Illuminate\Support\Facades\Blade;
|
use Illuminate\Support\Facades\Blade;
|
||||||
use Illuminate\Support\Facades\Response;
|
use Illuminate\Support\Facades\Response;
|
||||||
use Illuminate\Support\Facades\Route;
|
use Illuminate\Support\Facades\Route;
|
||||||
@@ -53,17 +50,6 @@ class AppServiceProvider extends ServiceProvider
|
|||||||
$headers['X-Trace-Id'] = $uuid;
|
$headers['X-Trace-Id'] = $uuid;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (config('app.debug')) {
|
|
||||||
try {
|
|
||||||
/** @var QueryCollector $collector */
|
|
||||||
$collector = Debugbar::getCollector('queries');
|
|
||||||
$info = $collector->collect();
|
|
||||||
$headers['X-Debug-QueryCount'] = $info['nb_statements'] ?? 0;
|
|
||||||
} catch (DebugBarException $e) {
|
|
||||||
// ignore error.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return response()
|
return response()
|
||||||
->json($value)
|
->json($value)
|
||||||
->withHeaders($headers)
|
->withHeaders($headers)
|
||||||
|
@@ -169,16 +169,11 @@ class EventServiceProvider extends ServiceProvider
|
|||||||
|
|
||||||
// is a Transaction Journal related event.
|
// is a Transaction Journal related event.
|
||||||
StoredTransactionGroup::class => [
|
StoredTransactionGroup::class => [
|
||||||
'FireflyIII\Handlers\Events\StoredGroupEventHandler@processRules',
|
'FireflyIII\Handlers\Events\StoredGroupEventHandler@runAllHandlers',
|
||||||
'FireflyIII\Handlers\Events\StoredGroupEventHandler@recalculateCredit',
|
|
||||||
'FireflyIII\Handlers\Events\StoredGroupEventHandler@triggerWebhooks',
|
|
||||||
],
|
],
|
||||||
// is a Transaction Journal related event.
|
// is a Transaction Journal related event.
|
||||||
UpdatedTransactionGroup::class => [
|
UpdatedTransactionGroup::class => [
|
||||||
'FireflyIII\Handlers\Events\UpdatedGroupEventHandler@unifyAccounts',
|
'FireflyIII\Handlers\Events\UpdatedGroupEventHandler@runAllHandlers',
|
||||||
'FireflyIII\Handlers\Events\UpdatedGroupEventHandler@processRules',
|
|
||||||
'FireflyIII\Handlers\Events\UpdatedGroupEventHandler@recalculateCredit',
|
|
||||||
'FireflyIII\Handlers\Events\UpdatedGroupEventHandler@triggerWebhooks',
|
|
||||||
],
|
],
|
||||||
DestroyedTransactionGroup::class => [
|
DestroyedTransactionGroup::class => [
|
||||||
'FireflyIII\Handlers\Events\DestroyedGroupEventHandler@triggerWebhooks',
|
'FireflyIII\Handlers\Events\DestroyedGroupEventHandler@triggerWebhooks',
|
||||||
|
@@ -40,6 +40,7 @@ use FireflyIII\Models\TransactionJournal;
|
|||||||
use FireflyIII\Services\Internal\Destroy\AccountDestroyService;
|
use FireflyIII\Services\Internal\Destroy\AccountDestroyService;
|
||||||
use FireflyIII\Services\Internal\Update\AccountUpdateService;
|
use FireflyIII\Services\Internal\Update\AccountUpdateService;
|
||||||
use FireflyIII\Support\Facades\Steam;
|
use FireflyIII\Support\Facades\Steam;
|
||||||
|
use FireflyIII\Support\Repositories\UserGroup\UserGroupTrait;
|
||||||
use FireflyIII\User;
|
use FireflyIII\User;
|
||||||
use Illuminate\Contracts\Auth\Authenticatable;
|
use Illuminate\Contracts\Auth\Authenticatable;
|
||||||
use Illuminate\Database\Eloquent\Builder as EloquentBuilder;
|
use Illuminate\Database\Eloquent\Builder as EloquentBuilder;
|
||||||
@@ -51,7 +52,7 @@ use Illuminate\Support\Collection;
|
|||||||
*/
|
*/
|
||||||
class AccountRepository implements AccountRepositoryInterface
|
class AccountRepository implements AccountRepositoryInterface
|
||||||
{
|
{
|
||||||
private User $user;
|
use UserGroupTrait;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Moved here from account CRUD.
|
* Moved here from account CRUD.
|
||||||
|
@@ -30,6 +30,7 @@ use FireflyIII\Models\Location;
|
|||||||
use FireflyIII\Models\TransactionCurrency;
|
use FireflyIII\Models\TransactionCurrency;
|
||||||
use FireflyIII\Models\TransactionGroup;
|
use FireflyIII\Models\TransactionGroup;
|
||||||
use FireflyIII\Models\TransactionJournal;
|
use FireflyIII\Models\TransactionJournal;
|
||||||
|
use FireflyIII\Models\UserGroup;
|
||||||
use FireflyIII\User;
|
use FireflyIII\User;
|
||||||
use Illuminate\Contracts\Auth\Authenticatable;
|
use Illuminate\Contracts\Auth\Authenticatable;
|
||||||
use Illuminate\Support\Collection;
|
use Illuminate\Support\Collection;
|
||||||
@@ -149,6 +150,8 @@ interface AccountRepositoryInterface
|
|||||||
|
|
||||||
public function setUser(null|Authenticatable|User $user): void;
|
public function setUser(null|Authenticatable|User $user): void;
|
||||||
|
|
||||||
|
public function setUserGroup(UserGroup $userGroup): void;
|
||||||
|
|
||||||
public function store(array $data): Account;
|
public function store(array $data): Account;
|
||||||
|
|
||||||
public function update(Account $account, array $data): Account;
|
public function update(Account $account, array $data): Account;
|
||||||
|
@@ -29,9 +29,11 @@ use FireflyIII\Exceptions\FireflyException;
|
|||||||
use FireflyIII\Helpers\Collector\GroupCollectorInterface;
|
use FireflyIII\Helpers\Collector\GroupCollectorInterface;
|
||||||
use FireflyIII\Models\Account;
|
use FireflyIII\Models\Account;
|
||||||
use FireflyIII\Repositories\UserGroups\Currency\CurrencyRepositoryInterface;
|
use FireflyIII\Repositories\UserGroups\Currency\CurrencyRepositoryInterface;
|
||||||
|
use FireflyIII\Support\Facades\Steam;
|
||||||
use FireflyIII\User;
|
use FireflyIII\User;
|
||||||
use Illuminate\Contracts\Auth\Authenticatable;
|
use Illuminate\Contracts\Auth\Authenticatable;
|
||||||
use Illuminate\Support\Collection;
|
use Illuminate\Support\Collection;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class AccountTasker.
|
* Class AccountTasker.
|
||||||
@@ -46,10 +48,13 @@ class AccountTasker implements AccountTaskerInterface
|
|||||||
public function getAccountReport(Collection $accounts, Carbon $start, Carbon $end): array
|
public function getAccountReport(Collection $accounts, Carbon $start, Carbon $end): array
|
||||||
{
|
{
|
||||||
$yesterday = clone $start;
|
$yesterday = clone $start;
|
||||||
$yesterday->subDay();
|
$yesterday->subDay()->endOfDay(); // exactly up until $start but NOT including.
|
||||||
$startSet = app('steam')->finalAccountsBalance($accounts, $yesterday);
|
$end->endOfDay(); // needs to be end of day to be correct.
|
||||||
$endSet = app('steam')->finalAccountsBalance($accounts, $end);
|
Log::debug(sprintf('getAccountReport: finalAccountsBalance("%s")', $yesterday->format('Y-m-d H:i:s')));
|
||||||
app('log')->debug('Start of accountreport');
|
Log::debug(sprintf('getAccountReport: finalAccountsBalance("%s")', $end->format('Y-m-d H:i:s')));
|
||||||
|
$startSet = Steam::finalAccountsBalance($accounts, $yesterday);
|
||||||
|
$endSet = Steam::finalAccountsBalance($accounts, $end);
|
||||||
|
Log::debug('Start of accountreport');
|
||||||
|
|
||||||
/** @var AccountRepositoryInterface $repository */
|
/** @var AccountRepositoryInterface $repository */
|
||||||
$repository = app(AccountRepositoryInterface::class);
|
$repository = app(AccountRepositoryInterface::class);
|
||||||
@@ -90,10 +95,10 @@ class AccountTasker implements AccountTaskerInterface
|
|||||||
$entry['end_balance'] = $endSet[$account->id]['balance'] ?? '0';
|
$entry['end_balance'] = $endSet[$account->id]['balance'] ?? '0';
|
||||||
|
|
||||||
// first journal exists, and is on start, then this is the actual opening balance:
|
// first journal exists, and is on start, then this is the actual opening balance:
|
||||||
if (null !== $first && $first->date->isSameDay($start) && TransactionTypeEnum::OPENING_BALANCE->value === $first->transactionType->type) {
|
if (null !== $first && $first->date->isSameDay($yesterday) && TransactionTypeEnum::OPENING_BALANCE->value === $first->transactionType->type) {
|
||||||
app('log')->debug(sprintf('Date of first journal for %s is %s', $account->name, $first->date->format('Y-m-d')));
|
Log::debug(sprintf('Date of first journal for %s is %s', $account->name, $first->date->format('Y-m-d')));
|
||||||
$entry['start_balance'] = $first->transactions()->where('account_id', $account->id)->first()->amount;
|
$entry['start_balance'] = $first->transactions()->where('account_id', $account->id)->first()->amount;
|
||||||
app('log')->debug(sprintf('Account %s was opened on %s, so opening balance is %f', $account->name, $start->format('Y-m-d'), $entry['start_balance']));
|
Log::debug(sprintf('Account %s was opened on %s, so opening balance is %f', $account->name, $yesterday->format('Y-m-d'), $entry['start_balance']));
|
||||||
}
|
}
|
||||||
$return['sums'][$currency->id]['start'] = bcadd($return['sums'][$currency->id]['start'], $entry['start_balance']);
|
$return['sums'][$currency->id]['start'] = bcadd($return['sums'][$currency->id]['start'], $entry['start_balance']);
|
||||||
$return['sums'][$currency->id]['end'] = bcadd($return['sums'][$currency->id]['end'], $entry['end_balance']);
|
$return['sums'][$currency->id]['end'] = bcadd($return['sums'][$currency->id]['end'], $entry['end_balance']);
|
||||||
@@ -173,7 +178,7 @@ class AccountTasker implements AccountTaskerInterface
|
|||||||
];
|
];
|
||||||
$report['accounts'][$key]['sum'] = bcadd($report['accounts'][$key]['sum'], $journal['amount']);
|
$report['accounts'][$key]['sum'] = bcadd($report['accounts'][$key]['sum'], $journal['amount']);
|
||||||
|
|
||||||
app('log')->debug(sprintf('Sum for %s is now %s', $journal['destination_account_name'], $report['accounts'][$key]['sum']));
|
Log::debug(sprintf('Sum for %s is now %s', $journal['destination_account_name'], $report['accounts'][$key]['sum']));
|
||||||
|
|
||||||
++$report['accounts'][$key]['count'];
|
++$report['accounts'][$key]['count'];
|
||||||
}
|
}
|
||||||
|
@@ -38,8 +38,7 @@ use FireflyIII\Services\Internal\Destroy\BillDestroyService;
|
|||||||
use FireflyIII\Services\Internal\Update\BillUpdateService;
|
use FireflyIII\Services\Internal\Update\BillUpdateService;
|
||||||
use FireflyIII\Support\CacheProperties;
|
use FireflyIII\Support\CacheProperties;
|
||||||
use FireflyIII\Support\Facades\Amount;
|
use FireflyIII\Support\Facades\Amount;
|
||||||
use FireflyIII\User;
|
use FireflyIII\Support\Repositories\UserGroup\UserGroupTrait;
|
||||||
use Illuminate\Contracts\Auth\Authenticatable;
|
|
||||||
use Illuminate\Database\Query\JoinClause;
|
use Illuminate\Database\Query\JoinClause;
|
||||||
use Illuminate\Pagination\LengthAwarePaginator;
|
use Illuminate\Pagination\LengthAwarePaginator;
|
||||||
use Illuminate\Support\Collection;
|
use Illuminate\Support\Collection;
|
||||||
@@ -51,8 +50,7 @@ use Illuminate\Support\Facades\Log;
|
|||||||
class BillRepository implements BillRepositoryInterface
|
class BillRepository implements BillRepositoryInterface
|
||||||
{
|
{
|
||||||
use CreatesObjectGroups;
|
use CreatesObjectGroups;
|
||||||
|
use UserGroupTrait;
|
||||||
private User $user;
|
|
||||||
|
|
||||||
public function billEndsWith(string $query, int $limit): Collection
|
public function billEndsWith(string $query, int $limit): Collection
|
||||||
{
|
{
|
||||||
@@ -294,13 +292,6 @@ class BillRepository implements BillRepositoryInterface
|
|||||||
return $result;
|
return $result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setUser(null|Authenticatable|User $user): void
|
|
||||||
{
|
|
||||||
if ($user instanceof User) {
|
|
||||||
$this->user = $user;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getPaginator(int $size): LengthAwarePaginator
|
public function getPaginator(int $size): LengthAwarePaginator
|
||||||
{
|
{
|
||||||
return $this->user->bills()
|
return $this->user->bills()
|
||||||
|
@@ -26,6 +26,7 @@ namespace FireflyIII\Repositories\Bill;
|
|||||||
use Carbon\Carbon;
|
use Carbon\Carbon;
|
||||||
use FireflyIII\Exceptions\FireflyException;
|
use FireflyIII\Exceptions\FireflyException;
|
||||||
use FireflyIII\Models\Bill;
|
use FireflyIII\Models\Bill;
|
||||||
|
use FireflyIII\Models\UserGroup;
|
||||||
use FireflyIII\User;
|
use FireflyIII\User;
|
||||||
use Illuminate\Contracts\Auth\Authenticatable;
|
use Illuminate\Contracts\Auth\Authenticatable;
|
||||||
use Illuminate\Pagination\LengthAwarePaginator;
|
use Illuminate\Pagination\LengthAwarePaginator;
|
||||||
@@ -40,6 +41,8 @@ interface BillRepositoryInterface
|
|||||||
|
|
||||||
public function billStartsWith(string $query, int $limit): Collection;
|
public function billStartsWith(string $query, int $limit): Collection;
|
||||||
|
|
||||||
|
public function setUserGroup(UserGroup $userGroup): void;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add correct order to bills.
|
* Add correct order to bills.
|
||||||
*/
|
*/
|
||||||
|
@@ -41,8 +41,7 @@ use FireflyIII\Repositories\Account\AccountRepositoryInterface;
|
|||||||
use FireflyIII\Repositories\UserGroups\Currency\CurrencyRepositoryInterface;
|
use FireflyIII\Repositories\UserGroups\Currency\CurrencyRepositoryInterface;
|
||||||
use FireflyIII\Services\Internal\Destroy\BudgetDestroyService;
|
use FireflyIII\Services\Internal\Destroy\BudgetDestroyService;
|
||||||
use FireflyIII\Support\Http\Api\ExchangeRateConverter;
|
use FireflyIII\Support\Http\Api\ExchangeRateConverter;
|
||||||
use FireflyIII\User;
|
use FireflyIII\Support\Repositories\UserGroup\UserGroupTrait;
|
||||||
use Illuminate\Contracts\Auth\Authenticatable;
|
|
||||||
use Illuminate\Database\QueryException;
|
use Illuminate\Database\QueryException;
|
||||||
use Illuminate\Support\Collection;
|
use Illuminate\Support\Collection;
|
||||||
use Illuminate\Support\Facades\Log;
|
use Illuminate\Support\Facades\Log;
|
||||||
@@ -52,7 +51,7 @@ use Illuminate\Support\Facades\Log;
|
|||||||
*/
|
*/
|
||||||
class BudgetRepository implements BudgetRepositoryInterface
|
class BudgetRepository implements BudgetRepositoryInterface
|
||||||
{
|
{
|
||||||
private User $user;
|
use UserGroupTrait;
|
||||||
|
|
||||||
public function budgetEndsWith(string $query, int $limit): Collection
|
public function budgetEndsWith(string $query, int $limit): Collection
|
||||||
{
|
{
|
||||||
@@ -154,13 +153,6 @@ class BudgetRepository implements BudgetRepositoryInterface
|
|||||||
return $return;
|
return $return;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setUser(null|Authenticatable|User $user): void
|
|
||||||
{
|
|
||||||
if ($user instanceof User) {
|
|
||||||
$this->user = $user;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getActiveBudgets(): Collection
|
public function getActiveBudgets(): Collection
|
||||||
{
|
{
|
||||||
return $this->user->budgets()->where('active', true)
|
return $this->user->budgets()->where('active', true)
|
||||||
|
@@ -27,6 +27,7 @@ use Carbon\Carbon;
|
|||||||
use FireflyIII\Exceptions\FireflyException;
|
use FireflyIII\Exceptions\FireflyException;
|
||||||
use FireflyIII\Models\AutoBudget;
|
use FireflyIII\Models\AutoBudget;
|
||||||
use FireflyIII\Models\Budget;
|
use FireflyIII\Models\Budget;
|
||||||
|
use FireflyIII\Models\UserGroup;
|
||||||
use FireflyIII\User;
|
use FireflyIII\User;
|
||||||
use Illuminate\Contracts\Auth\Authenticatable;
|
use Illuminate\Contracts\Auth\Authenticatable;
|
||||||
use Illuminate\Support\Collection;
|
use Illuminate\Support\Collection;
|
||||||
@@ -40,6 +41,8 @@ interface BudgetRepositoryInterface
|
|||||||
|
|
||||||
public function budgetStartsWith(string $query, int $limit): Collection;
|
public function budgetStartsWith(string $query, int $limit): Collection;
|
||||||
|
|
||||||
|
public function setUserGroup(UserGroup $userGroup): void;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the amount that is budgeted in a period.
|
* Returns the amount that is budgeted in a period.
|
||||||
*/
|
*/
|
||||||
|
@@ -214,7 +214,6 @@ class OperationsRepository implements OperationsRepositoryInterface
|
|||||||
Log::debug(sprintf('Start of %s.', __METHOD__));
|
Log::debug(sprintf('Start of %s.', __METHOD__));
|
||||||
// this collector excludes all transfers TO liabilities (which are also withdrawals)
|
// this collector excludes all transfers TO liabilities (which are also withdrawals)
|
||||||
// because those expenses only become expenses once they move from the liability to the friend.
|
// because those expenses only become expenses once they move from the liability to the friend.
|
||||||
|
|
||||||
// 2024-12-24 disable the exclusion for now.
|
// 2024-12-24 disable the exclusion for now.
|
||||||
|
|
||||||
$repository = app(AccountRepositoryInterface::class);
|
$repository = app(AccountRepositoryInterface::class);
|
||||||
@@ -245,7 +244,7 @@ class OperationsRepository implements OperationsRepositoryInterface
|
|||||||
}
|
}
|
||||||
if (null !== $currency) {
|
if (null !== $currency) {
|
||||||
Log::debug(sprintf('Limit to currency %s', $currency->code));
|
Log::debug(sprintf('Limit to currency %s', $currency->code));
|
||||||
$collector->setNormalCurrency($currency);
|
$collector->setCurrency($currency);
|
||||||
}
|
}
|
||||||
$collector->setBudgets($budgets);
|
$collector->setBudgets($budgets);
|
||||||
$journals = $collector->getExtractedJournals();
|
$journals = $collector->getExtractedJournals();
|
||||||
|
@@ -33,6 +33,7 @@ use FireflyIII\Models\RecurrenceTransactionMeta;
|
|||||||
use FireflyIII\Models\RuleAction;
|
use FireflyIII\Models\RuleAction;
|
||||||
use FireflyIII\Services\Internal\Destroy\CategoryDestroyService;
|
use FireflyIII\Services\Internal\Destroy\CategoryDestroyService;
|
||||||
use FireflyIII\Services\Internal\Update\CategoryUpdateService;
|
use FireflyIII\Services\Internal\Update\CategoryUpdateService;
|
||||||
|
use FireflyIII\Support\Repositories\UserGroup\UserGroupTrait;
|
||||||
use FireflyIII\User;
|
use FireflyIII\User;
|
||||||
use Illuminate\Contracts\Auth\Authenticatable;
|
use Illuminate\Contracts\Auth\Authenticatable;
|
||||||
use Illuminate\Support\Collection;
|
use Illuminate\Support\Collection;
|
||||||
@@ -43,7 +44,7 @@ use Illuminate\Support\Facades\Log;
|
|||||||
*/
|
*/
|
||||||
class CategoryRepository implements CategoryRepositoryInterface
|
class CategoryRepository implements CategoryRepositoryInterface
|
||||||
{
|
{
|
||||||
private User $user;
|
use UserGroupTrait;
|
||||||
|
|
||||||
public function categoryEndsWith(string $query, int $limit): Collection
|
public function categoryEndsWith(string $query, int $limit): Collection
|
||||||
{
|
{
|
||||||
|
@@ -26,6 +26,7 @@ namespace FireflyIII\Repositories\Category;
|
|||||||
use Carbon\Carbon;
|
use Carbon\Carbon;
|
||||||
use FireflyIII\Exceptions\FireflyException;
|
use FireflyIII\Exceptions\FireflyException;
|
||||||
use FireflyIII\Models\Category;
|
use FireflyIII\Models\Category;
|
||||||
|
use FireflyIII\Models\UserGroup;
|
||||||
use FireflyIII\User;
|
use FireflyIII\User;
|
||||||
use Illuminate\Contracts\Auth\Authenticatable;
|
use Illuminate\Contracts\Auth\Authenticatable;
|
||||||
use Illuminate\Support\Collection;
|
use Illuminate\Support\Collection;
|
||||||
@@ -88,6 +89,8 @@ interface CategoryRepositoryInterface
|
|||||||
|
|
||||||
public function setUser(null|Authenticatable|User $user): void;
|
public function setUser(null|Authenticatable|User $user): void;
|
||||||
|
|
||||||
|
public function setUserGroup(UserGroup $userGroup): void;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @throws FireflyException
|
* @throws FireflyException
|
||||||
*/
|
*/
|
||||||
|
@@ -57,7 +57,7 @@ class CurrencyRepository implements CurrencyRepositoryInterface
|
|||||||
*/
|
*/
|
||||||
public function getCompleteSet(): Collection
|
public function getCompleteSet(): Collection
|
||||||
{
|
{
|
||||||
return TransactionCurrency::orderBy('code', 'ASC')->get();
|
return TransactionCurrency::where('enabled', true)->orderBy('code', 'ASC')->get();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -36,6 +36,7 @@ use FireflyIII\Models\TransactionJournal;
|
|||||||
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
|
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
|
||||||
use FireflyIII\Repositories\Journal\JournalRepositoryInterface;
|
use FireflyIII\Repositories\Journal\JournalRepositoryInterface;
|
||||||
use FireflyIII\Support\Facades\Steam;
|
use FireflyIII\Support\Facades\Steam;
|
||||||
|
use FireflyIII\Support\Repositories\UserGroup\UserGroupTrait;
|
||||||
use FireflyIII\User;
|
use FireflyIII\User;
|
||||||
use Illuminate\Contracts\Auth\Authenticatable;
|
use Illuminate\Contracts\Auth\Authenticatable;
|
||||||
use Illuminate\Support\Collection;
|
use Illuminate\Support\Collection;
|
||||||
@@ -48,7 +49,7 @@ class PiggyBankRepository implements PiggyBankRepositoryInterface
|
|||||||
{
|
{
|
||||||
use ModifiesPiggyBanks;
|
use ModifiesPiggyBanks;
|
||||||
|
|
||||||
private User $user;
|
use UserGroupTrait;
|
||||||
|
|
||||||
public function destroyAll(): void
|
public function destroyAll(): void
|
||||||
{
|
{
|
||||||
@@ -308,6 +309,24 @@ class PiggyBankRepository implements PiggyBankRepositoryInterface
|
|||||||
return $sum;
|
return $sum;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get current amount saved in piggy bank.
|
||||||
|
*/
|
||||||
|
public function getCurrentNativeAmount(PiggyBank $piggyBank, ?Account $account = null): string
|
||||||
|
{
|
||||||
|
$sum = '0';
|
||||||
|
foreach ($piggyBank->accounts as $current) {
|
||||||
|
if (null !== $account && $account->id !== $current->id) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$amount = (string) $current->pivot->native_current_amount;
|
||||||
|
$amount = '' === $amount ? '0' : $amount;
|
||||||
|
$sum = bcadd($sum, $amount);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $sum;
|
||||||
|
}
|
||||||
|
|
||||||
public function getRepetition(PiggyBank $piggyBank, bool $overrule = false): ?PiggyBankRepetition
|
public function getRepetition(PiggyBank $piggyBank, bool $overrule = false): ?PiggyBankRepetition
|
||||||
{
|
{
|
||||||
if (false === $overrule) {
|
if (false === $overrule) {
|
||||||
@@ -352,6 +371,7 @@ class PiggyBankRepository implements PiggyBankRepositoryInterface
|
|||||||
public function leftOnAccount(PiggyBank $piggyBank, Account $account, Carbon $date): string
|
public function leftOnAccount(PiggyBank $piggyBank, Account $account, Carbon $date): string
|
||||||
{
|
{
|
||||||
Log::debug(sprintf('leftOnAccount("%s","%s","%s")', $piggyBank->name, $account->name, $date->format('Y-m-d H:i:s')));
|
Log::debug(sprintf('leftOnAccount("%s","%s","%s")', $piggyBank->name, $account->name, $date->format('Y-m-d H:i:s')));
|
||||||
|
Log::debug(sprintf('leftOnAccount: Call finalAccountBalance with date/time "%s"', $date->toIso8601String()));
|
||||||
$balance = Steam::finalAccountBalance($account, $date)['balance'];
|
$balance = Steam::finalAccountBalance($account, $date)['balance'];
|
||||||
|
|
||||||
Log::debug(sprintf('Balance is: %s', $balance));
|
Log::debug(sprintf('Balance is: %s', $balance));
|
||||||
|
@@ -29,6 +29,7 @@ use FireflyIII\Models\Account;
|
|||||||
use FireflyIII\Models\PiggyBank;
|
use FireflyIII\Models\PiggyBank;
|
||||||
use FireflyIII\Models\PiggyBankRepetition;
|
use FireflyIII\Models\PiggyBankRepetition;
|
||||||
use FireflyIII\Models\TransactionJournal;
|
use FireflyIII\Models\TransactionJournal;
|
||||||
|
use FireflyIII\Models\UserGroup;
|
||||||
use FireflyIII\User;
|
use FireflyIII\User;
|
||||||
use Illuminate\Contracts\Auth\Authenticatable;
|
use Illuminate\Contracts\Auth\Authenticatable;
|
||||||
use Illuminate\Support\Collection;
|
use Illuminate\Support\Collection;
|
||||||
@@ -40,6 +41,8 @@ interface PiggyBankRepositoryInterface
|
|||||||
{
|
{
|
||||||
public function addAmount(PiggyBank $piggyBank, Account $account, string $amount, ?TransactionJournal $journal = null): bool;
|
public function addAmount(PiggyBank $piggyBank, Account $account, string $amount, ?TransactionJournal $journal = null): bool;
|
||||||
|
|
||||||
|
public function getCurrentNativeAmount(PiggyBank $piggyBank, ?Account $account = null): string;
|
||||||
|
|
||||||
public function addAmountToPiggyBank(PiggyBank $piggyBank, string $amount, TransactionJournal $journal): void;
|
public function addAmountToPiggyBank(PiggyBank $piggyBank, string $amount, TransactionJournal $journal): void;
|
||||||
|
|
||||||
public function canAddAmount(PiggyBank $piggyBank, Account $account, string $amount): bool;
|
public function canAddAmount(PiggyBank $piggyBank, Account $account, string $amount): bool;
|
||||||
@@ -135,6 +138,8 @@ interface PiggyBankRepositoryInterface
|
|||||||
|
|
||||||
public function setUser(null|Authenticatable|User $user): void;
|
public function setUser(null|Authenticatable|User $user): void;
|
||||||
|
|
||||||
|
public function setUserGroup(UserGroup $userGroup): void;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Store new piggy bank.
|
* Store new piggy bank.
|
||||||
*
|
*
|
||||||
|
@@ -93,7 +93,7 @@ class RecurringRepository implements RecurringRepositoryInterface
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns all of the user's recurring transactions.
|
* Returns all the user's recurring transactions.
|
||||||
*/
|
*/
|
||||||
public function get(): Collection
|
public function get(): Collection
|
||||||
{
|
{
|
||||||
|
@@ -43,8 +43,7 @@ use FireflyIII\Repositories\Attachment\AttachmentRepositoryInterface;
|
|||||||
use FireflyIII\Services\Internal\Destroy\TransactionGroupDestroyService;
|
use FireflyIII\Services\Internal\Destroy\TransactionGroupDestroyService;
|
||||||
use FireflyIII\Services\Internal\Update\GroupUpdateService;
|
use FireflyIII\Services\Internal\Update\GroupUpdateService;
|
||||||
use FireflyIII\Support\NullArrayObject;
|
use FireflyIII\Support\NullArrayObject;
|
||||||
use FireflyIII\User;
|
use FireflyIII\Support\Repositories\UserGroup\UserGroupTrait;
|
||||||
use Illuminate\Contracts\Auth\Authenticatable;
|
|
||||||
use Illuminate\Database\Eloquent\Builder;
|
use Illuminate\Database\Eloquent\Builder;
|
||||||
use Illuminate\Support\Collection;
|
use Illuminate\Support\Collection;
|
||||||
|
|
||||||
@@ -53,7 +52,7 @@ use Illuminate\Support\Collection;
|
|||||||
*/
|
*/
|
||||||
class TransactionGroupRepository implements TransactionGroupRepositoryInterface
|
class TransactionGroupRepository implements TransactionGroupRepositoryInterface
|
||||||
{
|
{
|
||||||
private User $user;
|
use UserGroupTrait;
|
||||||
|
|
||||||
public function countAttachments(int $journalId): int
|
public function countAttachments(int $journalId): int
|
||||||
{
|
{
|
||||||
@@ -163,13 +162,6 @@ class TransactionGroupRepository implements TransactionGroupRepositoryInterface
|
|||||||
return $result;
|
return $result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setUser(null|Authenticatable|User $user): void
|
|
||||||
{
|
|
||||||
if ($user instanceof User) {
|
|
||||||
$this->user = $user;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the note text for a journal (by ID).
|
* Get the note text for a journal (by ID).
|
||||||
*/
|
*/
|
||||||
@@ -408,7 +400,8 @@ class TransactionGroupRepository implements TransactionGroupRepositoryInterface
|
|||||||
{
|
{
|
||||||
/** @var TransactionGroupFactory $factory */
|
/** @var TransactionGroupFactory $factory */
|
||||||
$factory = app(TransactionGroupFactory::class);
|
$factory = app(TransactionGroupFactory::class);
|
||||||
$factory->setUser($this->user);
|
$factory->setUser($data['user']);
|
||||||
|
$factory->setUserGroup($data['user_group']);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
return $factory->create($data);
|
return $factory->create($data);
|
||||||
|
@@ -28,6 +28,7 @@ use FireflyIII\Exceptions\DuplicateTransactionException;
|
|||||||
use FireflyIII\Exceptions\FireflyException;
|
use FireflyIII\Exceptions\FireflyException;
|
||||||
use FireflyIII\Models\Location;
|
use FireflyIII\Models\Location;
|
||||||
use FireflyIII\Models\TransactionGroup;
|
use FireflyIII\Models\TransactionGroup;
|
||||||
|
use FireflyIII\Models\UserGroup;
|
||||||
use FireflyIII\Support\NullArrayObject;
|
use FireflyIII\Support\NullArrayObject;
|
||||||
use FireflyIII\User;
|
use FireflyIII\User;
|
||||||
use Illuminate\Contracts\Auth\Authenticatable;
|
use Illuminate\Contracts\Auth\Authenticatable;
|
||||||
@@ -99,6 +100,8 @@ interface TransactionGroupRepositoryInterface
|
|||||||
|
|
||||||
public function setUser(null|Authenticatable|User $user): void;
|
public function setUser(null|Authenticatable|User $user): void;
|
||||||
|
|
||||||
|
public function setUserGroup(UserGroup $userGroup): void;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new transaction group.
|
* Create a new transaction group.
|
||||||
*
|
*
|
||||||
|
@@ -108,6 +108,6 @@ class ExchangeRateRepository implements ExchangeRateRepositoryInterface
|
|||||||
#[\Override]
|
#[\Override]
|
||||||
public function getAll(): Collection
|
public function getAll(): Collection
|
||||||
{
|
{
|
||||||
return $this->userGroup->currencyExchangeRates()->get();
|
return $this->userGroup->currencyExchangeRates()->orderBy('date', 'ASC')->get();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -659,9 +659,10 @@ trait AccountServiceTrait
|
|||||||
|
|
||||||
// submit to factory:
|
// submit to factory:
|
||||||
$submission = [
|
$submission = [
|
||||||
'group_title' => null,
|
'group_title' => null,
|
||||||
'user' => $account->user_id,
|
'user' => $account->user,
|
||||||
'transactions' => [
|
'user_group' => $account->user->userGroup,
|
||||||
|
'transactions' => [
|
||||||
[
|
[
|
||||||
'type' => 'Opening balance',
|
'type' => 'Opening balance',
|
||||||
'date' => $openingBalanceDate,
|
'date' => $openingBalanceDate,
|
||||||
@@ -669,7 +670,8 @@ trait AccountServiceTrait
|
|||||||
'source_name' => $sourceName,
|
'source_name' => $sourceName,
|
||||||
'destination_id' => $destId,
|
'destination_id' => $destId,
|
||||||
'destination_name' => $destName,
|
'destination_name' => $destName,
|
||||||
'user' => $account->user_id,
|
'user' => $account->user,
|
||||||
|
'user_group' => $account->user->userGroup,
|
||||||
'currency_id' => $currency->id,
|
'currency_id' => $currency->id,
|
||||||
'order' => 0,
|
'order' => 0,
|
||||||
'amount' => $amount,
|
'amount' => $amount,
|
||||||
|
@@ -203,8 +203,7 @@ class FrontpageChartGenerator
|
|||||||
$amount = $limit->native_amount;
|
$amount = $limit->native_amount;
|
||||||
Log::debug(sprintf('Amount is now "%s".', $amount));
|
Log::debug(sprintf('Amount is now "%s".', $amount));
|
||||||
}
|
}
|
||||||
|
$amount = null === $amount ? '0' : $amount;
|
||||||
|
|
||||||
$sumSpent = bcmul($entry['sum'], '-1'); // spent
|
$sumSpent = bcmul($entry['sum'], '-1'); // spent
|
||||||
$data[0]['entries'][$title] ??= '0';
|
$data[0]['entries'][$title] ??= '0';
|
||||||
$data[1]['entries'][$title] ??= '0';
|
$data[1]['entries'][$title] ??= '0';
|
||||||
|
@@ -513,7 +513,7 @@ class ExportDataGenerator
|
|||||||
'currency_code', 'foreign_currency_code', 'source_name', 'source_type', 'destination_name', 'destination_type', 'amount', 'foreign_amount', 'category', 'budget', 'piggy_bank', 'tags',
|
'currency_code', 'foreign_currency_code', 'source_name', 'source_type', 'destination_name', 'destination_type', 'amount', 'foreign_amount', 'category', 'budget', 'piggy_bank', 'tags',
|
||||||
];
|
];
|
||||||
$records = [];
|
$records = [];
|
||||||
$recurrences = $recurringRepos->getAll();
|
$recurrences = $recurringRepos->get();
|
||||||
|
|
||||||
/** @var Recurrence $recurrence */
|
/** @var Recurrence $recurrence */
|
||||||
foreach ($recurrences as $recurrence) {
|
foreach ($recurrences as $recurrence) {
|
||||||
|
@@ -88,6 +88,11 @@ class ExchangeRateConverter
|
|||||||
|
|
||||||
return '1';
|
return '1';
|
||||||
}
|
}
|
||||||
|
if ($from->id === $to->id) {
|
||||||
|
Log::debug('ExchangeRateConverter: From and to are the same, return "1".');
|
||||||
|
|
||||||
|
return '1';
|
||||||
|
}
|
||||||
$rate = $this->getRate($from, $to, $date);
|
$rate = $this->getRate($from, $to, $date);
|
||||||
|
|
||||||
return '0' === $rate ? '1' : $rate;
|
return '0' === $rate ? '1' : $rate;
|
||||||
@@ -103,7 +108,7 @@ class ExchangeRateConverter
|
|||||||
|
|
||||||
// find in cache
|
// find in cache
|
||||||
if (null !== $res) {
|
if (null !== $res) {
|
||||||
Log::debug(sprintf('ExchangeRateConverter: Return cached rate from #%d to #%d on %s.', $from->id, $to->id, $date->format('Y-m-d')));
|
Log::debug(sprintf('ExchangeRateConverter: Return cached rate from %s to %s on %s.', $from->code, $to->code, $date->format('Y-m-d')));
|
||||||
|
|
||||||
return $res;
|
return $res;
|
||||||
}
|
}
|
||||||
@@ -112,7 +117,7 @@ class ExchangeRateConverter
|
|||||||
$rate = $this->getFromDB($from->id, $to->id, $date->format('Y-m-d'));
|
$rate = $this->getFromDB($from->id, $to->id, $date->format('Y-m-d'));
|
||||||
if (null !== $rate) {
|
if (null !== $rate) {
|
||||||
Cache::forever($key, $rate);
|
Cache::forever($key, $rate);
|
||||||
Log::debug(sprintf('ExchangeRateConverter: Return DB rate from #%d to #%d on %s.', $from->id, $to->id, $date->format('Y-m-d')));
|
Log::debug(sprintf('ExchangeRateConverter: Return DB rate from %s to %s on %s.', $from->code, $to->code, $date->format('Y-m-d')));
|
||||||
|
|
||||||
return $rate;
|
return $rate;
|
||||||
}
|
}
|
||||||
@@ -122,7 +127,7 @@ class ExchangeRateConverter
|
|||||||
if (null !== $rate) {
|
if (null !== $rate) {
|
||||||
$rate = bcdiv('1', $rate);
|
$rate = bcdiv('1', $rate);
|
||||||
Cache::forever($key, $rate);
|
Cache::forever($key, $rate);
|
||||||
Log::debug(sprintf('ExchangeRateConverter: Return inverse DB rate from #%d to #%d on %s.', $from->id, $to->id, $date->format('Y-m-d')));
|
Log::debug(sprintf('ExchangeRateConverter: Return inverse DB rate from %s to %s on %s.', $from->code, $to->code, $date->format('Y-m-d')));
|
||||||
|
|
||||||
return $rate;
|
return $rate;
|
||||||
}
|
}
|
||||||
@@ -133,14 +138,14 @@ class ExchangeRateConverter
|
|||||||
|
|
||||||
// combined (if present), they can be used to calculate the necessary conversion rate.
|
// combined (if present), they can be used to calculate the necessary conversion rate.
|
||||||
if (0 === bccomp('0', $first) || 0 === bccomp('0', $second)) {
|
if (0 === bccomp('0', $first) || 0 === bccomp('0', $second)) {
|
||||||
Log::warning(sprintf('$first is "%s" and $second is "%s"', $first, $second));
|
Log::warning(sprintf('There is not enough information to convert %s to %s on date %s', $from->code, $to->code, $date->format('Y-m-d')));
|
||||||
|
|
||||||
return '1';
|
return '1';
|
||||||
}
|
}
|
||||||
|
|
||||||
$second = bcdiv('1', $second);
|
$second = bcdiv('1', $second);
|
||||||
$rate = bcmul($first, $second);
|
$rate = bcmul($first, $second);
|
||||||
Log::debug(sprintf('ExchangeRateConverter: Return DB rate from #%d to #%d on %s.', $from->id, $to->id, $date->format('Y-m-d')));
|
Log::debug(sprintf('ExchangeRateConverter: Return DB rate from %s to %s on %s.', $from->code, $to->code, $date->format('Y-m-d')));
|
||||||
Cache::forever($key, $rate);
|
Cache::forever($key, $rate);
|
||||||
|
|
||||||
return $rate;
|
return $rate;
|
||||||
@@ -154,6 +159,8 @@ class ExchangeRateConverter
|
|||||||
private function getFromDB(int $from, int $to, string $date): ?string
|
private function getFromDB(int $from, int $to, string $date): ?string
|
||||||
{
|
{
|
||||||
if ($from === $to) {
|
if ($from === $to) {
|
||||||
|
Log::debug('ExchangeRateConverter: From and to are the same, return "1".');
|
||||||
|
|
||||||
return '1';
|
return '1';
|
||||||
}
|
}
|
||||||
$key = sprintf('cer-%d-%d-%s', $from, $to, $date);
|
$key = sprintf('cer-%d-%d-%s', $from, $to, $date);
|
||||||
@@ -173,7 +180,7 @@ class ExchangeRateConverter
|
|||||||
if ('' === $rate) {
|
if ('' === $rate) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
Log::debug(sprintf('ExchangeRateConverter: Found !cached! rate from #%d to #%d on %s.', $from, $to, $date));
|
Log::debug(sprintf('ExchangeRateConverter: Found cached rate from #%d to #%d on %s.', $from, $to, $date));
|
||||||
|
|
||||||
return $rate;
|
return $rate;
|
||||||
}
|
}
|
||||||
|
@@ -38,6 +38,8 @@ use Illuminate\Support\Facades\Log;
|
|||||||
*/
|
*/
|
||||||
trait ValidatesUserGroupTrait
|
trait ValidatesUserGroupTrait
|
||||||
{
|
{
|
||||||
|
protected ?UserGroup $userGroup = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An "undocumented" filter
|
* An "undocumented" filter
|
||||||
*
|
*
|
||||||
@@ -59,7 +61,7 @@ trait ValidatesUserGroupTrait
|
|||||||
$user = auth()->user();
|
$user = auth()->user();
|
||||||
$groupId = 0;
|
$groupId = 0;
|
||||||
if (!$request->has('user_group_id')) {
|
if (!$request->has('user_group_id')) {
|
||||||
$groupId = $user->user_group_id;
|
$groupId = (int) $user->user_group_id;
|
||||||
Log::debug(sprintf('validateUserGroup: no user group submitted, use default group #%d.', $groupId));
|
Log::debug(sprintf('validateUserGroup: no user group submitted, use default group #%d.', $groupId));
|
||||||
}
|
}
|
||||||
if ($request->has('user_group_id')) {
|
if ($request->has('user_group_id')) {
|
||||||
@@ -98,6 +100,7 @@ trait ValidatesUserGroupTrait
|
|||||||
foreach ($roles as $role) {
|
foreach ($roles as $role) {
|
||||||
if ($user->hasRoleInGroupOrOwner($group, $role)) {
|
if ($user->hasRoleInGroupOrOwner($group, $role)) {
|
||||||
Log::debug(sprintf('validateUserGroup: User has role "%s" in group #%d, return the group.', $role->value, $groupId));
|
Log::debug(sprintf('validateUserGroup: User has role "%s" in group #%d, return the group.', $role->value, $groupId));
|
||||||
|
$this->userGroup = $group;
|
||||||
|
|
||||||
return $group;
|
return $group;
|
||||||
}
|
}
|
||||||
|
@@ -33,6 +33,7 @@ use FireflyIII\Support\CacheProperties;
|
|||||||
use FireflyIII\Support\Facades\Amount;
|
use FireflyIII\Support\Facades\Amount;
|
||||||
use FireflyIII\Support\Facades\Steam;
|
use FireflyIII\Support\Facades\Steam;
|
||||||
use Illuminate\Support\Collection;
|
use Illuminate\Support\Collection;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Trait ChartGeneration
|
* Trait ChartGeneration
|
||||||
@@ -57,7 +58,7 @@ trait ChartGeneration
|
|||||||
if ($cache->has()) {
|
if ($cache->has()) {
|
||||||
return $cache->get();
|
return $cache->get();
|
||||||
}
|
}
|
||||||
app('log')->debug('Regenerate chart.account.account-balance-chart from scratch.');
|
Log::debug('Regenerate chart.account.account-balance-chart from scratch.');
|
||||||
$locale = app('steam')->getLocale();
|
$locale = app('steam')->getLocale();
|
||||||
|
|
||||||
/** @var GeneratorInterface $generator */
|
/** @var GeneratorInterface $generator */
|
||||||
@@ -69,12 +70,16 @@ trait ChartGeneration
|
|||||||
$default = app('amount')->getNativeCurrency();
|
$default = app('amount')->getNativeCurrency();
|
||||||
$chartData = [];
|
$chartData = [];
|
||||||
|
|
||||||
|
Log::debug(sprintf('Start of accountBalanceChart(list, %s, %s)', $start->format('Y-m-d H:i:s'), $end->format('Y-m-d H:i:s')));
|
||||||
|
|
||||||
/** @var Account $account */
|
/** @var Account $account */
|
||||||
foreach ($accounts as $account) {
|
foreach ($accounts as $account) {
|
||||||
|
Log::debug(sprintf('Now at account #%d ("%s)', $account->id, $account->name));
|
||||||
$currency = $accountRepos->getAccountCurrency($account) ?? $default;
|
$currency = $accountRepos->getAccountCurrency($account) ?? $default;
|
||||||
$useNative = $convertToNative && $default->id !== $currency->id;
|
$useNative = $convertToNative && $default->id !== $currency->id;
|
||||||
$field = $useNative ? 'native_balance' : 'balance';
|
$field = $convertToNative ? 'native_balance' : 'balance';
|
||||||
$currency = $useNative ? $default : $currency;
|
$currency = $useNative ? $default : $currency;
|
||||||
|
Log::debug(sprintf('Will use field %s', $field));
|
||||||
$currentSet = [
|
$currentSet = [
|
||||||
'label' => $account->name,
|
'label' => $account->name,
|
||||||
'currency_symbol' => $currency->symbol,
|
'currency_symbol' => $currency->symbol,
|
||||||
@@ -82,8 +87,9 @@ trait ChartGeneration
|
|||||||
];
|
];
|
||||||
|
|
||||||
$currentStart = clone $start;
|
$currentStart = clone $start;
|
||||||
$range = Steam::finalAccountBalanceInRange($account, $start, clone $end, $this->convertToNative);
|
$range = Steam::finalAccountBalanceInRange($account, clone $start, clone $end, $this->convertToNative);
|
||||||
$previous = array_values($range)[0];
|
$previous = array_values($range)[0];
|
||||||
|
Log::debug(sprintf('Start balance for account #%d ("%s) is', $account->id, $account->name), $previous);
|
||||||
while ($currentStart <= $end) {
|
while ($currentStart <= $end) {
|
||||||
$format = $currentStart->format('Y-m-d');
|
$format = $currentStart->format('Y-m-d');
|
||||||
$label = trim($currentStart->isoFormat((string) trans('config.month_and_day_js', [], $locale)));
|
$label = trim($currentStart->isoFormat((string) trans('config.month_and_day_js', [], $locale)));
|
||||||
|
@@ -203,11 +203,10 @@ trait PeriodOverview
|
|||||||
$currencySymbol = $journal['currency_symbol'];
|
$currencySymbol = $journal['currency_symbol'];
|
||||||
$currencyDecimalPlaces = $journal['currency_decimal_places'];
|
$currencyDecimalPlaces = $journal['currency_decimal_places'];
|
||||||
$foreignCurrencyId = $journal['foreign_currency_id'];
|
$foreignCurrencyId = $journal['foreign_currency_id'];
|
||||||
$amount = $journal['amount'];
|
$amount = $journal['amount'] ?? '0';
|
||||||
|
|
||||||
|
|
||||||
if ($this->convertToNative && $currencyId !== $this->defaultCurrency->id && $foreignCurrencyId !== $this->defaultCurrency->id) {
|
if ($this->convertToNative && $currencyId !== $this->defaultCurrency->id && $foreignCurrencyId !== $this->defaultCurrency->id) {
|
||||||
$amount = $journal['native_amount'];
|
$amount = $journal['native_amount'] ?? '0';
|
||||||
$currencyId = $this->defaultCurrency->id;
|
$currencyId = $this->defaultCurrency->id;
|
||||||
$currencyCode = $this->defaultCurrency->code;
|
$currencyCode = $this->defaultCurrency->code;
|
||||||
$currencyName = $this->defaultCurrency->name;
|
$currencyName = $this->defaultCurrency->name;
|
||||||
@@ -220,7 +219,7 @@ trait PeriodOverview
|
|||||||
$currencyName = $journal['foreign_currency_name'];
|
$currencyName = $journal['foreign_currency_name'];
|
||||||
$currencySymbol = $journal['foreign_currency_symbol'];
|
$currencySymbol = $journal['foreign_currency_symbol'];
|
||||||
$currencyDecimalPlaces = $journal['foreign_currency_decimal_places'];
|
$currencyDecimalPlaces = $journal['foreign_currency_decimal_places'];
|
||||||
$amount = $journal['foreign_amount'];
|
$amount = $journal['foreign_amount'] ?? '0';
|
||||||
}
|
}
|
||||||
$return[$currencyId] ??= [
|
$return[$currencyId] ??= [
|
||||||
'amount' => '0',
|
'amount' => '0',
|
||||||
|
@@ -202,7 +202,7 @@ class Preferences
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
if ('' === $result->data) {
|
if ('' === $result->data) {
|
||||||
Log::warning(sprintf('Empty encrypted preference found: "%s"', $name));
|
// Log::warning(sprintf('Empty encrypted preference found: "%s"', $name));
|
||||||
|
|
||||||
return $result;
|
return $result;
|
||||||
}
|
}
|
||||||
@@ -214,7 +214,7 @@ class Preferences
|
|||||||
Log::debug('Set data to NULL');
|
Log::debug('Set data to NULL');
|
||||||
$result->data = null;
|
$result->data = null;
|
||||||
}
|
}
|
||||||
Log::error(sprintf('Could not decrypt preference "%s": %s', $name, $e->getMessage()));
|
// Log::error(sprintf('Could not decrypt preference "%s": %s', $name, $e->getMessage()));
|
||||||
|
|
||||||
return $result;
|
return $result;
|
||||||
}
|
}
|
||||||
@@ -226,7 +226,7 @@ class Preferences
|
|||||||
{
|
{
|
||||||
$result = $this->getForUser($user, $name, $default);
|
$result = $this->getForUser($user, $name, $default);
|
||||||
if ('' === $result->data) {
|
if ('' === $result->data) {
|
||||||
Log::warning(sprintf('Empty encrypted preference found: "%s"', $name));
|
// Log::warning(sprintf('Empty encrypted preference found: "%s"', $name));
|
||||||
|
|
||||||
return $result;
|
return $result;
|
||||||
}
|
}
|
||||||
@@ -238,7 +238,7 @@ class Preferences
|
|||||||
Log::debug('Set data to NULL');
|
Log::debug('Set data to NULL');
|
||||||
$result->data = null;
|
$result->data = null;
|
||||||
}
|
}
|
||||||
Log::error(sprintf('Could not decrypt preference "%s": %s', $name, $e->getMessage()));
|
// Log::error(sprintf('Could not decrypt preference "%s": %s', $name, $e->getMessage()));
|
||||||
|
|
||||||
return $result;
|
return $result;
|
||||||
}
|
}
|
||||||
|
@@ -51,6 +51,7 @@ class TransactionSummarizer
|
|||||||
|
|
||||||
public function groupByCurrencyId(array $journals, string $method = 'negative'): array
|
public function groupByCurrencyId(array $journals, string $method = 'negative'): array
|
||||||
{
|
{
|
||||||
|
Log::debug(sprintf('Now in groupByCurrencyId(array, "%s")', $method));
|
||||||
$array = [];
|
$array = [];
|
||||||
foreach ($journals as $journal) {
|
foreach ($journals as $journal) {
|
||||||
$field = 'amount';
|
$field = 'amount';
|
||||||
@@ -61,6 +62,10 @@ class TransactionSummarizer
|
|||||||
$currencySymbol = $journal['currency_symbol'];
|
$currencySymbol = $journal['currency_symbol'];
|
||||||
$currencyCode = $journal['currency_code'];
|
$currencyCode = $journal['currency_code'];
|
||||||
$currencyDecimalPlaces = $journal['currency_decimal_places'];
|
$currencyDecimalPlaces = $journal['currency_decimal_places'];
|
||||||
|
|
||||||
|
// prepare foreign currency info:
|
||||||
|
$foreignCurrencyId = 0;
|
||||||
|
|
||||||
if ($this->convertToNative) {
|
if ($this->convertToNative) {
|
||||||
// if convert to native, use the native amount yes or no?
|
// if convert to native, use the native amount yes or no?
|
||||||
$useNative = $this->default->id !== (int) $journal['currency_id'];
|
$useNative = $this->default->id !== (int) $journal['currency_id'];
|
||||||
@@ -85,8 +90,18 @@ class TransactionSummarizer
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!$this->convertToNative) {
|
if (!$this->convertToNative) {
|
||||||
// default to the normal amount, but also
|
Log::debug(sprintf('Journal #%d also includes foreign amount (foreign is %s)', $journal['transaction_journal_id'], $journal['foreign_currency_code']));
|
||||||
|
// use foreign amount?
|
||||||
|
$foreignCurrencyId = (int) $journal['foreign_currency_id'];
|
||||||
|
if (0 !== $foreignCurrencyId) {
|
||||||
|
$foreignCurrencyName = $journal['foreign_currency_name'];
|
||||||
|
$foreignCurrencySymbol = $journal['foreign_currency_symbol'];
|
||||||
|
$foreignCurrencyCode = $journal['foreign_currency_code'];
|
||||||
|
$foreignCurrencyDecimalPlaces = $journal['foreign_currency_decimal_places'];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// first process normal amount
|
||||||
$amount = (string) ($journal[$field] ?? '0');
|
$amount = (string) ($journal[$field] ?? '0');
|
||||||
$array[$currencyId] ??= [
|
$array[$currencyId] ??= [
|
||||||
'sum' => '0',
|
'sum' => '0',
|
||||||
@@ -96,12 +111,34 @@ class TransactionSummarizer
|
|||||||
'currency_code' => $currencyCode,
|
'currency_code' => $currencyCode,
|
||||||
'currency_decimal_places' => $currencyDecimalPlaces,
|
'currency_decimal_places' => $currencyDecimalPlaces,
|
||||||
];
|
];
|
||||||
|
|
||||||
if ('positive' === $method) {
|
if ('positive' === $method) {
|
||||||
$array[$currencyId]['sum'] = bcadd($array[$currencyId]['sum'], app('steam')->positive($amount));
|
$array[$currencyId]['sum'] = bcadd($array[$currencyId]['sum'], app('steam')->positive($amount));
|
||||||
}
|
}
|
||||||
if ('negative' === $method) {
|
if ('negative' === $method) {
|
||||||
$array[$currencyId]['sum'] = bcadd($array[$currencyId]['sum'], app('steam')->negative($amount));
|
$array[$currencyId]['sum'] = bcadd($array[$currencyId]['sum'], app('steam')->negative($amount));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// then process foreign amount, if it exists.
|
||||||
|
if (0 !== $foreignCurrencyId) {
|
||||||
|
$amount = (string) ($journal['foreign_amount'] ?? '0');
|
||||||
|
$array[$foreignCurrencyId] ??= [
|
||||||
|
'sum' => '0',
|
||||||
|
'currency_id' => $foreignCurrencyId,
|
||||||
|
'currency_name' => $foreignCurrencyName,
|
||||||
|
'currency_symbol' => $foreignCurrencySymbol,
|
||||||
|
'currency_code' => $foreignCurrencyCode,
|
||||||
|
'currency_decimal_places' => $foreignCurrencyDecimalPlaces,
|
||||||
|
];
|
||||||
|
|
||||||
|
if ('positive' === $method) {
|
||||||
|
$array[$foreignCurrencyId]['sum'] = bcadd($array[$foreignCurrencyId]['sum'], app('steam')->positive($amount));
|
||||||
|
}
|
||||||
|
if ('negative' === $method) {
|
||||||
|
$array[$foreignCurrencyId]['sum'] = bcadd($array[$foreignCurrencyId]['sum'], app('steam')->negative($amount));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// $array[$currencyId]['sum'] = bcadd($array[$currencyId]['sum'], app('steam')->{$method}($amount));
|
// $array[$currencyId]['sum'] = bcadd($array[$currencyId]['sum'], app('steam')->{$method}($amount));
|
||||||
// Log::debug(sprintf('Journal #%d adds amount %s %s', $journal['transaction_journal_id'], $currencyCode, $amount));
|
// Log::debug(sprintf('Journal #%d adds amount %s %s', $journal['transaction_journal_id'], $currencyCode, $amount));
|
||||||
}
|
}
|
||||||
|
@@ -24,30 +24,48 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace FireflyIII\Support\Repositories\UserGroup;
|
namespace FireflyIII\Support\Repositories\UserGroup;
|
||||||
|
|
||||||
|
use FireflyIII\Enums\UserRoleEnum;
|
||||||
use FireflyIII\Exceptions\FireflyException;
|
use FireflyIII\Exceptions\FireflyException;
|
||||||
use FireflyIII\Models\GroupMembership;
|
use FireflyIII\Models\GroupMembership;
|
||||||
use FireflyIII\Models\UserGroup;
|
use FireflyIII\Models\UserGroup;
|
||||||
use FireflyIII\User;
|
use FireflyIII\User;
|
||||||
use Illuminate\Contracts\Auth\Authenticatable;
|
use Illuminate\Contracts\Auth\Authenticatable;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Trait UserGroupTrait
|
* Trait UserGroupTrait
|
||||||
*/
|
*/
|
||||||
trait UserGroupTrait
|
trait UserGroupTrait
|
||||||
{
|
{
|
||||||
protected User $user;
|
protected ?User $user = null;
|
||||||
protected UserGroup $userGroup;
|
protected ?UserGroup $userGroup = null;
|
||||||
|
|
||||||
public function getUserGroup(): UserGroup
|
public function getUserGroup(): UserGroup
|
||||||
{
|
{
|
||||||
return $this->userGroup;
|
return $this->userGroup;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function checkUserGroupAccess(UserRoleEnum $role): bool
|
||||||
|
{
|
||||||
|
$result = $this->user->hasRoleInGroupOrOwner($this->userGroup, $role);
|
||||||
|
if ($result) {
|
||||||
|
Log::debug(sprintf('User #%d has role %s in group #%d or is owner/full.', $this->user->id, $role->value, $this->userGroup->id));
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
Log::warning(sprintf('User #%d DOES NOT have role %s in group #%d.', $this->user->id, $role->value, $this->userGroup->id));
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TODO This method does not check if the user has access to this particular user group.
|
* TODO This method does not check if the user has access to this particular user group.
|
||||||
*/
|
*/
|
||||||
public function setUserGroup(UserGroup $userGroup): void
|
public function setUserGroup(UserGroup $userGroup): void
|
||||||
{
|
{
|
||||||
|
if (null === $this->user) {
|
||||||
|
Log::warning(sprintf('User is not set in repository %s', static::class));
|
||||||
|
}
|
||||||
$this->userGroup = $userGroup;
|
$this->userGroup = $userGroup;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -62,7 +80,11 @@ trait UserGroupTrait
|
|||||||
throw new FireflyException(sprintf('User #%d has no user group.', $user->id));
|
throw new FireflyException(sprintf('User #%d has no user group.', $user->id));
|
||||||
}
|
}
|
||||||
$this->userGroup = $user->userGroup;
|
$this->userGroup = $user->userGroup;
|
||||||
|
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
throw new FireflyException(sprintf('Object is of class %s, not User.', get_class($user)));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -70,7 +92,7 @@ trait UserGroupTrait
|
|||||||
*/
|
*/
|
||||||
public function setUserGroupById(int $userGroupId): void
|
public function setUserGroupById(int $userGroupId): void
|
||||||
{
|
{
|
||||||
$memberships = GroupMembership::where('user_id', $this->user->id)
|
$memberships = GroupMembership::where('user_id', $this->user->id)
|
||||||
->where('user_group_id', $userGroupId)
|
->where('user_group_id', $userGroupId)
|
||||||
->count()
|
->count()
|
||||||
;
|
;
|
||||||
@@ -79,10 +101,10 @@ trait UserGroupTrait
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** @var null|UserGroup $userGroup */
|
/** @var null|UserGroup $userGroup */
|
||||||
$userGroup = UserGroup::find($userGroupId);
|
$userGroup = UserGroup::find($userGroupId);
|
||||||
if (null === $userGroup) {
|
if (null === $userGroup) {
|
||||||
throw new FireflyException(sprintf('Cannot find administration for user #%d', $this->user->id));
|
throw new FireflyException(sprintf('Cannot find administration for user #%d', $this->user->id));
|
||||||
}
|
}
|
||||||
$this->userGroup = $userGroup;
|
$this->setUserGroup($userGroup);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -55,4 +55,36 @@ abstract class Node
|
|||||||
return $this->prohibited;
|
return $this->prohibited;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function equals(self $compare): bool
|
||||||
|
{
|
||||||
|
if ($compare->isProhibited(false) !== $this->isProhibited(false)) {
|
||||||
|
Log::debug('Return false because prohibited status is different');
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if ($compare instanceof NodeGroup && $this instanceof NodeGroup) {
|
||||||
|
if (count($compare->getNodes()) !== count($this->getNodes())) {
|
||||||
|
Log::debug(sprintf('Return false because node count is different. Original is %d, compare is %d', count($this->getNodes()), count($compare->getNodes())));
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var int $index
|
||||||
|
* @var Node $node
|
||||||
|
*/
|
||||||
|
foreach ($this->getNodes() as $index => $node) {
|
||||||
|
if (false === $node->equals($compare->getNodes()[$index])) {
|
||||||
|
Log::debug('Return false because nodes are different!');
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -71,6 +71,7 @@ class QueryParser implements QueryParserInterface
|
|||||||
|
|
||||||
while ($this->position < strlen($this->query)) {
|
while ($this->position < strlen($this->query)) {
|
||||||
$char = $this->query[$this->position];
|
$char = $this->query[$this->position];
|
||||||
|
// Log::debug(sprintf('Char #%d: %s', $this->position, $char));
|
||||||
|
|
||||||
// If we're in a quoted string, we treat all characters except another quote as ordinary characters
|
// If we're in a quoted string, we treat all characters except another quote as ordinary characters
|
||||||
if ($inQuotes) {
|
if ($inQuotes) {
|
||||||
@@ -150,15 +151,19 @@ class QueryParser implements QueryParserInterface
|
|||||||
|
|
||||||
|
|
||||||
case ':':
|
case ':':
|
||||||
if ('' !== $tokenUnderConstruction) {
|
$skipNext = false;
|
||||||
|
if ('' === $tokenUnderConstruction) {
|
||||||
|
// In any other location, it's just a normal character
|
||||||
|
$tokenUnderConstruction .= $char;
|
||||||
|
$skipNext = true;
|
||||||
|
}
|
||||||
|
if ('' !== $tokenUnderConstruction && !$skipNext) { // @phpstan-ignore-line
|
||||||
|
Log::debug(sprintf('Turns out that "%s" is a field name. Reset the token.', $tokenUnderConstruction));
|
||||||
// If we meet a colon with a left-hand side string, we know we're in a field and are about to set up the value
|
// If we meet a colon with a left-hand side string, we know we're in a field and are about to set up the value
|
||||||
$fieldName = $tokenUnderConstruction;
|
$fieldName = $tokenUnderConstruction;
|
||||||
$tokenUnderConstruction = '';
|
$tokenUnderConstruction = '';
|
||||||
}
|
}
|
||||||
if ('' === $tokenUnderConstruction) { // @phpstan-ignore-line
|
|
||||||
// In any other location, it's just a normal character
|
|
||||||
$tokenUnderConstruction .= $char;
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@@ -28,10 +28,11 @@ use FireflyIII\Exceptions\FireflyException;
|
|||||||
use FireflyIII\Models\Account;
|
use FireflyIII\Models\Account;
|
||||||
use FireflyIII\Models\Transaction;
|
use FireflyIII\Models\Transaction;
|
||||||
use FireflyIII\Models\TransactionCurrency;
|
use FireflyIII\Models\TransactionCurrency;
|
||||||
|
use FireflyIII\Support\Facades\Amount;
|
||||||
|
use FireflyIII\Support\Http\Api\ExchangeRateConverter;
|
||||||
use Illuminate\Support\Collection;
|
use Illuminate\Support\Collection;
|
||||||
use Illuminate\Support\Facades\DB;
|
use Illuminate\Support\Facades\DB;
|
||||||
use Illuminate\Support\Facades\Log;
|
use Illuminate\Support\Facades\Log;
|
||||||
use FireflyIII\Support\Facades\Amount;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class Steam.
|
* Class Steam.
|
||||||
@@ -58,8 +59,8 @@ class Steam
|
|||||||
public function finalAccountBalanceInRange(Account $account, Carbon $start, Carbon $end, bool $convertToNative): array
|
public function finalAccountBalanceInRange(Account $account, Carbon $start, Carbon $end, bool $convertToNative): array
|
||||||
{
|
{
|
||||||
// expand period.
|
// expand period.
|
||||||
$start->subDay()->startOfDay();
|
$start->startOfDay();
|
||||||
$end->addDay()->endOfDay();
|
$end->endOfDay();
|
||||||
Log::debug(sprintf('finalAccountBalanceInRange(#%d, %s, %s)', $account->id, $start->format('Y-m-d H:i:s'), $end->format('Y-m-d H:i:s')));
|
Log::debug(sprintf('finalAccountBalanceInRange(#%d, %s, %s)', $account->id, $start->format('Y-m-d H:i:s'), $end->format('Y-m-d H:i:s')));
|
||||||
|
|
||||||
// set up cache
|
// set up cache
|
||||||
@@ -67,6 +68,7 @@ class Steam
|
|||||||
$cache->addProperty($account->id);
|
$cache->addProperty($account->id);
|
||||||
$cache->addProperty('final-balance-in-range');
|
$cache->addProperty('final-balance-in-range');
|
||||||
$cache->addProperty($start);
|
$cache->addProperty($start);
|
||||||
|
$cache->addProperty($convertToNative);
|
||||||
$cache->addProperty($end);
|
$cache->addProperty($end);
|
||||||
if ($cache->has()) {
|
if ($cache->has()) {
|
||||||
return $cache->get();
|
return $cache->get();
|
||||||
@@ -74,101 +76,100 @@ class Steam
|
|||||||
|
|
||||||
$balances = [];
|
$balances = [];
|
||||||
$formatted = $start->format('Y-m-d');
|
$formatted = $start->format('Y-m-d');
|
||||||
$startBalance = $this->finalAccountBalance($account, $start);
|
/*
|
||||||
$defaultCurrency = app('amount')->getNativeCurrencyByUserGroup($account->user->userGroup);
|
* To make sure the start balance is correct, we need to get the balance at the exact end of the previous day.
|
||||||
|
* Since we just did "startOfDay" we can do subDay()->endOfDay() to get the correct moment.
|
||||||
|
* THAT will be the start balance.
|
||||||
|
*/
|
||||||
|
$request = clone $start;
|
||||||
|
$request->subDay()->endOfDay();
|
||||||
|
Log::debug(sprintf('finalAccountBalanceInRange: Call finalAccountBalance with date/time "%s"', $request->toIso8601String()));
|
||||||
|
$startBalance = $this->finalAccountBalance($account, $request);
|
||||||
|
$nativeCurrency = app('amount')->getNativeCurrencyByUserGroup($account->user->userGroup);
|
||||||
$accountCurrency = $this->getAccountCurrency($account);
|
$accountCurrency = $this->getAccountCurrency($account);
|
||||||
$hasCurrency = null !== $accountCurrency;
|
$hasCurrency = null !== $accountCurrency;
|
||||||
$currency = $accountCurrency ?? $defaultCurrency;
|
$currency = $accountCurrency ?? $nativeCurrency;
|
||||||
Log::debug(sprintf('Currency is %s', $currency->code));
|
Log::debug(sprintf('Currency is %s', $currency->code));
|
||||||
|
|
||||||
|
|
||||||
|
// set start balances:
|
||||||
|
$startBalance[$currency->code] ??= '0';
|
||||||
|
if ($hasCurrency) {
|
||||||
|
$startBalance[$accountCurrency->code] ??= '0';
|
||||||
|
}
|
||||||
if (!$hasCurrency) {
|
if (!$hasCurrency) {
|
||||||
Log::debug(sprintf('Also set start balance in %s', $defaultCurrency->code));
|
Log::debug(sprintf('Also set start balance in %s', $nativeCurrency->code));
|
||||||
$startBalance[$defaultCurrency->code] ??= '0';
|
$startBalance[$nativeCurrency->code] ??= '0';
|
||||||
}
|
}
|
||||||
$currencies = [
|
$currencies = [
|
||||||
$currency->id => $currency,
|
$currency->id => $currency,
|
||||||
$defaultCurrency->id => $defaultCurrency,
|
$nativeCurrency->id => $nativeCurrency,
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
||||||
$startBalance[$currency->code] ??= '0';
|
|
||||||
$balances[$formatted] = $startBalance;
|
$balances[$formatted] = $startBalance;
|
||||||
Log::debug('Final start balance: ', $startBalance);
|
Log::debug('Final start balance: ', $startBalance);
|
||||||
|
|
||||||
|
// sums up the balance changes per day.
|
||||||
// sums up the balance changes per day, for foreign, native and normal amounts.
|
Log::debug(sprintf('Date >= %s and <= %s', $start->format('Y-m-d H:i:s'), $end->format('Y-m-d H:i:s')));
|
||||||
$set = $account->transactions()
|
$set = $account->transactions()
|
||||||
->leftJoin('transaction_journals', 'transactions.transaction_journal_id', '=', 'transaction_journals.id')
|
->leftJoin('transaction_journals', 'transactions.transaction_journal_id', '=', 'transaction_journals.id')
|
||||||
->where('transaction_journals.date', '>=', $start->format('Y-m-d H:i:s'))
|
->where('transaction_journals.date', '>=', $start->format('Y-m-d H:i:s'))
|
||||||
->where('transaction_journals.date', '<=', $end->format('Y-m-d H:i:s'))
|
->where('transaction_journals.date', '<=', $end->format('Y-m-d H:i:s'))
|
||||||
->groupBy('transaction_journals.date')
|
->groupBy('transaction_journals.date')
|
||||||
->groupBy('transactions.transaction_currency_id')
|
->groupBy('transactions.transaction_currency_id')
|
||||||
->groupBy('transactions.foreign_currency_id')
|
|
||||||
->orderBy('transaction_journals.date', 'ASC')
|
->orderBy('transaction_journals.date', 'ASC')
|
||||||
->whereNull('transaction_journals.deleted_at')
|
->whereNull('transaction_journals.deleted_at')
|
||||||
->get(
|
->get(
|
||||||
[ // @phpstan-ignore-line
|
[ // @phpstan-ignore-line
|
||||||
'transaction_journals.date',
|
'transaction_journals.date',
|
||||||
'transactions.transaction_currency_id',
|
'transactions.transaction_currency_id',
|
||||||
DB::raw('SUM(transactions.amount) AS modified'),
|
DB::raw('SUM(transactions.amount) AS sum_of_day'),
|
||||||
'transactions.foreign_currency_id',
|
|
||||||
DB::raw('SUM(transactions.foreign_amount) AS modified_foreign'),
|
|
||||||
DB::raw('SUM(transactions.native_amount) AS modified_native'),
|
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
;
|
;
|
||||||
|
|
||||||
$currentBalance = $startBalance;
|
$currentBalance = $startBalance;
|
||||||
|
$converter = new ExchangeRateConverter();
|
||||||
|
|
||||||
|
|
||||||
/** @var Transaction $entry */
|
/** @var Transaction $entry */
|
||||||
foreach ($set as $entry) {
|
foreach ($set as $entry) {
|
||||||
// normal, native and foreign amount
|
// get date object
|
||||||
$carbon = new Carbon($entry->date, $entry->date_tz);
|
$carbon = new Carbon($entry->date, $entry->date_tz);
|
||||||
$modified = (string) (null === $entry->modified ? '0' : $entry->modified);
|
$carbonKey = $carbon->format('Y-m-d');
|
||||||
$foreignModified = (string) (null === $entry->modified_foreign ? '0' : $entry->modified_foreign);
|
// make sure sum is a string:
|
||||||
$nativeModified = (string) (null === $entry->modified_native ? '0' : $entry->modified_native);
|
$sumOfDay = (string) (null === $entry->sum_of_day ? '0' : $entry->sum_of_day);
|
||||||
|
|
||||||
// find currency of this entry.
|
// find currency of this entry, does not have to exist.
|
||||||
$currencies[$entry->transaction_currency_id] ??= TransactionCurrency::find($entry->transaction_currency_id);
|
$currencies[$entry->transaction_currency_id] ??= TransactionCurrency::find($entry->transaction_currency_id);
|
||||||
|
|
||||||
|
// make sure this $entry has its own $entryCurrency
|
||||||
/** @var TransactionCurrency $entryCurrency */
|
/** @var TransactionCurrency $entryCurrency */
|
||||||
$entryCurrency = $currencies[$entry->transaction_currency_id];
|
$entryCurrency = $currencies[$entry->transaction_currency_id];
|
||||||
|
|
||||||
Log::debug(sprintf('Processing transaction(s) on date %s', $carbon->format('Y-m-d H:i:s')));
|
Log::debug(sprintf('Processing transaction(s) on moment %s', $carbon->format('Y-m-d H:i:s')));
|
||||||
|
|
||||||
// if convert to native, if NOT convert to native.
|
// add amount to current balance in currency code.
|
||||||
if ($convertToNative) {
|
$currentBalance[$entryCurrency->code] ??= '0';
|
||||||
Log::debug(sprintf('Amount is %s %s, foreign amount is %s, native amount is %s', $entryCurrency->code, $this->bcround($modified, 2), $this->bcround($foreignModified, 2), $this->bcround($nativeModified, 2)));
|
$currentBalance[$entryCurrency->code] = bcadd($sumOfDay, $currentBalance[$entryCurrency->code]);
|
||||||
// if the currency is the default currency add to native balance + currency balance
|
|
||||||
if ($entry->transaction_currency_id === $defaultCurrency->id) {
|
|
||||||
Log::debug('Add amount to native.');
|
|
||||||
$currentBalance['native_balance'] = bcadd($currentBalance['native_balance'], $modified);
|
|
||||||
}
|
|
||||||
|
|
||||||
// add to native balance.
|
// if not convert to native, add the amount to "balance", do nothing else.
|
||||||
if ($entry->foreign_currency_id !== $defaultCurrency->id) {
|
|
||||||
// this check is not necessary, because if the foreign currency is the same as the default currency, the native amount is zero.
|
|
||||||
// so adding this would mean nothing.
|
|
||||||
$currentBalance['native_balance'] = bcadd($currentBalance['native_balance'], $nativeModified);
|
|
||||||
}
|
|
||||||
if ($entry->foreign_currency_id === $defaultCurrency->id) {
|
|
||||||
$currentBalance['native_balance'] = bcadd($currentBalance['native_balance'], $foreignModified);
|
|
||||||
}
|
|
||||||
// add to balance if is the same.
|
|
||||||
if ($entry->transaction_currency_id === $accountCurrency?->id) {
|
|
||||||
$currentBalance['balance'] = bcadd($currentBalance['balance'], $modified);
|
|
||||||
}
|
|
||||||
// add currency balance
|
|
||||||
$currentBalance[$entryCurrency->code] = bcadd($currentBalance[$entryCurrency->code] ?? '0', $modified);
|
|
||||||
}
|
|
||||||
if (!$convertToNative) {
|
if (!$convertToNative) {
|
||||||
Log::debug(sprintf('Amount is %s %s, foreign amount is %s, native amount is %s', $entryCurrency->code, $modified, $foreignModified, $nativeModified));
|
$currentBalance['balance'] = bcadd($currentBalance['balance'], $sumOfDay);
|
||||||
// add to balance, as expected.
|
|
||||||
$currentBalance['balance'] = bcadd($currentBalance['balance'] ?? '0', $modified);
|
|
||||||
// add to GBP, as expected.
|
|
||||||
$currentBalance[$entryCurrency->code] = bcadd($currentBalance[$entryCurrency->code] ?? '0', $modified);
|
|
||||||
}
|
}
|
||||||
$balances[$carbon->format('Y-m-d')] = $currentBalance;
|
// if convert to native add the converted amount to "native_balance".
|
||||||
Log::debug('Updated entry', $currentBalance);
|
// if there is a request to convert, convert to "native_balance" and use "balance" for whichever amount is in the native currency.
|
||||||
|
if ($convertToNative) {
|
||||||
|
$nativeSumOfDay = $converter->convert($entryCurrency, $nativeCurrency, $carbon, $sumOfDay);
|
||||||
|
$currentBalance['native_balance'] = bcadd($currentBalance['native_balance'], $nativeSumOfDay);
|
||||||
|
if ($currency->id === $entryCurrency->id) {
|
||||||
|
$currentBalance['balance'] = bcadd($currentBalance['balance'], $sumOfDay);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
// just set it.
|
||||||
|
$balances[$carbonKey] = $currentBalance;
|
||||||
|
Log::debug(sprintf('Updated entry [%s]', $carbonKey), $currentBalance);
|
||||||
}
|
}
|
||||||
$cache->store($balances);
|
$cache->store($balances);
|
||||||
Log::debug('End of method');
|
Log::debug('End of method');
|
||||||
@@ -178,6 +179,7 @@ class Steam
|
|||||||
|
|
||||||
public function finalAccountsBalance(Collection $accounts, Carbon $date): array
|
public function finalAccountsBalance(Collection $accounts, Carbon $date): array
|
||||||
{
|
{
|
||||||
|
Log::debug(sprintf('finalAccountsBalance: Call finalAccountBalance with date/time "%s"', $date->toIso8601String()));
|
||||||
$balances = [];
|
$balances = [];
|
||||||
foreach ($accounts as $account) {
|
foreach ($accounts as $account) {
|
||||||
$balances[$account->id] = $this->finalAccountBalance($account, $date);
|
$balances[$account->id] = $this->finalAccountBalance($account, $date);
|
||||||
@@ -274,117 +276,80 @@ class Steam
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Returns smaller than or equal to, so be careful with END OF DAY.
|
||||||
|
*
|
||||||
* Returns the balance of an account at exact moment given. Array with at least one value.
|
* Returns the balance of an account at exact moment given. Array with at least one value.
|
||||||
|
* Always returns:
|
||||||
|
* "balance": balance in the account's currency OR user's native currency if the account has no currency
|
||||||
|
* "EUR": balance in EUR (or whatever currencies the account has balance in)
|
||||||
*
|
*
|
||||||
* "balance" the balance in whatever currency the account has, so the sum of all transaction that happen to have
|
* If the user has $convertToNative:
|
||||||
* THAT currency.
|
* "balance": balance in the account's currency OR user's native currency if the account has no currency
|
||||||
* "native_balance" the balance according to the "native_amount" + "native_foreign_amount" fields.
|
* --> "native_balance": balance in the user's native balance, with all amounts converted to native.
|
||||||
* "ABC" the balance in this particular currency code (may repeat for each found currency).
|
* "EUR": balance in EUR (or whatever currencies the account has balance in)
|
||||||
*
|
|
||||||
* Het maakt niet uit of de native currency wel of niet gelijk is aan de account currency.
|
|
||||||
* Optelsom zou hetzelfde moeten zijn. Als het EUR is en de rekening ook is native_amount 0.
|
|
||||||
* Zo niet is amount 0 en native_amount het bedrag.
|
|
||||||
*
|
|
||||||
* Eerst een som van alle transacties in de native currency. Alle EUR bij elkaar opgeteld.
|
|
||||||
* Om te weten wat er nog meer op de rekening gebeurt, pak alles waar currency niet EUR is, en de foreign ook niet,
|
|
||||||
* en tel native_amount erbij op.
|
|
||||||
* Daarna pak je alle transacties waar currency niet EUR is, en de foreign wel, en tel foreign_amount erbij op.
|
|
||||||
*
|
|
||||||
* Wil je niks weten van native currencies, pak je:
|
|
||||||
*
|
|
||||||
* Eerst een som van alle transacties gegroepeerd op currency. Einde.
|
|
||||||
*/
|
*/
|
||||||
public function finalAccountBalance(Account $account, Carbon $date): array
|
public function finalAccountBalance(Account $account, Carbon $date): array
|
||||||
{
|
{
|
||||||
$cache = new CacheProperties();
|
|
||||||
|
$cache = new CacheProperties();
|
||||||
$cache->addProperty($account->id);
|
$cache->addProperty($account->id);
|
||||||
$cache->addProperty($date);
|
$cache->addProperty($date);
|
||||||
if ($cache->has()) {
|
if ($cache->has()) {
|
||||||
|
// Log::debug(sprintf('CACHED finalAccountBalance(#%d, %s)', $account->id, $date->format('Y-m-d H:i:s')));
|
||||||
return $cache->get();
|
return $cache->get();
|
||||||
}
|
}
|
||||||
|
Log::debug(sprintf('finalAccountBalance(#%d, %s)', $account->id, $date->format('Y-m-d H:i:s')));
|
||||||
|
|
||||||
Log::debug(sprintf('Now in finalAccountBalance(#%d, "%s", "%s")', $account->id, $account->name, $date->format('Y-m-d H:i:s')));
|
$native = Amount::getNativeCurrencyByUserGroup($account->user->userGroup);
|
||||||
|
$convertToNative = Amount::convertToNative($account->user);
|
||||||
$native = Amount::getNativeCurrencyByUserGroup($account->user->userGroup);
|
$accountCurrency = $this->getAccountCurrency($account);
|
||||||
$convertToNative = Amount::convertToNative($account->user);
|
$hasCurrency = null !== $accountCurrency;
|
||||||
$accountCurrency = $this->getAccountCurrency($account);
|
$currency = $hasCurrency ? $accountCurrency : $native;
|
||||||
$hasCurrency = null !== $accountCurrency;
|
$return = [
|
||||||
$currency = $hasCurrency ? $accountCurrency : $native;
|
'native_balance' => '0',
|
||||||
$return = [];
|
'balance' => '0', // this key is overwritten right away, but I must remember it is always created.
|
||||||
|
];
|
||||||
// first, the "balance", as described earlier.
|
// balance(s) in all currencies.
|
||||||
if ($convertToNative) {
|
$array = $account->transactions()
|
||||||
// normal balance
|
|
||||||
$return['balance'] = (string) $account->transactions()
|
|
||||||
->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id')
|
|
||||||
->where('transaction_journals.date', '<=', $date->format('Y-m-d H:i:s'))
|
|
||||||
->where('transactions.transaction_currency_id', $native->id)
|
|
||||||
->sum('transactions.amount')
|
|
||||||
;
|
|
||||||
// plus virtual balance, if the account has a virtual_balance in the native currency
|
|
||||||
if ($native->id === $accountCurrency?->id) {
|
|
||||||
$return['balance'] = bcadd('' === (string) $account->virtual_balance ? '0' : $account->virtual_balance, $return['balance']);
|
|
||||||
}
|
|
||||||
// Log::debug(sprintf('balance is (%s only) %s (with virtual balance)', $native->code, $this->bcround($return['balance'], 2)));
|
|
||||||
|
|
||||||
// native balance
|
|
||||||
$return['native_balance'] = (string) $account->transactions()
|
|
||||||
->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id')
|
|
||||||
->where('transaction_journals.date', '<=', $date->format('Y-m-d H:i:s'))
|
|
||||||
->whereNot('transactions.transaction_currency_id', $native->id)
|
|
||||||
->sum('transactions.native_amount')
|
|
||||||
;
|
|
||||||
// plus native virtual balance.
|
|
||||||
$return['native_balance'] = bcadd('' === (string) $account->native_virtual_balance ? '0' : $account->native_virtual_balance, $return['native_balance']);
|
|
||||||
// Log::debug(sprintf('native_balance is (all transactions to %s) %s (with virtual balance)', $native->code, $this->bcround($return['native_balance'])));
|
|
||||||
|
|
||||||
// plus foreign transactions in THIS currency.
|
|
||||||
$sum = (string) $account->transactions()
|
|
||||||
->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id')
|
|
||||||
->where('transaction_journals.date', '<=', $date->format('Y-m-d H:i:s'))
|
|
||||||
->whereNot('transactions.transaction_currency_id', $native->id)
|
|
||||||
->where('transactions.foreign_currency_id', $native->id)
|
|
||||||
->sum('transactions.foreign_amount')
|
|
||||||
;
|
|
||||||
$return['native_balance'] = bcadd($return['native_balance'], $sum);
|
|
||||||
|
|
||||||
// Log::debug(sprintf('Foreign amount transactions add (%s only) %s, total native_balance is now %s', $native->code, $this->bcround($sum), $this->bcround($return['native_balance'])));
|
|
||||||
}
|
|
||||||
|
|
||||||
// balance(s) in other (all) currencies.
|
|
||||||
$array = $account->transactions()
|
|
||||||
->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id')
|
->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id')
|
||||||
->leftJoin('transaction_currencies', 'transaction_currencies.id', '=', 'transactions.transaction_currency_id')
|
->leftJoin('transaction_currencies', 'transaction_currencies.id', '=', 'transactions.transaction_currency_id')
|
||||||
->where('transaction_journals.date', '<=', $date->format('Y-m-d H:i:s'))
|
->where('transaction_journals.date', '<=', $date->format('Y-m-d H:i:s'))
|
||||||
->get(['transaction_currencies.code', 'transactions.amount'])->toArray()
|
->get(['transaction_currencies.code', 'transactions.amount'])->toArray()
|
||||||
;
|
;
|
||||||
$others = $this->groupAndSumTransactions($array, 'code', 'amount');
|
$others = $this->groupAndSumTransactions($array, 'code', 'amount');
|
||||||
// Log::debug('All balances are (joined)', $others);
|
// Log::debug('All balances are (joined)', $others);
|
||||||
// if the account has no own currency preference, drop balance in favor of native balance
|
// if there is no request to convert, take this as "balance" and "native_balance".
|
||||||
if ($hasCurrency && !$convertToNative) {
|
$return['balance'] = $others[$currency->code] ?? '0';
|
||||||
$return['balance'] = $others[$currency->code] ?? '0';
|
if (!$convertToNative) {
|
||||||
$return['native_balance'] = $others[$currency->code] ?? '0';
|
unset($return['native_balance']);
|
||||||
// Log::debug(sprintf('Set balance + native_balance to %s', $return['balance']));
|
// Log::debug(sprintf('Set balance to %s, unset native_balance', $return['balance']));
|
||||||
|
}
|
||||||
|
// if there is a request to convert, convert to "native_balance" and use "balance" for whichever amount is in the native currency.
|
||||||
|
if ($convertToNative) {
|
||||||
|
$return['native_balance'] = $this->convertAllBalances($others, $native, $date); // todo sum all and convert.
|
||||||
|
// Log::debug(sprintf('Set native_balance to %s', $return['native_balance']));
|
||||||
}
|
}
|
||||||
|
|
||||||
// if the currency is the same as the native currency, set the native_balance to the balance for consistency.
|
// either way, the balance is always combined with the virtual balance:
|
||||||
// if($currency->id === $native->id) {
|
$virtualBalance = (string) ('' === (string) $account->virtual_balance ? '0' : $account->virtual_balance);
|
||||||
// $return['native_balance'] = $return['balance'];
|
|
||||||
// }
|
|
||||||
|
|
||||||
if (!$hasCurrency && array_key_exists('balance', $return)) {
|
if ($convertToNative) {
|
||||||
// Log::debug('Account has no currency preference, dropping balance in favor of native balance.');
|
// the native balance is combined with a converted virtual_balance:
|
||||||
$sum = bcadd($return['balance'], $return['native_balance']);
|
$converter = new ExchangeRateConverter();
|
||||||
// Log::debug(sprintf('%s + %s = %s', $return['balance'], $return['native_balance'], $sum));
|
$nativeVirtualBalance = $converter->convert($currency, $native, $date, $virtualBalance);
|
||||||
$return['native_balance'] = $sum;
|
$return['native_balance'] = bcadd($nativeVirtualBalance, $return['native_balance']);
|
||||||
unset($return['balance']);
|
// Log::debug(sprintf('Native virtual balance makes the native total %s', $return['native_balance']));
|
||||||
}
|
}
|
||||||
$final = array_merge($return, $others);
|
if (!$convertToNative) {
|
||||||
// Log::debug('Return is', $final);
|
// if not, also increase the balance + native balance for consistency.
|
||||||
|
$return['balance'] = bcadd($return['balance'], $virtualBalance);
|
||||||
|
// Log::debug(sprintf('Virtual balance makes the (native) total %s', $return['balance']));
|
||||||
|
}
|
||||||
|
$final = array_merge($return, $others);
|
||||||
|
Log::debug('Final balance is', $final);
|
||||||
$cache->store($final);
|
$cache->store($final);
|
||||||
|
|
||||||
return array_merge($return, $others);
|
return $final;
|
||||||
// Log::debug('Return is', $final);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function filterAccountBalances(array $total, Account $account, bool $convertToNative, ?TransactionCurrency $currency = null): array
|
public function filterAccountBalances(array $total, Account $account, bool $convertToNative, ?TransactionCurrency $currency = null): array
|
||||||
@@ -410,17 +375,18 @@ class Steam
|
|||||||
$defaultCurrency = app('amount')->getNativeCurrency();
|
$defaultCurrency = app('amount')->getNativeCurrency();
|
||||||
if ($convertToNative) {
|
if ($convertToNative) {
|
||||||
if ($defaultCurrency->id === $currency?->id) {
|
if ($defaultCurrency->id === $currency?->id) {
|
||||||
Log::debug(sprintf('Unset "native_balance" and "%s" for account #%d', $defaultCurrency->code, $account->id));
|
Log::debug(sprintf('Unset [%s] for account #%d (no longer unset "native_balance")', $defaultCurrency->code, $account->id));
|
||||||
unset($set['native_balance'], $set[$defaultCurrency->code]);
|
unset($set[$defaultCurrency->code]);
|
||||||
}
|
}
|
||||||
|
// todo rethink this logic.
|
||||||
if (null !== $currency && $defaultCurrency->id !== $currency->id) {
|
if (null !== $currency && $defaultCurrency->id !== $currency->id) {
|
||||||
Log::debug(sprintf('Unset balance for account #%d', $account->id));
|
Log::debug(sprintf('Unset balance for account #%d', $account->id));
|
||||||
unset($set['balance']);
|
unset($set['balance']);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (null === $currency) {
|
if (null === $currency) {
|
||||||
Log::debug(sprintf('TEMP DO NOT Drop defaultCurrency balance for account #%d', $account->id));
|
Log::debug(sprintf('Unset balance for account #%d', $account->id));
|
||||||
// unset($set[$this->defaultCurrency->code]);
|
unset($set['balance']);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -428,16 +394,15 @@ class Steam
|
|||||||
if (null === $currency) {
|
if (null === $currency) {
|
||||||
Log::debug(sprintf('Unset native_balance and make defaultCurrency balance the balance for account #%d', $account->id));
|
Log::debug(sprintf('Unset native_balance and make defaultCurrency balance the balance for account #%d', $account->id));
|
||||||
$set['balance'] = $set[$defaultCurrency->code] ?? '0';
|
$set['balance'] = $set[$defaultCurrency->code] ?? '0';
|
||||||
unset($set['native_balance'], $set[$defaultCurrency->code]);
|
unset($set[$defaultCurrency->code]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (null !== $currency) {
|
if (null !== $currency) {
|
||||||
Log::debug(sprintf('Unset native_balance + defaultCurrency + currencyCode balance for account #%d', $account->id));
|
Log::debug(sprintf('Unset [%s] + [%s] balance for account #%d', $defaultCurrency->code, $currency->code, $account->id));
|
||||||
unset($set['native_balance'], $set[$defaultCurrency->code], $set[$currency->code]);
|
unset($set[$defaultCurrency->code], $set[$currency->code]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// put specific value first in array.
|
// put specific value first in array.
|
||||||
if (array_key_exists('native_balance', $set)) {
|
if (array_key_exists('native_balance', $set)) {
|
||||||
$set = ['native_balance' => $set['native_balance']] + $set;
|
$set = ['native_balance' => $set['native_balance']] + $set;
|
||||||
@@ -687,4 +652,21 @@ class Steam
|
|||||||
|
|
||||||
return $amount;
|
return $amount;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function convertAllBalances(array $others, TransactionCurrency $native, Carbon $date): string
|
||||||
|
{
|
||||||
|
$total = '0';
|
||||||
|
$converter = new ExchangeRateConverter();
|
||||||
|
foreach ($others as $key => $amount) {
|
||||||
|
$currency = TransactionCurrency::where('code', $key)->first();
|
||||||
|
if (null === $currency) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$current = $converter->convert($currency, $native, $date, $amount);
|
||||||
|
Log::debug(sprintf('Convert %s %s to %s %s', $currency->code, $amount, $native->code, $current));
|
||||||
|
$total = bcadd($current, $total);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $total;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -26,6 +26,8 @@ namespace FireflyIII\Support\Twig;
|
|||||||
use FireflyIII\Models\Account as AccountModel;
|
use FireflyIII\Models\Account as AccountModel;
|
||||||
use FireflyIII\Models\TransactionCurrency;
|
use FireflyIII\Models\TransactionCurrency;
|
||||||
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
|
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
|
||||||
|
use FireflyIII\Support\Facades\Amount;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
use Twig\Extension\AbstractExtension;
|
use Twig\Extension\AbstractExtension;
|
||||||
use Twig\TwigFilter;
|
use Twig\TwigFilter;
|
||||||
use Twig\TwigFunction;
|
use Twig\TwigFunction;
|
||||||
@@ -112,8 +114,13 @@ class AmountFormat extends AbstractExtension
|
|||||||
static function (string $amount, string $code, ?bool $coloured = null): string {
|
static function (string $amount, string $code, ?bool $coloured = null): string {
|
||||||
$coloured ??= true;
|
$coloured ??= true;
|
||||||
|
|
||||||
/** @var TransactionCurrency $currency */
|
/** @var null|TransactionCurrency $currency */
|
||||||
$currency = TransactionCurrency::whereCode($code)->first();
|
$currency = TransactionCurrency::whereCode($code)->first();
|
||||||
|
if (null === $currency) {
|
||||||
|
Log::error(sprintf('Could not find currency with code "%s". Fallback to native currency.', $code));
|
||||||
|
$currency = Amount::getNativeCurrency();
|
||||||
|
Log::error(sprintf('Fallback currency is "%s".', $currency->code));
|
||||||
|
}
|
||||||
|
|
||||||
return app('amount')->formatAnything($currency, $amount, $coloured);
|
return app('amount')->formatAnything($currency, $amount, $coloured);
|
||||||
},
|
},
|
||||||
|
@@ -31,6 +31,7 @@ use FireflyIII\Repositories\User\UserRepositoryInterface;
|
|||||||
use FireflyIII\Support\Facades\Amount;
|
use FireflyIII\Support\Facades\Amount;
|
||||||
use FireflyIII\Support\Facades\Steam;
|
use FireflyIII\Support\Facades\Steam;
|
||||||
use FireflyIII\Support\Search\OperatorQuerySearch;
|
use FireflyIII\Support\Search\OperatorQuerySearch;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
use League\CommonMark\GithubFlavoredMarkdownConverter;
|
use League\CommonMark\GithubFlavoredMarkdownConverter;
|
||||||
use Route;
|
use Route;
|
||||||
use Twig\Extension\AbstractExtension;
|
use Twig\Extension\AbstractExtension;
|
||||||
@@ -67,11 +68,13 @@ class General extends AbstractExtension
|
|||||||
|
|
||||||
/** @var Carbon $date */
|
/** @var Carbon $date */
|
||||||
$date = session('end', today(config('app.timezone'))->endOfMonth());
|
$date = session('end', today(config('app.timezone'))->endOfMonth());
|
||||||
|
Log::debug(sprintf('twig balance: Call finalAccountBalance with date/time "%s"', $date->toIso8601String()));
|
||||||
$info = Steam::finalAccountBalance($account, $date);
|
$info = Steam::finalAccountBalance($account, $date);
|
||||||
$currency = Steam::getAccountCurrency($account);
|
$currency = Steam::getAccountCurrency($account);
|
||||||
$default = Amount::getNativeCurrency();
|
$default = Amount::getNativeCurrency();
|
||||||
$convertToNative = Amount::convertToNative();
|
$convertToNative = Amount::convertToNative();
|
||||||
$useNative = $convertToNative && $default->id !== $currency->id;
|
$useNative = $convertToNative && $default->id !== $currency->id;
|
||||||
|
$currency = null === $currency ? $default : $currency;
|
||||||
$strings = [];
|
$strings = [];
|
||||||
foreach ($info as $key => $balance) {
|
foreach ($info as $key => $balance) {
|
||||||
if ('balance' === $key) {
|
if ('balance' === $key) {
|
||||||
|
@@ -31,6 +31,7 @@ use FireflyIII\Models\TransactionCurrency;
|
|||||||
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
|
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
|
||||||
use FireflyIII\Support\Facades\Amount;
|
use FireflyIII\Support\Facades\Amount;
|
||||||
use FireflyIII\Support\Facades\Steam;
|
use FireflyIII\Support\Facades\Steam;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
use Symfony\Component\HttpFoundation\ParameterBag;
|
use Symfony\Component\HttpFoundation\ParameterBag;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -106,6 +107,7 @@ class AccountTransformer extends AbstractTransformer
|
|||||||
$order = null;
|
$order = null;
|
||||||
}
|
}
|
||||||
// balance, native balance, virtual balance, native virtual balance?
|
// balance, native balance, virtual balance, native virtual balance?
|
||||||
|
Log::debug(sprintf('transform: Call finalAccountBalance with date/time "%s"', $date->toIso8601String()));
|
||||||
$finalBalance = Steam::finalAccountBalance($account, $date);
|
$finalBalance = Steam::finalAccountBalance($account, $date);
|
||||||
if ($convertToNative) {
|
if ($convertToNative) {
|
||||||
$finalBalance['balance'] = $finalBalance[$currencyCode] ?? '0';
|
$finalBalance['balance'] = $finalBalance[$currencyCode] ?? '0';
|
||||||
|
@@ -54,7 +54,7 @@ class PiggyBankEventTransformer extends AbstractTransformer
|
|||||||
public function transform(PiggyBankEvent $event): array
|
public function transform(PiggyBankEvent $event): array
|
||||||
{
|
{
|
||||||
// get account linked to piggy bank
|
// get account linked to piggy bank
|
||||||
$account = $event->piggyBank->account;
|
$account = $event->piggyBank->accounts()->first();
|
||||||
|
|
||||||
// set up repositories.
|
// set up repositories.
|
||||||
$this->repository->setUser($account->user);
|
$this->repository->setUser($account->user);
|
||||||
|
@@ -99,10 +99,8 @@ class PiggyBankTransformer extends AbstractTransformer
|
|||||||
'id' => (string) $piggyBank->id,
|
'id' => (string) $piggyBank->id,
|
||||||
'created_at' => $piggyBank->created_at->toAtomString(),
|
'created_at' => $piggyBank->created_at->toAtomString(),
|
||||||
'updated_at' => $piggyBank->updated_at->toAtomString(),
|
'updated_at' => $piggyBank->updated_at->toAtomString(),
|
||||||
'accounts' => $this->renderAccounts($piggyBank),
|
|
||||||
// 'account_id' => (string)$piggyBank->account_id,
|
|
||||||
// 'account_name' => $piggyBank->account->name,
|
|
||||||
'name' => $piggyBank->name,
|
'name' => $piggyBank->name,
|
||||||
|
'accounts' => $this->renderAccounts($piggyBank),
|
||||||
'currency_id' => (string) $currency->id,
|
'currency_id' => (string) $currency->id,
|
||||||
'currency_code' => $currency->code,
|
'currency_code' => $currency->code,
|
||||||
'currency_symbol' => $currency->symbol,
|
'currency_symbol' => $currency->symbol,
|
||||||
@@ -134,9 +132,10 @@ class PiggyBankTransformer extends AbstractTransformer
|
|||||||
$return = [];
|
$return = [];
|
||||||
foreach ($piggyBank->accounts()->get() as $account) {
|
foreach ($piggyBank->accounts()->get() as $account) {
|
||||||
$return[] = [
|
$return[] = [
|
||||||
'id' => $account->id,
|
'id' => (string) $account->id,
|
||||||
'name' => $account->name,
|
'name' => $account->name,
|
||||||
'current_amount' => (string) $account->pivot->current_amount,
|
'current_amount' => (string) $account->pivot->current_amount,
|
||||||
|
'native_current_amount' => (string) $account->pivot->native_current_amount,
|
||||||
// TODO add balance, add left to save.
|
// TODO add balance, add left to save.
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
@@ -183,6 +183,8 @@ class AccountTransformer extends AbstractTransformer
|
|||||||
$bEnd = [];
|
$bEnd = [];
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
Log::debug(sprintf('v2 transformer: finalAccountsBalance("%s")', $start->format('Y-m-d H:i:s')));
|
||||||
|
Log::debug(sprintf('v2 transformer: finalAccountsBalance("%s")', $end->format('Y-m-d H:i:s')));
|
||||||
$bStart = app('steam')->finalAccountsBalance($accounts, $start);
|
$bStart = app('steam')->finalAccountsBalance($accounts, $start);
|
||||||
$bEnd = app('steam')->finalAccountsBalance($accounts, $end);
|
$bEnd = app('steam')->finalAccountsBalance($accounts, $end);
|
||||||
} catch (FireflyException $e) {
|
} catch (FireflyException $e) {
|
||||||
|
@@ -35,6 +35,7 @@ use FireflyIII\Models\UserGroup;
|
|||||||
use FireflyIII\Repositories\Account\AccountRepository;
|
use FireflyIII\Repositories\Account\AccountRepository;
|
||||||
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
|
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
|
||||||
use FireflyIII\User;
|
use FireflyIII\User;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
use Illuminate\Validation\Validator;
|
use Illuminate\Validation\Validator;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -52,12 +53,12 @@ trait TransactionValidation
|
|||||||
if ($validator->errors()->count() > 0) {
|
if ($validator->errors()->count() > 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
app('log')->debug('Now in validateAccountInformation (TransactionValidation) ()');
|
Log::debug('Now in validateAccountInformation (TransactionValidation) ()');
|
||||||
$transactions = $this->getTransactionsArray($validator);
|
$transactions = $this->getTransactionsArray($validator);
|
||||||
$data = $validator->getData();
|
$data = $validator->getData();
|
||||||
$transactionType = $data['type'] ?? 'invalid';
|
$transactionType = $data['type'] ?? 'invalid';
|
||||||
|
|
||||||
app('log')->debug(sprintf('Going to loop %d transaction(s)', count($transactions)));
|
Log::debug(sprintf('Going to loop %d transaction(s)', count($transactions)));
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var int|string $index
|
* @var int|string $index
|
||||||
@@ -75,15 +76,15 @@ trait TransactionValidation
|
|||||||
|
|
||||||
protected function getTransactionsArray(Validator $validator): array
|
protected function getTransactionsArray(Validator $validator): array
|
||||||
{
|
{
|
||||||
app('log')->debug('Now in getTransactionsArray');
|
Log::debug('Now in getTransactionsArray');
|
||||||
$data = $validator->getData();
|
$data = $validator->getData();
|
||||||
$transactions = [];
|
$transactions = [];
|
||||||
if (array_key_exists('transactions', $data) && is_array($data['transactions'])) {
|
if (array_key_exists('transactions', $data) && is_array($data['transactions'])) {
|
||||||
app('log')->debug('Transactions key exists and is array.');
|
Log::debug('Transactions key exists and is array.');
|
||||||
$transactions = $data['transactions'];
|
$transactions = $data['transactions'];
|
||||||
}
|
}
|
||||||
if (array_key_exists('transactions', $data) && !is_array($data['transactions'])) {
|
if (array_key_exists('transactions', $data) && !is_array($data['transactions'])) {
|
||||||
app('log')->debug(sprintf('Transactions key exists but is NOT array, its a %s', gettype($data['transactions'])));
|
Log::debug(sprintf('Transactions key exists but is NOT array, its a %s', gettype($data['transactions'])));
|
||||||
}
|
}
|
||||||
|
|
||||||
return $transactions;
|
return $transactions;
|
||||||
@@ -94,7 +95,7 @@ trait TransactionValidation
|
|||||||
*/
|
*/
|
||||||
protected function validateSingleAccount(Validator $validator, int $index, string $transactionType, array $transaction): void
|
protected function validateSingleAccount(Validator $validator, int $index, string $transactionType, array $transaction): void
|
||||||
{
|
{
|
||||||
app('log')->debug(sprintf('Now in validateSingleAccount(%d)', $index));
|
Log::debug(sprintf('Now in validateSingleAccount(%d)', $index));
|
||||||
|
|
||||||
/** @var AccountValidator $accountValidator */
|
/** @var AccountValidator $accountValidator */
|
||||||
$accountValidator = app(AccountValidator::class);
|
$accountValidator = app(AccountValidator::class);
|
||||||
@@ -158,11 +159,11 @@ trait TransactionValidation
|
|||||||
*/
|
*/
|
||||||
protected function sanityCheckReconciliation(Validator $validator, string $transactionType, int $index, array $source, array $destination): void
|
protected function sanityCheckReconciliation(Validator $validator, string $transactionType, int $index, array $source, array $destination): void
|
||||||
{
|
{
|
||||||
app('log')->debug('Now in sanityCheckReconciliation');
|
Log::debug('Now in sanityCheckReconciliation');
|
||||||
if (TransactionTypeEnum::RECONCILIATION->value === ucfirst($transactionType)
|
if (TransactionTypeEnum::RECONCILIATION->value === ucfirst($transactionType)
|
||||||
&& null === $source['id'] && null === $source['name'] && null === $destination['id'] && null === $destination['name']
|
&& null === $source['id'] && null === $source['name'] && null === $destination['id'] && null === $destination['name']
|
||||||
) {
|
) {
|
||||||
app('log')->debug('Both are NULL, error!');
|
Log::debug('Both are NULL, error!');
|
||||||
$validator->errors()->add(sprintf('transactions.%d.source_id', $index), trans('validation.reconciliation_either_account'));
|
$validator->errors()->add(sprintf('transactions.%d.source_id', $index), trans('validation.reconciliation_either_account'));
|
||||||
$validator->errors()->add(sprintf('transactions.%d.source_name', $index), trans('validation.reconciliation_either_account'));
|
$validator->errors()->add(sprintf('transactions.%d.source_name', $index), trans('validation.reconciliation_either_account'));
|
||||||
$validator->errors()->add(sprintf('transactions.%d.destination_id', $index), trans('validation.reconciliation_either_account'));
|
$validator->errors()->add(sprintf('transactions.%d.destination_id', $index), trans('validation.reconciliation_either_account'));
|
||||||
@@ -172,7 +173,7 @@ trait TransactionValidation
|
|||||||
if (TransactionTypeEnum::RECONCILIATION->value === $transactionType
|
if (TransactionTypeEnum::RECONCILIATION->value === $transactionType
|
||||||
&& (null !== $source['id'] || null !== $source['name'])
|
&& (null !== $source['id'] || null !== $source['name'])
|
||||||
&& (null !== $destination['id'] || null !== $destination['name'])) {
|
&& (null !== $destination['id'] || null !== $destination['name'])) {
|
||||||
app('log')->debug('Both are not NULL, error!');
|
Log::debug('Both are not NULL, error!');
|
||||||
$validator->errors()->add(sprintf('transactions.%d.source_id', $index), trans('validation.reconciliation_either_account'));
|
$validator->errors()->add(sprintf('transactions.%d.source_id', $index), trans('validation.reconciliation_either_account'));
|
||||||
$validator->errors()->add(sprintf('transactions.%d.source_name', $index), trans('validation.reconciliation_either_account'));
|
$validator->errors()->add(sprintf('transactions.%d.source_name', $index), trans('validation.reconciliation_either_account'));
|
||||||
$validator->errors()->add(sprintf('transactions.%d.destination_id', $index), trans('validation.reconciliation_either_account'));
|
$validator->errors()->add(sprintf('transactions.%d.destination_id', $index), trans('validation.reconciliation_either_account'));
|
||||||
@@ -193,30 +194,30 @@ trait TransactionValidation
|
|||||||
string $transactionType,
|
string $transactionType,
|
||||||
int $index
|
int $index
|
||||||
): void {
|
): void {
|
||||||
app('log')->debug('Now in sanityCheckForeignCurrency()');
|
Log::debug('Now in sanityCheckForeignCurrency()');
|
||||||
if (0 !== $validator->errors()->count()) {
|
if (0 !== $validator->errors()->count()) {
|
||||||
app('log')->debug('Already have errors, return');
|
Log::debug('Already have errors, return');
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (null === $accountValidator->source) {
|
if (null === $accountValidator->source) {
|
||||||
app('log')->debug('No source, return');
|
Log::debug('No source, return');
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (null === $accountValidator->destination) {
|
if (null === $accountValidator->destination) {
|
||||||
app('log')->debug('No destination, return');
|
Log::debug('No destination, return');
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
$source = $accountValidator->source;
|
$source = $accountValidator->source;
|
||||||
$destination = $accountValidator->destination;
|
$destination = $accountValidator->destination;
|
||||||
|
|
||||||
app('log')->debug(sprintf('Source: #%d "%s (%s)"', $source->id, $source->name, $source->accountType->type));
|
Log::debug(sprintf('Source: #%d "%s (%s)"', $source->id, $source->name, $source->accountType->type));
|
||||||
app('log')->debug(sprintf('Destination: #%d "%s" (%s)', $destination->id, $destination->name, $source->accountType->type));
|
Log::debug(sprintf('Destination: #%d "%s" (%s)', $destination->id, $destination->name, $source->accountType->type));
|
||||||
|
|
||||||
if (!$this->isLiabilityOrAsset($source) || !$this->isLiabilityOrAsset($destination)) {
|
if (!$this->isLiabilityOrAsset($source) || !$this->isLiabilityOrAsset($destination)) {
|
||||||
app('log')->debug('Any account must be liability or asset account to continue.');
|
Log::debug('Any account must be liability or asset account to continue.');
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -228,17 +229,17 @@ trait TransactionValidation
|
|||||||
$destinationCurrency = $accountRepository->getAccountCurrency($destination) ?? $defaultCurrency;
|
$destinationCurrency = $accountRepository->getAccountCurrency($destination) ?? $defaultCurrency;
|
||||||
// if both accounts have the same currency, continue.
|
// if both accounts have the same currency, continue.
|
||||||
if ($sourceCurrency->code === $destinationCurrency->code) {
|
if ($sourceCurrency->code === $destinationCurrency->code) {
|
||||||
app('log')->debug('Both accounts have the same currency, continue.');
|
Log::debug('Both accounts have the same currency, continue.');
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
app('log')->debug(sprintf('Source account expects %s', $sourceCurrency->code));
|
Log::debug(sprintf('Source account expects %s', $sourceCurrency->code));
|
||||||
app('log')->debug(sprintf('Destination account expects %s', $destinationCurrency->code));
|
Log::debug(sprintf('Destination account expects %s', $destinationCurrency->code));
|
||||||
|
|
||||||
app('log')->debug(sprintf('Amount is %s', $transaction['amount']));
|
Log::debug(sprintf('Amount is %s', $transaction['amount']));
|
||||||
|
|
||||||
if (TransactionTypeEnum::DEPOSIT->value === ucfirst($transactionType)) {
|
if (TransactionTypeEnum::DEPOSIT->value === ucfirst($transactionType)) {
|
||||||
app('log')->debug(sprintf('Processing as a "%s"', $transactionType));
|
Log::debug(sprintf('Processing as a "%s"', $transactionType));
|
||||||
// use case: deposit from liability account to an asset account
|
// use case: deposit from liability account to an asset account
|
||||||
// the foreign amount must be in the currency of the source
|
// the foreign amount must be in the currency of the source
|
||||||
// the amount must be in the currency of the destination
|
// the amount must be in the currency of the destination
|
||||||
@@ -253,7 +254,7 @@ trait TransactionValidation
|
|||||||
// wrong currency information is present
|
// wrong currency information is present
|
||||||
$foreignCurrencyCode = $transaction['foreign_currency_code'] ?? false;
|
$foreignCurrencyCode = $transaction['foreign_currency_code'] ?? false;
|
||||||
$foreignCurrencyId = (int) ($transaction['foreign_currency_id'] ?? 0);
|
$foreignCurrencyId = (int) ($transaction['foreign_currency_id'] ?? 0);
|
||||||
app('log')->debug(sprintf('Foreign currency code seems to be #%d "%s"', $foreignCurrencyId, $foreignCurrencyCode), $transaction);
|
Log::debug(sprintf('Foreign currency code seems to be #%d "%s"', $foreignCurrencyId, $foreignCurrencyCode), $transaction);
|
||||||
if ($foreignCurrencyCode !== $sourceCurrency->code && $foreignCurrencyId !== $sourceCurrency->id) {
|
if ($foreignCurrencyCode !== $sourceCurrency->code && $foreignCurrencyId !== $sourceCurrency->id) {
|
||||||
$validator->errors()->add(sprintf('transactions.%d.foreign_currency_code', $index), (string) trans('validation.require_foreign_src'));
|
$validator->errors()->add(sprintf('transactions.%d.foreign_currency_code', $index), (string) trans('validation.require_foreign_src'));
|
||||||
|
|
||||||
@@ -261,7 +262,7 @@ trait TransactionValidation
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (TransactionTypeEnum::TRANSFER->value === ucfirst($transactionType) || TransactionTypeEnum::WITHDRAWAL->value === ucfirst($transactionType)) {
|
if (TransactionTypeEnum::TRANSFER->value === ucfirst($transactionType) || TransactionTypeEnum::WITHDRAWAL->value === ucfirst($transactionType)) {
|
||||||
app('log')->debug(sprintf('Processing as a "%s"', $transactionType));
|
Log::debug(sprintf('Processing as a "%s"', $transactionType));
|
||||||
// use case: withdrawal from asset account to a liability account.
|
// use case: withdrawal from asset account to a liability account.
|
||||||
// the foreign amount must be in the currency of the destination
|
// the foreign amount must be in the currency of the destination
|
||||||
// the amount must be in the currency of the source
|
// the amount must be in the currency of the source
|
||||||
@@ -280,10 +281,10 @@ trait TransactionValidation
|
|||||||
// wrong currency information is present
|
// wrong currency information is present
|
||||||
$foreignCurrencyCode = $transaction['foreign_currency_code'] ?? false;
|
$foreignCurrencyCode = $transaction['foreign_currency_code'] ?? false;
|
||||||
$foreignCurrencyId = (int) ($transaction['foreign_currency_id'] ?? 0);
|
$foreignCurrencyId = (int) ($transaction['foreign_currency_id'] ?? 0);
|
||||||
app('log')->debug(sprintf('Foreign currency code seems to be #%d "%s"', $foreignCurrencyId, $foreignCurrencyCode), $transaction);
|
Log::debug(sprintf('Foreign currency code seems to be #%d "%s"', $foreignCurrencyId, $foreignCurrencyCode), $transaction);
|
||||||
if ($foreignCurrencyCode !== $destinationCurrency->code && $foreignCurrencyId !== $destinationCurrency->id) {
|
if ($foreignCurrencyCode !== $destinationCurrency->code && $foreignCurrencyId !== $destinationCurrency->id) {
|
||||||
app('log')->debug(sprintf('No match on code, "%s" vs "%s"', $foreignCurrencyCode, $destinationCurrency->code));
|
Log::debug(sprintf('No match on code, "%s" vs "%s"', $foreignCurrencyCode, $destinationCurrency->code));
|
||||||
app('log')->debug(sprintf('No match on ID, #%d vs #%d', $foreignCurrencyId, $destinationCurrency->id));
|
Log::debug(sprintf('No match on ID, #%d vs #%d', $foreignCurrencyId, $destinationCurrency->id));
|
||||||
$validator->errors()->add(sprintf('transactions.%d.foreign_amount', $index), (string) trans('validation.require_foreign_dest'));
|
$validator->errors()->add(sprintf('transactions.%d.foreign_amount', $index), (string) trans('validation.require_foreign_dest'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -336,9 +337,9 @@ trait TransactionValidation
|
|||||||
*/
|
*/
|
||||||
public function validateAccountInformationUpdate(Validator $validator, TransactionGroup $transactionGroup): void
|
public function validateAccountInformationUpdate(Validator $validator, TransactionGroup $transactionGroup): void
|
||||||
{
|
{
|
||||||
app('log')->debug('Now in validateAccountInformationUpdate()');
|
Log::debug('Now in validateAccountInformationUpdate()');
|
||||||
if ($validator->errors()->count() > 0) {
|
if ($validator->errors()->count() > 0) {
|
||||||
app('log')->debug('Validator already has errors, so return.');
|
Log::debug('Validator already has errors, so return.');
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -359,7 +360,7 @@ trait TransactionValidation
|
|||||||
|
|
||||||
protected function validateSingleUpdate(Validator $validator, int $index, array $transaction, TransactionGroup $transactionGroup): void
|
protected function validateSingleUpdate(Validator $validator, int $index, array $transaction, TransactionGroup $transactionGroup): void
|
||||||
{
|
{
|
||||||
app('log')->debug('Now validating single account update in validateSingleUpdate()');
|
Log::debug('Now validating single account update in validateSingleUpdate()');
|
||||||
|
|
||||||
// if no account types are given, just skip the check.
|
// if no account types are given, just skip the check.
|
||||||
if (
|
if (
|
||||||
@@ -367,7 +368,7 @@ trait TransactionValidation
|
|||||||
&& !array_key_exists('source_name', $transaction)
|
&& !array_key_exists('source_name', $transaction)
|
||||||
&& !array_key_exists('destination_id', $transaction)
|
&& !array_key_exists('destination_id', $transaction)
|
||||||
&& !array_key_exists('destination_name', $transaction)) {
|
&& !array_key_exists('destination_name', $transaction)) {
|
||||||
app('log')->debug('No account data has been submitted so will not validating account info.');
|
Log::debug('No account data has been submitted so will not validating account info.');
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -376,8 +377,13 @@ trait TransactionValidation
|
|||||||
/** @var AccountValidator $accountValidator */
|
/** @var AccountValidator $accountValidator */
|
||||||
$accountValidator = app(AccountValidator::class);
|
$accountValidator = app(AccountValidator::class);
|
||||||
|
|
||||||
|
// 2025-01-29 grab the transaction type from the update array.
|
||||||
|
$originalType = $this->getTransactionType($transactionGroup, []);
|
||||||
|
$transactionType = $transaction['type'] ?? $originalType;
|
||||||
|
Log::debug(sprintf('Determined transaction type to be "%s"', $transactionType));
|
||||||
|
|
||||||
// get the transaction type using the original transaction group:
|
// get the transaction type using the original transaction group:
|
||||||
$accountValidator->setTransactionType($this->getTransactionType($transactionGroup, []));
|
$accountValidator->setTransactionType($transactionType);
|
||||||
|
|
||||||
// validate if the submitted source ID/name/iban/number are valid
|
// validate if the submitted source ID/name/iban/number are valid
|
||||||
if (
|
if (
|
||||||
@@ -386,7 +392,7 @@ trait TransactionValidation
|
|||||||
|| array_key_exists('source_iban', $transaction)
|
|| array_key_exists('source_iban', $transaction)
|
||||||
|| array_key_exists('source_number', $transaction)
|
|| array_key_exists('source_number', $transaction)
|
||||||
) {
|
) {
|
||||||
app('log')->debug('Will try to validate source account information.');
|
Log::debug('Will try to validate source account information.');
|
||||||
$sourceId = (int) ($transaction['source_id'] ?? 0);
|
$sourceId = (int) ($transaction['source_id'] ?? 0);
|
||||||
$sourceName = $transaction['source_name'] ?? null;
|
$sourceName = $transaction['source_name'] ?? null;
|
||||||
$sourceIban = $transaction['source_iban'] ?? null;
|
$sourceIban = $transaction['source_iban'] ?? null;
|
||||||
@@ -397,15 +403,20 @@ trait TransactionValidation
|
|||||||
|
|
||||||
// do something with result:
|
// do something with result:
|
||||||
if (false === $validSource) {
|
if (false === $validSource) {
|
||||||
app('log')->warning('Looks like the source account is not valid so complain to the user about it.');
|
Log::warning('Looks like the source account is not valid so complain to the user about it.');
|
||||||
$validator->errors()->add(sprintf('transactions.%d.source_id', $index), $accountValidator->sourceError);
|
$validator->errors()->add(sprintf('transactions.%d.source_id', $index), $accountValidator->sourceError);
|
||||||
$validator->errors()->add(sprintf('transactions.%d.source_name', $index), $accountValidator->sourceError);
|
$validator->errors()->add(sprintf('transactions.%d.source_name', $index), $accountValidator->sourceError);
|
||||||
$validator->errors()->add(sprintf('transactions.%d.source_iban', $index), $accountValidator->sourceError);
|
$validator->errors()->add(sprintf('transactions.%d.source_iban', $index), $accountValidator->sourceError);
|
||||||
$validator->errors()->add(sprintf('transactions.%d.source_number', $index), $accountValidator->sourceError);
|
$validator->errors()->add(sprintf('transactions.%d.source_number', $index), $accountValidator->sourceError);
|
||||||
|
|
||||||
|
// also add an error for the transaction type, if it is different.
|
||||||
|
if ($originalType !== $transactionType) {
|
||||||
|
$validator->errors()->add(sprintf('transactions.%d.type', $index), (string) trans('validation.transaction_type_changed'));
|
||||||
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
app('log')->debug('Source account info is valid.');
|
Log::debug('Source account info is valid.');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (
|
if (
|
||||||
@@ -414,15 +425,15 @@ trait TransactionValidation
|
|||||||
|| array_key_exists('destination_iban', $transaction)
|
|| array_key_exists('destination_iban', $transaction)
|
||||||
|| array_key_exists('destination_number', $transaction)
|
|| array_key_exists('destination_number', $transaction)
|
||||||
) {
|
) {
|
||||||
app('log')->debug('Will try to validate destination account information.');
|
Log::debug('Will try to validate destination account information.');
|
||||||
// at this point the validator may not have a source account, because it was never submitted for validation.
|
// at this point the validator may not have a source account, because it was never submitted for validation.
|
||||||
// must add it ourselves or the validator can never check if the destination is correct.
|
// must add it ourselves or the validator can never check if the destination is correct.
|
||||||
// the $transaction array must have a journal id or it's just one, this was validated before.
|
// the $transaction array must have a journal id or it's just one, this was validated before.
|
||||||
if (null === $accountValidator->source) {
|
if (null === $accountValidator->source) {
|
||||||
app('log')->debug('Account validator has no source account, must find it.');
|
Log::debug('Account validator has no source account, must find it.');
|
||||||
$source = $this->getOriginalSource($transaction, $transactionGroup);
|
$source = $this->getOriginalSource($transaction, $transactionGroup);
|
||||||
if (null !== $source) {
|
if (null !== $source) {
|
||||||
app('log')->debug('Found a source!');
|
Log::debug('Found a source!');
|
||||||
$accountValidator->source = $source;
|
$accountValidator->source = $source;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -434,13 +445,17 @@ trait TransactionValidation
|
|||||||
$validDestination = $accountValidator->validateDestination($array);
|
$validDestination = $accountValidator->validateDestination($array);
|
||||||
// do something with result:
|
// do something with result:
|
||||||
if (false === $validDestination) {
|
if (false === $validDestination) {
|
||||||
app('log')->warning('Looks like the destination account is not valid so complain to the user about it.');
|
Log::warning('Looks like the destination account is not valid so complain to the user about it.');
|
||||||
$validator->errors()->add(sprintf('transactions.%d.destination_id', $index), $accountValidator->destError);
|
$validator->errors()->add(sprintf('transactions.%d.destination_id', $index), $accountValidator->destError);
|
||||||
$validator->errors()->add(sprintf('transactions.%d.destination_name', $index), $accountValidator->destError);
|
$validator->errors()->add(sprintf('transactions.%d.destination_name', $index), $accountValidator->destError);
|
||||||
|
// also add an error for the transaction type, if it is different.
|
||||||
|
if ($originalType !== $transactionType) {
|
||||||
|
$validator->errors()->add(sprintf('transactions.%d.type', $index), (string) trans('validation.transaction_type_changed'));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
app('log')->debug('Destination account info is valid.');
|
Log::debug('Destination account info is valid.');
|
||||||
}
|
}
|
||||||
app('log')->debug('Done with validateSingleUpdate().');
|
Log::debug('Done with validateSingleUpdate().');
|
||||||
}
|
}
|
||||||
|
|
||||||
private function getTransactionType(TransactionGroup $group, array $transactions): string
|
private function getTransactionType(TransactionGroup $group, array $transactions): string
|
||||||
@@ -472,7 +487,7 @@ trait TransactionValidation
|
|||||||
*/
|
*/
|
||||||
public function validateOneRecurrenceTransaction(Validator $validator): void
|
public function validateOneRecurrenceTransaction(Validator $validator): void
|
||||||
{
|
{
|
||||||
app('log')->debug('Now in validateOneRecurrenceTransaction()');
|
Log::debug('Now in validateOneRecurrenceTransaction()');
|
||||||
$transactions = $this->getTransactionsArray($validator);
|
$transactions = $this->getTransactionsArray($validator);
|
||||||
|
|
||||||
// need at least one transaction
|
// need at least one transaction
|
||||||
@@ -486,9 +501,9 @@ trait TransactionValidation
|
|||||||
*/
|
*/
|
||||||
public function validateOneTransaction(Validator $validator): void
|
public function validateOneTransaction(Validator $validator): void
|
||||||
{
|
{
|
||||||
app('log')->debug('Now in validateOneTransaction');
|
Log::debug('Now in validateOneTransaction');
|
||||||
if ($validator->errors()->count() > 0) {
|
if ($validator->errors()->count() > 0) {
|
||||||
app('log')->debug('Validator already has errors, so return.');
|
Log::debug('Validator already has errors, so return.');
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -496,11 +511,11 @@ trait TransactionValidation
|
|||||||
// need at least one transaction
|
// need at least one transaction
|
||||||
if (0 === count($transactions)) {
|
if (0 === count($transactions)) {
|
||||||
$validator->errors()->add('transactions.0.description', (string) trans('validation.at_least_one_transaction'));
|
$validator->errors()->add('transactions.0.description', (string) trans('validation.at_least_one_transaction'));
|
||||||
app('log')->debug('Added error: at_least_one_transaction.');
|
Log::debug('Added error: at_least_one_transaction.');
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
app('log')->debug('Added NO errors.');
|
Log::debug('Added NO errors.');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function validateTransactionArray(Validator $validator): void
|
public function validateTransactionArray(Validator $validator): void
|
||||||
@@ -512,7 +527,7 @@ trait TransactionValidation
|
|||||||
foreach (array_keys($transactions) as $key) {
|
foreach (array_keys($transactions) as $key) {
|
||||||
if (!is_int($key)) {
|
if (!is_int($key)) {
|
||||||
$validator->errors()->add('transactions.0.description', (string) trans('validation.at_least_one_transaction'));
|
$validator->errors()->add('transactions.0.description', (string) trans('validation.at_least_one_transaction'));
|
||||||
app('log')->debug('Added error: at_least_one_transaction.');
|
Log::debug('Added error: at_least_one_transaction.');
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -527,7 +542,7 @@ trait TransactionValidation
|
|||||||
if ($validator->errors()->count() > 0) {
|
if ($validator->errors()->count() > 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
app('log')->debug('Now in validateTransactionTypes()');
|
Log::debug('Now in validateTransactionTypes()');
|
||||||
$transactions = $this->getTransactionsArray($validator);
|
$transactions = $this->getTransactionsArray($validator);
|
||||||
|
|
||||||
$types = [];
|
$types = [];
|
||||||
@@ -551,7 +566,7 @@ trait TransactionValidation
|
|||||||
*/
|
*/
|
||||||
public function validateTransactionTypesForUpdate(Validator $validator): void
|
public function validateTransactionTypesForUpdate(Validator $validator): void
|
||||||
{
|
{
|
||||||
app('log')->debug('Now in validateTransactionTypesForUpdate()');
|
Log::debug('Now in validateTransactionTypesForUpdate()');
|
||||||
$transactions = $this->getTransactionsArray($validator);
|
$transactions = $this->getTransactionsArray($validator);
|
||||||
$types = [];
|
$types = [];
|
||||||
foreach ($transactions as $transaction) {
|
foreach ($transactions as $transaction) {
|
||||||
@@ -561,12 +576,12 @@ trait TransactionValidation
|
|||||||
}
|
}
|
||||||
$unique = array_unique($types);
|
$unique = array_unique($types);
|
||||||
if (count($unique) > 1) {
|
if (count($unique) > 1) {
|
||||||
app('log')->warning('Add error for mismatch transaction types.');
|
Log::warning('Add error for mismatch transaction types.');
|
||||||
$validator->errors()->add('transactions.0.type', (string) trans('validation.transaction_types_equal'));
|
$validator->errors()->add('transactions.0.type', (string) trans('validation.transaction_types_equal'));
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
app('log')->debug('No errors in validateTransactionTypesForUpdate()');
|
Log::debug('No errors in validateTransactionTypesForUpdate()');
|
||||||
}
|
}
|
||||||
|
|
||||||
private function getOriginalType(int $journalId): string
|
private function getOriginalType(int $journalId): string
|
||||||
@@ -589,7 +604,7 @@ trait TransactionValidation
|
|||||||
if ($validator->errors()->count() > 0) {
|
if ($validator->errors()->count() > 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
app('log')->debug('Now in validateEqualAccounts()');
|
Log::debug('Now in validateEqualAccounts()');
|
||||||
$transactions = $this->getTransactionsArray($validator);
|
$transactions = $this->getTransactionsArray($validator);
|
||||||
|
|
||||||
// needs to be split
|
// needs to be split
|
||||||
@@ -635,16 +650,16 @@ trait TransactionValidation
|
|||||||
private function validateEqualAccountsForUpdate(Validator $validator, TransactionGroup $transactionGroup): void
|
private function validateEqualAccountsForUpdate(Validator $validator, TransactionGroup $transactionGroup): void
|
||||||
{
|
{
|
||||||
if ($validator->errors()->count() > 0) {
|
if ($validator->errors()->count() > 0) {
|
||||||
app('log')->debug('Validator already has errors, so return.');
|
Log::debug('Validator already has errors, so return.');
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
app('log')->debug('Now in validateEqualAccountsForUpdate()');
|
Log::debug('Now in validateEqualAccountsForUpdate()');
|
||||||
$transactions = $this->getTransactionsArray($validator);
|
$transactions = $this->getTransactionsArray($validator);
|
||||||
|
|
||||||
if (2 !== count($transactions)) {
|
if (2 !== count($transactions)) {
|
||||||
app('log')->debug('Less than 2 transactions, do nothing.');
|
Log::debug('Less than 2 transactions, do nothing.');
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -668,11 +683,11 @@ trait TransactionValidation
|
|||||||
$validator->errors()->add('transactions.0.source_id', (string) trans('validation.all_accounts_equal'));
|
$validator->errors()->add('transactions.0.source_id', (string) trans('validation.all_accounts_equal'));
|
||||||
$validator->errors()->add('transactions.0.destination_id', (string) trans('validation.all_accounts_equal'));
|
$validator->errors()->add('transactions.0.destination_id', (string) trans('validation.all_accounts_equal'));
|
||||||
}
|
}
|
||||||
app('log')->warning('Add error about equal accounts.');
|
Log::warning('Add error about equal accounts.');
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
app('log')->debug('No errors found in validateEqualAccountsForUpdate');
|
Log::debug('No errors found in validateEqualAccountsForUpdate');
|
||||||
}
|
}
|
||||||
|
|
||||||
private function collectComparisonData(array $transactions): array
|
private function collectComparisonData(array $transactions): array
|
||||||
|
105
changelog.md
105
changelog.md
@@ -3,9 +3,108 @@
|
|||||||
All notable changes to this project will be documented in this file.
|
All notable changes to this project will be documented in this file.
|
||||||
This project adheres to [Semantic Versioning](http://semver.org/).
|
This project adheres to [Semantic Versioning](http://semver.org/).
|
||||||
|
|
||||||
## 6.2.0 - 2025-01-26 (or later)
|
## 6.2.6 - 2025-02-13
|
||||||
|
|
||||||
*This release comes with many changes, small and large. I expect you will run into issue, and I appreciate your feedback and your patience as I fix them. I've tested many things, but I'm 100% sure I've missed things. Please open [an issue here](https://github.com/firefly-iii/firefly-iii/issues/new?template=bug.yml) if you run into problems.
|
### Fixed
|
||||||
|
|
||||||
|
- [Issue 9797](https://github.com/firefly-iii/firefly-iii/issues/9797) (All account charts show a horizontal line) reported by @avee87
|
||||||
|
- [Issue 9806](https://github.com/firefly-iii/firefly-iii/issues/9806) (Exchange Rates table fails to load when language is not English) reported by @polter-rnd
|
||||||
|
- [Issue 9807](https://github.com/firefly-iii/firefly-iii/issues/9807) (Start Date of Reconciliation Period Incorrectly Excludes Transactions for That Day) reported by @pwschattenberg
|
||||||
|
- [Issue 9808](https://github.com/firefly-iii/firefly-iii/issues/9808) (Default financial report line graph shows a different balance than the text) reported by @mtaygur
|
||||||
|
- [Issue 9810](https://github.com/firefly-iii/firefly-iii/issues/9810) (Foreign amount not taken into consideration for budget spent/leaving) reported by @M4xS0ch
|
||||||
|
- [Issue 9821](https://github.com/firefly-iii/firefly-iii/issues/9821) (piggy events api 500 error) reported by @4e868df3
|
||||||
|
- [Issue 9826](https://github.com/firefly-iii/firefly-iii/issues/9826) (Wrong account balance) reported by @fabienfitoussi
|
||||||
|
|
||||||
|
## 6.2.5 - 2025-02-08
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- [Issue 9736](https://github.com/firefly-iii/firefly-iii/issues/9736) (Wrong `finalAccountBalance` result) reported by @gthbusrr
|
||||||
|
- [Issue 9747](https://github.com/firefly-iii/firefly-iii/issues/9747) (Data entry issues with exchange rates) reported by @Azmodeszer
|
||||||
|
- [Issue 9769](https://github.com/firefly-iii/firefly-iii/issues/9769) ("Your accounts" graph shows changes at wrong dates - not fixed by v6.2.4) reported by @SteffoSpieler
|
||||||
|
- [Discussion 9780](https://github.com/orgs/firefly-iii/discussions/9780) (Rules or webhook precedence?) started by @joeshmoe57
|
||||||
|
- [Issue 9781](https://github.com/firefly-iii/firefly-iii/issues/9781) (Search key `has_any_external_url:false` returns all transactions) reported by @joeshmoe57
|
||||||
|
- [Issue 9783](https://github.com/firefly-iii/firefly-iii/issues/9783) (Subscriptions: Make "Not expected this period" and "expected x days from now" different colors) reported by @SteffoSpieler
|
||||||
|
- [Issue 9784](https://github.com/firefly-iii/firefly-iii/issues/9784) (Transfers with external currency not considered for account balance?) reported by @pvieira84
|
||||||
|
- [Issue 9786](https://github.com/firefly-iii/firefly-iii/issues/9786) (The error 500 information page has non-clickable links to github and the debug page) reported by @tjmv
|
||||||
|
- [Issue 9787](https://github.com/firefly-iii/firefly-iii/issues/9787) (Twig general template error formatting TransactionCurrency on main page) reported by @tjmv
|
||||||
|
- [Issue 9789](https://github.com/firefly-iii/firefly-iii/issues/9789) (Can't open expense and revenue accounts view) reported by @puffer-duck
|
||||||
|
|
||||||
|
## 6.2.4 - 2025-02-05
|
||||||
|
|
||||||
|
> ⚠️ _Most pressing issues are fixed. Please open [an issue here](https://github.com/firefly-iii/firefly-iii/issues/new?template=bug.yml) if you run into problems._
|
||||||
|
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- [Issue 9327](https://github.com/firefly-iii/firefly-iii/issues/9327) (Add Link to Search-Page to the help file) reported by @nottheend
|
||||||
|
- [Issue 9713](https://github.com/firefly-iii/firefly-iii/issues/9713) (Many decimal points in amounts) reported by @memo-567
|
||||||
|
- [Issue 9736](https://github.com/firefly-iii/firefly-iii/issues/9736) (Wrong `finalAccountBalance` result) reported by @gthbusrr
|
||||||
|
- [Discussion 9737](https://github.com/orgs/firefly-iii/discussions/9737) (API returns 0 as current balance) started by @eps90
|
||||||
|
- [Issue 9745](https://github.com/firefly-iii/firefly-iii/issues/9745) (Type mismatch in period overview) reported by @electrofloat
|
||||||
|
- [Issue 9747](https://github.com/firefly-iii/firefly-iii/issues/9747) (Data entry issues with exchange rates) reported by @Azmodeszer
|
||||||
|
- [Issue 9751](https://github.com/firefly-iii/firefly-iii/issues/9751) (Net worth changes since 6.2 update) reported by @ahmaddxb
|
||||||
|
- [Issue 9754](https://github.com/firefly-iii/firefly-iii/issues/9754) (Deleting account - Attachments remain) reported by @memo-567
|
||||||
|
- [Issue 9762](https://github.com/firefly-iii/firefly-iii/issues/9762) (Piggy bank show: start/target date not displayed) reported by @Simeam
|
||||||
|
- Various other balance related fixes.
|
||||||
|
- Hotfix for account charts.
|
||||||
|
|
||||||
|
## 6.2.3 - 2025-02-05
|
||||||
|
|
||||||
|
> ⚠️ _Most pressing issues are fixed. Please open [an issue here](https://github.com/firefly-iii/firefly-iii/issues/new?template=bug.yml) if you run into problems._
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- [Issue 9327](https://github.com/firefly-iii/firefly-iii/issues/9327) (Add Link to Search-Page to the help file) reported by @nottheend
|
||||||
|
- [Issue 9713](https://github.com/firefly-iii/firefly-iii/issues/9713) (Many decimal points in amounts) reported by @memo-567
|
||||||
|
- [Issue 9736](https://github.com/firefly-iii/firefly-iii/issues/9736) (Wrong `finalAccountBalance` result) reported by @gthbusrr
|
||||||
|
- [Discussion 9737](https://github.com/orgs/firefly-iii/discussions/9737) (API returns 0 as current balance) started by @eps90
|
||||||
|
- [Issue 9745](https://github.com/firefly-iii/firefly-iii/issues/9745) (Type mismatch in period overview) reported by @electrofloat
|
||||||
|
- [Issue 9747](https://github.com/firefly-iii/firefly-iii/issues/9747) (Data entry issues with exchange rates) reported by @Azmodeszer
|
||||||
|
- [Issue 9751](https://github.com/firefly-iii/firefly-iii/issues/9751) (Net worth changes since 6.2 update) reported by @ahmaddxb
|
||||||
|
- [Issue 9754](https://github.com/firefly-iii/firefly-iii/issues/9754) (Deleting account - Attachments remain) reported by @memo-567
|
||||||
|
- [Issue 9762](https://github.com/firefly-iii/firefly-iii/issues/9762) (Piggy bank show: start/target date not displayed) reported by @Simeam
|
||||||
|
- Various other balance related fixes.
|
||||||
|
|
||||||
|
## 6.2.2 - 2025-02-02
|
||||||
|
|
||||||
|
> ⚠️ _This release comes with many changes, small and large. I expect you will run into issue, and I appreciate your feedback and your patience as I fix them. I've tested many things, but I'm 100% sure I've missed things. Please open [an issue here](https://github.com/firefly-iii/firefly-iii/issues/new?template=bug.yml) if you run into problems._
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- [Issue 9713](https://github.com/firefly-iii/firefly-iii/issues/9713) (Many decimal points in amounts) reported by @memo-567
|
||||||
|
- [Discussion 9727](https://github.com/orgs/firefly-iii/discussions/9727) (Odd behavior from graphs) started by @jbrandwi
|
||||||
|
- [Issue 9729](https://github.com/firefly-iii/firefly-iii/issues/9729) (Type mismatch in transaction collector) reported by @electrofloat
|
||||||
|
- [Issue 9730](https://github.com/firefly-iii/firefly-iii/issues/9730) (API: `PiggyBankAccountRead.id` should return string, returns int) reported by @dreautall
|
||||||
|
- [Issue 9731](https://github.com/firefly-iii/firefly-iii/issues/9731) ($userGroup must not be accessed before initialization) reported by @Azmodeszer
|
||||||
|
- [Issue 9732](https://github.com/firefly-iii/firefly-iii/issues/9732) (Editing dates of a piggy bank does not save) reported by @Simeam
|
||||||
|
- [Issue 9736](https://github.com/firefly-iii/firefly-iii/issues/9736) (Wrong `finalAccountBalance` result) reported by @gthbusrr
|
||||||
|
- [Issue 9738](https://github.com/firefly-iii/firefly-iii/issues/9738) (Missing pagination controls on exchange rate page) reported by @dicksonleong
|
||||||
|
- [Discussion 9744](https://github.com/orgs/firefly-iii/discussions/9744) (Downloading exchange rates results in 404 error) started by @electrofloat
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- [PR 9743](https://github.com/firefly-iii/firefly-iii/pull/9743) (Feature nordic currencies) reported by @mansehr
|
||||||
|
|
||||||
|
|
||||||
|
## 6.2.1 - 2025-02-01
|
||||||
|
|
||||||
|
> ⚠️ _This release comes with many changes, small and large. I expect you will run into issue, and I appreciate your feedback and your patience as I fix them. I've tested many things, but I'm 100% sure I've missed things. Please open [an issue here](https://github.com/firefly-iii/firefly-iii/issues/new?template=bug.yml) if you run into problems._
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- [Issue 9714](https://github.com/firefly-iii/firefly-iii/issues/9714) (current transaction is aborted, commands ignored until end of transaction block) reported by @captainark
|
||||||
|
- [Issue 9717](https://github.com/firefly-iii/firefly-iii/issues/9717) (API api/v1/accounts broken) reported by @brot
|
||||||
|
- [Issue 9719](https://github.com/firefly-iii/firefly-iii/issues/9719) (A couple of TODOs left in resources/views/list/groups.twig) reported by @lostfocus
|
||||||
|
- [Issue 9720](https://github.com/firefly-iii/firefly-iii/issues/9720) (Piggy Bank with no Target amount: unable to add money) reported by @maxsmooth
|
||||||
|
- [Issue 9721](https://github.com/firefly-iii/firefly-iii/issues/9721) (Documentation on exchange-rates page leads to non-existent page) reported by @electrofloat
|
||||||
|
- [Issue 9722](https://github.com/firefly-iii/firefly-iii/issues/9722) (Error 500 on tags page after enabling native currency) reported by @lostfocus
|
||||||
|
- [Issue 9723](https://github.com/firefly-iii/firefly-iii/issues/9723) (Convert to native routine is not called when convert to native is activated) reported by @JC5
|
||||||
|
- [Issue 9726](https://github.com/firefly-iii/firefly-iii/issues/9726) (Postgres cannot deal with "virtual_balance" column) reported by @dicksonleong
|
||||||
|
|
||||||
|
## 6.2.0 - 2025-01-31
|
||||||
|
|
||||||
|
> ⚠️ _This release comes with many changes, small and large. I expect you will run into issue, and I appreciate your feedback and your patience as I fix them. I've tested many things, but I'm 100% sure I've missed things. Please open [an issue here](https://github.com/firefly-iii/firefly-iii/issues/new?template=bug.yml) if you run into problems._
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|
||||||
@@ -45,12 +144,14 @@ This project adheres to [Semantic Versioning](http://semver.org/).
|
|||||||
|
|
||||||
- [Issue 9532](https://github.com/firefly-iii/firefly-iii/issues/9532) (ReportSum Integrity Check fails due to empty foreign_amount) reported by @SircasticFox
|
- [Issue 9532](https://github.com/firefly-iii/firefly-iii/issues/9532) (ReportSum Integrity Check fails due to empty foreign_amount) reported by @SircasticFox
|
||||||
- [Issue 7288](https://github.com/firefly-iii/firefly-iii/issues/7288) (currentMonthStart/currentMonthEnd not working for no-budget view) reported by @bradsk88
|
- [Issue 7288](https://github.com/firefly-iii/firefly-iii/issues/7288) (currentMonthStart/currentMonthEnd not working for no-budget view) reported by @bradsk88
|
||||||
|
- [Issue 9704](https://github.com/firefly-iii/firefly-iii/issues/9704) (Piggy banks widget displays only main currency for different currencies) reported by @vayakovlev
|
||||||
|
|
||||||
### API
|
### API
|
||||||
|
|
||||||
- API changes related to new features are [documented](https://api-docs.firefly-iii.org/).
|
- API changes related to new features are [documented](https://api-docs.firefly-iii.org/).
|
||||||
- New endpoint for multiple financial administrations ("user groups").
|
- New endpoint for multiple financial administrations ("user groups").
|
||||||
- The change from "default currency" (user) to "native currency" (financial administration) is slowly being reflected in the API. Please report issues.
|
- The change from "default currency" (user) to "native currency" (financial administration) is slowly being reflected in the API. Please report issues.
|
||||||
|
- You can change the "transaction type" of an existing transaction if you submit a new `type` and the correct source and destination account names or IDs.
|
||||||
|
|
||||||
## 6.1.25 - 2024-12-19
|
## 6.1.25 - 2024-12-19
|
||||||
|
|
||||||
|
396
composer.lock
generated
396
composer.lock
generated
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user