Compare commits

...

77 Commits

Author SHA1 Message Date
github-actions[bot] 84efd6e2ee Merge pull request #10487 from firefly-iii/release-1750649637
🤖 Automatically merge the PR into the develop branch.
2025-06-23 05:34:05 +02:00
JC5 b1fbe4e909 🤖 Auto commit for release 'develop' on 2025-06-23 2025-06-23 05:33:57 +02:00
James Cole 8576877072 Reverse currency change. 2025-06-20 07:45:41 +02:00
github-actions[bot] ac61a78d8d Merge pull request #10478 from firefly-iii/release-1750394715
🤖 Automatically merge the PR into the develop branch.
2025-06-20 06:45:22 +02:00
JC5 fce90a94c4 🤖 Auto commit for release 'v6.2.18' on 2025-06-20 2025-06-20 06:45:15 +02:00
github-actions[bot] 023a4f178d Merge pull request #10477 from firefly-iii/release-1750393987
🤖 Automatically merge the PR into the develop branch.
2025-06-20 06:33:14 +02:00
JC5 ef254995ad 🤖 Auto commit for release 'develop' on 2025-06-20 2025-06-20 06:33:07 +02:00
James Cole faeb74634b Merge branch 'main' into develop 2025-06-20 06:28:53 +02:00
James Cole b5baae373f Move changelog. 2025-06-20 06:28:42 +02:00
James Cole 63de711cda Update changelog. 2025-06-20 06:24:19 +02:00
James Cole bd28d116cb Fix currency seeder, add some debug logs. 2025-06-20 05:59:44 +02:00
github-actions[bot] 7efc2861bc Merge pull request #10468 from firefly-iii/release-1750044727
🤖 Automatically merge the PR into the develop branch.
2025-06-16 05:32:16 +02:00
JC5 5c689a2ca2 🤖 Auto commit for release 'develop' on 2025-06-16 2025-06-16 05:32:08 +02:00
github-actions[bot] d5d65df76f Merge pull request #10459 from firefly-iii/release-1749897382
🤖 Automatically merge the PR into the develop branch.
2025-06-14 12:36:32 +02:00
JC5 df7d4f700c 🤖 Auto commit for release 'develop' on 2025-06-14 2025-06-14 12:36:22 +02:00
James Cole efebe3cb41 Remove debug letters. 2025-06-14 12:31:54 +02:00
James Cole 2ba5b6ae49 Fix #10454 2025-06-14 10:18:58 +02:00
github-actions[bot] 31d93efab2 Merge pull request #10451 from firefly-iii/release-1749735701
🤖 Automatically merge the PR into the develop branch.
2025-06-12 15:41:49 +02:00
JC5 657b95485c 🤖 Auto commit for release 'develop' on 2025-06-12 2025-06-12 15:41:41 +02:00
Sander Dorigo 3bfc12f93b Try to be more clear about OAuth errors 2025-06-12 15:36:38 +02:00
James Cole ccfd2f2ac3 Update fr.yml
Signed-off-by: James Cole <james@firefly-iii.org>
2025-06-12 13:12:50 +02:00
James Cole fb3fe0d87b Update bug.yml
Signed-off-by: James Cole <james@firefly-iii.org>
2025-06-12 13:11:55 +02:00
James Cole c80c6d52fe Update config.yml
Signed-off-by: James Cole <james@firefly-iii.org>
2025-06-12 13:02:14 +02:00
Sander Dorigo 0fb3c0c7bf Add missing variable name 2025-06-11 15:51:39 +02:00
github-actions[bot] 43c625bee2 Merge pull request #10444 from firefly-iii/develop
🤖 Automatically merge the PR into the main branch.
2025-06-11 14:07:28 +02:00
github-actions[bot] 967a5dd256 Merge pull request #10443 from firefly-iii/release-1749643634
🤖 Automatically merge the PR into the develop branch.
2025-06-11 14:07:22 +02:00
JC5 3c9d1bcaa1 🤖 Auto commit for release 'v6.2.17' on 2025-06-11 2025-06-11 14:07:14 +02:00
github-actions[bot] 8cd2de14a9 Merge pull request #10442 from firefly-iii/release-1749642296
🤖 Automatically merge the PR into the develop branch.
2025-06-11 13:45:03 +02:00
JC5 7728a35e04 🤖 Auto commit for release 'develop' on 2025-06-11 2025-06-11 13:44:56 +02:00
Sander Dorigo 49000da123 Update changelog. 2025-06-11 13:40:11 +02:00
Sander Dorigo 32a8f89875 Fix #10419 2025-06-11 13:29:36 +02:00
Sander Dorigo 49e5a81bd3 Fix 10382 2025-06-11 13:23:51 +02:00
Sander Dorigo a8efe86af0 Fix #10229 2025-06-11 13:19:53 +02:00
Sander Dorigo 4f07b089d2 Fix #10441 2025-06-11 09:28:56 +02:00
James Cole e786bf47c2 Small code quality things. 2025-06-09 07:06:42 +02:00
github-actions[bot] be11778c53 Merge pull request #10438 from firefly-iii/release-1749444033
🤖 Automatically merge the PR into the develop branch.
2025-06-09 06:40:42 +02:00
JC5 3d7325424c 🤖 Auto commit for release 'develop' on 2025-06-09 2025-06-09 06:40:34 +02:00
James Cole f4ffed99ef Change some code. 2025-06-09 06:35:58 +02:00
github-actions[bot] 52dfe9a738 Merge pull request #10437 from firefly-iii/release-1749442144
🤖 Automatically merge the PR into the develop branch.
2025-06-09 06:09:10 +02:00
JC5 a0bc8b2ba2 🤖 Auto commit for release 'develop' on 2025-06-09 2025-06-09 06:09:04 +02:00
James Cole 4ffca9e2ca Some fixable code. 2025-06-09 06:05:18 +02:00
James Cole a6afec9afa Merge branch 'main' into develop 2025-06-09 06:04:58 +02:00
James Cole 5d859222f8 Add debug info to release script. 2025-06-09 06:04:50 +02:00
github-actions[bot] 0e3ba14666 Merge pull request #10436 from firefly-iii/release-1749441527
🤖 Automatically merge the PR into the develop branch.
2025-06-09 05:58:55 +02:00
JC5 860767fe5a 🤖 Auto commit for release 'develop' on 2025-06-09 2025-06-09 05:58:47 +02:00
James Cole 91b0ad625c Fix #10433 2025-06-09 05:53:11 +02:00
James Cole 67bab2561a Fix https://github.com/firefly-iii/firefly-iii/issues/10432 2025-06-09 05:50:23 +02:00
github-actions[bot] b7908ebcb4 Merge pull request #10434 from firefly-iii/release-1749439923
🤖 Automatically merge the PR into the develop branch.
2025-06-09 05:32:12 +02:00
JC5 a20601ea85 🤖 Auto commit for release 'develop' on 2025-06-09 2025-06-09 05:32:04 +02:00
James Cole 14622329a8 Replace app calls with static calls. 2025-06-08 15:20:22 +02:00
github-actions[bot] 5577be7b08 Merge pull request #10428 from firefly-iii/release-1749383237
🤖 Automatically merge the PR into the develop branch.
2025-06-08 13:47:27 +02:00
JC5 e3bab9d7d8 🤖 Auto commit for release 'develop' on 2025-06-08 2025-06-08 13:47:17 +02:00
James Cole e0512bee3d Fix #10427 2025-06-08 13:17:01 +02:00
James Cole 20827a5fd1 Fix #10426 2025-06-08 05:55:22 +02:00
James Cole 8819dac1e1 Merge branches 'develop' and 'develop' of github.com:firefly-iii/firefly-iii into develop 2025-06-07 06:31:19 +02:00
James Cole da0a07262c Fix # 2025-06-07 06:31:14 +02:00
github-actions[bot] 9c195dcc66 Merge pull request #10416 from firefly-iii/release-1749057506
🤖 Automatically merge the PR into the develop branch.
2025-06-04 19:18:33 +02:00
JC5 0b45506e52 🤖 Auto commit for release 'develop' on 2025-06-04 2025-06-04 19:18:26 +02:00
James Cole 51e58f8d88 Fix #10413 2025-06-04 15:40:29 +02:00
James Cole d0c658e79a Update message to include IP 2025-06-03 20:00:13 +02:00
github-actions[bot] 35e0791a9f Merge pull request #10411 from firefly-iii/release-1748971941
🤖 Automatically merge the PR into the develop branch.
2025-06-03 19:32:29 +02:00
JC5 637ecc66d2 🤖 Auto commit for release 'develop' on 2025-06-03 2025-06-03 19:32:21 +02:00
James Cole 3a38175b2a Fix renamed variable. 2025-06-03 19:26:07 +02:00
James Cole d78fd86d7a Catch already linked transactions. 2025-06-02 20:46:09 +02:00
James Cole 395332d6dd Fix #10403 2025-06-02 20:32:58 +02:00
James Cole c5cbceb81a Fix #10399 2025-06-02 05:39:43 +02:00
github-actions[bot] ec94f1bcf1 Merge pull request #10401 from firefly-iii/release-1748835078
🤖 Automatically merge the PR into the develop branch.
2025-06-02 05:31:25 +02:00
JC5 ee3d18a8ea 🤖 Auto commit for release 'develop' on 2025-06-02 2025-06-02 05:31:18 +02:00
James Cole a9cd8b6512 Better fit for run recalculations. 2025-06-01 14:00:35 +02:00
James Cole 5bd87036b0 Config works now. Does not feel solved yet, but still. 2025-06-01 13:32:18 +02:00
github-actions[bot] 0e7d72023d Merge pull request #10398 from firefly-iii/release-1748774144
🤖 Automatically merge the PR into the develop branch.
2025-06-01 12:35:50 +02:00
JC5 314f91ff24 🤖 Auto commit for release 'develop' on 2025-06-01 2025-06-01 12:35:44 +02:00
James Cole ed54a5c9a4 Fix cache issue in recurring cron job report. 2025-06-01 12:24:02 +02:00
github-actions[bot] adbf785aba Merge pull request #10381 from firefly-iii/develop
🤖 Automatically merge the PR into the main branch.
2025-05-27 18:27:32 +02:00
github-actions[bot] 1fae39a49d Merge pull request #10366 from firefly-iii/develop
🤖 Automatically merge the PR into the main branch.
2025-05-25 07:11:22 +02:00
github-actions[bot] 659240a98b Merge pull request #10363 from firefly-iii/develop
🤖 Automatically merge the PR into the main branch.
2025-05-25 06:49:54 +02:00
github-actions[bot] e9644c9679 Merge pull request #10345 from firefly-iii/develop
🤖 Automatically merge the PR into the main branch.
2025-05-24 06:31:42 +02:00
117 changed files with 3899 additions and 3495 deletions
+3 -10
View File
@@ -1,4 +1,4 @@
name: Bug Report
name: Bug report
description: Report a bug in Firefly III (or associated tools)
body:
- type: checkboxes
@@ -12,7 +12,7 @@ body:
- type: checkboxes
attributes:
label: I've found a bug and checked that ...
description: Make sure that your request fulfills all of the following requirements. If one requirement cannot be satisfied, explain in detail why.
description: Make sure that your request fulfills all of the following requirements. If one requirement cannot be satisfied, please explain why.
options:
- label: ... [the documentation](https://docs.firefly-iii.org/) does not mention anything about my problem
- label: ... there are no open or closed issues that are related to my problem
@@ -33,13 +33,6 @@ body:
validations:
required: true
- type: textarea
attributes:
label: Expected behaviour
description: Please describe precisely what you'd expect to happen. Be specific.
validations:
required: false
- type: textarea
attributes:
label: Steps to reproduce
@@ -54,4 +47,4 @@ body:
- type: textarea
attributes:
label: Additional info
description: Please provide any additional information that seem useful.
description: Please provide any additional information that seems useful.
+3
View File
@@ -3,3 +3,6 @@ contact_links:
- name: Ask a question
url: https://github.com/firefly-iii/firefly-iii/discussions
about: Please ask and answer questions here.
- name: I need support!
url: https://github.com/firefly-iii/firefly-iii/discussions
about: I think I broke something...
+1 -6
View File
@@ -1,4 +1,4 @@
name: Feature Request
name: Feature request
description: Request a feature or enhancement in Firefly III (or associated tools)
body:
- type: checkboxes
@@ -31,11 +31,6 @@ body:
validations:
required: true
- type: textarea
attributes:
label: What are alternatives?
description: Please describe what alternatives currently exist.
- type: textarea
attributes:
label: Additional context
+17
View File
@@ -279,10 +279,20 @@ jobs:
if [[ "develop" != "$version" ]] && [[ "$version" != branch* ]] && [[ "$version" != *alpha* ]] && [[ "$version" != *beta* ]]; then
echo 'Describe the latest release'
sudo chown -R runner:docker output.txt
# the changelog is in output.txt
mv output.txt output2.txt
touch output.txt
echo '' >> output.txt
echo "Welcome to release $version of Firefly III. It contains the the latest fixes, translations and features. Docker users can find this release under the \`latest\` tag." >> output.txt
echo '' >> output.txt
# add changelog to file.
cat output2.txt >> output.txt
echo '' >> output.txt
rm -f output2.txt
echo '### Instructions' >> output.txt
echo '' >> output.txt
echo "* Installation instructions for [Docker](https://docs.firefly-iii.org/how-to/firefly-iii/installation/docker/), [Portainer](https://docs.firefly-iii.org/how-to/firefly-iii/installation/portainer/), [Kubernetes](https://docs.firefly-iii.org/how-to/firefly-iii/installation/kubernetes/) or [self-managed servers](https://docs.firefly-iii.org/how-to/firefly-iii/installation/self-managed/)" >> output.txt
@@ -465,20 +475,27 @@ jobs:
- name: Upload artifacts
run: |
# add zip file to release.
echo "Upload $zipName to $releaseName"
gh release upload $releaseName $zipName
echo "Upload $tarName to $releaseName"
gh release upload $releaseName $tarName
# add sha256 sum to release
echo "Upload $zipName.sha256 to $releaseName"
gh release upload $releaseName $zipName.sha256
echo "Upload $tarName.sha256 to $releaseName"
gh release upload $releaseName $tarName.sha256
# add signatures to release
echo "Upload $zipName.asc to $releaseName"
gh release upload $releaseName $zipName.asc
echo "Upload $tarName.asc to $releaseName"
gh release upload $releaseName $tarName.asc
# get current HEAD and add as file to the release
HEAD=$(git rev-parse HEAD)
echo $HEAD > HEAD.txt
echo "Upload HEAD.txt to $releaseName"
gh release upload $releaseName HEAD.txt
# remove all temporary files
@@ -24,6 +24,7 @@ declare(strict_types=1);
namespace FireflyIII\Api\V1\Controllers\Autocomplete;
use Deprecated;
use FireflyIII\Api\V1\Controllers\Controller;
use FireflyIII\Api\V1\Requests\Autocomplete\AutocompleteRequest;
use FireflyIII\Models\TransactionCurrency;
@@ -83,9 +84,8 @@ class CurrencyController extends Controller
/**
* Documentation for this endpoint is at:
* https://api-docs.firefly-iii.org/?urls.primaryName=2.0.0%20(v1)#/autocomplete/getCurrenciesCodeAC
*
* @deprecated
*/
#[Deprecated]
public function currenciesWithCode(AutocompleteRequest $request): JsonResponse
{
$data = $request->getData();
@@ -24,6 +24,7 @@ declare(strict_types=1);
namespace FireflyIII\Api\V1\Controllers\Chart;
use FireflyIII\Exceptions\ValidationException;
use FireflyIII\Models\TransactionCurrency;
use Carbon\Carbon;
use FireflyIII\Api\V1\Controllers\Controller;
@@ -35,6 +36,7 @@ use FireflyIII\Models\Account;
use FireflyIII\Models\Preference;
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use FireflyIII\Support\Chart\ChartData;
use FireflyIII\Support\Facades\Preferences;
use FireflyIII\Support\Facades\Steam;
use FireflyIII\Support\Http\Api\ApiSupport;
use FireflyIII\Support\Http\Api\CollectsAccountsFromFilter;
@@ -139,7 +141,7 @@ class AccountController extends Controller
* This endpoint is documented at:
* https://api-docs.firefly-iii.org/?urls.primaryName=2.0.0%20(v1)#/charts/getChartAccountOverview
*
* @throws FireflyException
* @throws ValidationException
*/
public function overview(DateRequest $request): JsonResponse
{
@@ -160,7 +162,7 @@ class AccountController extends Controller
$defaultSet = $this->repository->getAccountsByType([AccountTypeEnum::ASSET->value])->pluck('id')->toArray();
/** @var Preference $frontpage */
$frontpage = app('preferences')->get('frontpageAccounts', $defaultSet);
$frontpage = Preferences::get('frontpageAccounts', $defaultSet);
if (!(is_array($frontpage->data) && count($frontpage->data) > 0)) {
$frontpage->data = $defaultSet;
@@ -212,7 +212,7 @@ class BudgetController extends Controller
*/
private function budgetLimits(Budget $budget, Collection $limits): array
{
app('log')->debug(sprintf('Now in budgetLimits(#%d)', $budget->id));
Log::debug(sprintf('Now in budgetLimits(#%d)', $budget->id));
$data = [];
/** @var BudgetLimit $limit */
@@ -233,16 +233,11 @@ class BudgetController extends Controller
$end->endOfDay();
$spent = $this->opsRepository->listExpenses($limit->start_date, $end, null, new Collection([$budget]));
$limitCurrencyId = $limit->transaction_currency_id;
$filtered = [];
/** @var array $entry */
foreach ($spent as $currencyId => $entry) {
// only spent the entry where the entry's currency matches the budget limit's currency
// so $filtered will only have 1 or 0 entries
if ($entry['currency_id'] === $limitCurrencyId) {
$filtered[$currencyId] = $entry;
}
}
// only spent the entry where the entry's currency matches the budget limit's currency
// so $filtered will only have 1 or 0 entries
$filtered = array_filter($spent, fn ($entry) => $entry['currency_id'] === $limitCurrencyId);
$result = $this->processExpenses($budget->id, $filtered, $limit->start_date, $end);
if (1 === count($result)) {
$compare = bccomp($limit->amount, (string) app('steam')->positive($result[$limitCurrencyId]['spent']));
-1
View File
@@ -127,7 +127,6 @@ abstract class Controller extends BaseController
Log::error(sprintf('Request field "%s" contains a non-scalar value. Value set to NULL.', $field));
Log::error($e->getMessage());
Log::error($e->getTraceAsString());
$value = null;
}
$obj = null;
if (null !== $date) {
@@ -64,7 +64,7 @@ class DestroyController extends Controller
public function destroy(DestroyRequest $request): JsonResponse
{
$objects = $request->getObjects();
$this->unused = $request->boolean('unused', false);
$this->unused = $request->boolean('unused');
$allExceptAssets = [AccountTypeEnum::BENEFICIARY->value, AccountTypeEnum::CASH->value, AccountTypeEnum::CREDITCARD->value, AccountTypeEnum::DEFAULT->value, AccountTypeEnum::EXPENSE->value, AccountTypeEnum::IMPORT->value, AccountTypeEnum::INITIAL_BALANCE->value, AccountTypeEnum::LIABILITY_CREDIT->value, AccountTypeEnum::RECONCILIATION->value, AccountTypeEnum::REVENUE->value];
$all = [AccountTypeEnum::ASSET->value, AccountTypeEnum::BENEFICIARY->value, AccountTypeEnum::CASH->value, AccountTypeEnum::CREDITCARD->value, AccountTypeEnum::DEBT->value, AccountTypeEnum::DEFAULT->value, AccountTypeEnum::EXPENSE->value, AccountTypeEnum::IMPORT->value, AccountTypeEnum::INITIAL_BALANCE->value, AccountTypeEnum::LIABILITY_CREDIT->value, AccountTypeEnum::LOAN->value, AccountTypeEnum::MORTGAGE->value, AccountTypeEnum::RECONCILIATION->value];
@@ -176,14 +176,14 @@ class DestroyController extends Controller
foreach ($collection as $account) {
$count = $account->transactions()->count();
if (true === $this->unused && 0 === $count) {
app('log')->info(sprintf('Deleted unused account #%d "%s"', $account->id, $account->name));
Log::info(sprintf('Deleted unused account #%d "%s"', $account->id, $account->name));
Log::channel('audit')->info(sprintf('Deleted unused account #%d "%s"', $account->id, $account->name));
$service->destroy($account, null);
continue;
}
if (false === $this->unused) {
app('log')->info(sprintf('Deleting account #%d "%s"', $account->id, $account->name));
Log::info(sprintf('Deleting account #%d "%s"', $account->id, $account->name));
Log::channel('audit')->warning(sprintf('Deleted account #%d "%s"', $account->id, $account->name));
$service->destroy($account, null);
}
@@ -29,6 +29,7 @@ use FireflyIII\Api\V1\Requests\Data\Export\ExportRequest;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Support\Export\ExportDataGenerator;
use Illuminate\Http\Response as LaravelResponse;
use Safe\Exceptions\DatetimeException;
use function Safe\date;
@@ -72,6 +73,7 @@ class ExportController extends Controller
/**
* @throws FireflyException
* @throws DatetimeException
*/
private function returnExport(string $key): LaravelResponse
{
@@ -32,6 +32,7 @@ use FireflyIII\Support\JsonApi\Enrichments\AccountEnrichment;
use FireflyIII\Transformers\AccountTransformer;
use FireflyIII\User;
use Illuminate\Http\JsonResponse;
use Illuminate\Support\Facades\Log;
use League\Fractal\Resource\Item;
/**
@@ -67,7 +68,7 @@ class UpdateController extends Controller
*/
public function update(UpdateRequest $request, Account $account): JsonResponse
{
app('log')->debug(sprintf('Now in %s', __METHOD__));
Log::debug(sprintf('Now in %s', __METHOD__));
$data = $request->getUpdateData();
$data['type'] = config('firefly.shortNamesByFullName.'.$account->accountType->type);
$account = $this->repository->update($account, $data);
@@ -80,7 +80,7 @@ class StoreController extends Controller
throw new NotFoundHttpException();
}
app('log')->debug(sprintf('Now in %s', __METHOD__));
Log::debug(sprintf('Now in %s', __METHOD__));
$data = $request->getAll();
$attachment = $this->repository->store($data);
$manager = $this->getManager();
@@ -109,13 +109,13 @@ class StoreController extends Controller
$helper = app(AttachmentHelperInterface::class);
$body = $request->getContent();
if ('' === $body) {
app('log')->error('Body of attachment is empty.');
Log::error('Body of attachment is empty.');
return response()->json([], 422);
}
$result = $helper->saveAttachmentFromApi($attachment, $body);
if (false === $result) {
app('log')->error('Could not save attachment from API.');
Log::error('Could not save attachment from API.');
return response()->json([], 422);
}
@@ -69,7 +69,6 @@ class StoreController extends Controller
$data = $request->getAll();
$data['start_date'] = $data['start'];
$data['end_date'] = $data['end'];
$data['notes'] = $data['notes'];
$data['budget_id'] = $budget->id;
$budgetLimit = $this->blRepository->store($data);
@@ -34,6 +34,7 @@ use FireflyIII\Repositories\Journal\JournalRepositoryInterface;
use FireflyIII\Repositories\TransactionGroup\TransactionGroupRepository;
use FireflyIII\User;
use Illuminate\Http\JsonResponse;
use Illuminate\Support\Facades\Log;
/**
* Class DestroyController
@@ -73,7 +74,7 @@ class DestroyController extends Controller
*/
public function destroy(TransactionGroup $transactionGroup): JsonResponse
{
app('log')->debug(sprintf('Now in %s', __METHOD__));
Log::debug(sprintf('Now in %s', __METHOD__));
// grab asset account(s) from group:
$accounts = [];
@@ -95,7 +96,7 @@ class DestroyController extends Controller
/** @var Account $account */
foreach ($accounts as $account) {
app('log')->debug(sprintf('Now going to trigger updated account event for account #%d', $account->id));
Log::debug(sprintf('Now going to trigger updated account event for account #%d', $account->id));
event(new UpdatedAccount($account));
}
@@ -84,7 +84,7 @@ class StoreController extends Controller
*/
public function store(StoreRequest $request): JsonResponse
{
app('log')->debug('Now in API StoreController::store()');
Log::debug('Now in API StoreController::store()');
$data = $request->getAll();
$data['user'] = auth()->user();
$data['user_group'] = $this->userGroup;
@@ -95,13 +95,13 @@ class StoreController extends Controller
try {
$transactionGroup = $this->groupRepository->store($data);
} catch (DuplicateTransactionException $e) {
app('log')->warning('Caught a duplicate transaction. Return error message.');
Log::warning('Caught a duplicate transaction. Return error message.');
$validator = Validator::make(['transactions' => [['description' => $e->getMessage()]]], ['transactions.0.description' => new IsDuplicateTransaction()]);
throw new ValidationException($validator);
} catch (FireflyException $e) {
app('log')->warning('Caught an exception. Return error message.');
app('log')->error($e->getMessage());
Log::warning('Caught an exception. Return error message.');
Log::error($e->getMessage());
$message = sprintf('Internal exception: %s', $e->getMessage());
$validator = Validator::make(['transactions' => [['description' => $message]]], ['transactions.0.description' => new IsDuplicateTransaction()]);
@@ -72,27 +72,25 @@ class UpdateController extends Controller
*/
public function update(UpdateRequest $request, TransactionGroup $transactionGroup): JsonResponse
{
app('log')->debug('Now in update routine for transaction group');
$data = $request->getAll();
$oldAmount = $this->groupRepository->getTotalAmount($transactionGroup);
$transactionGroup = $this->groupRepository->update($transactionGroup, $data);
$newAmount = $this->groupRepository->getTotalAmount($transactionGroup);
$manager = $this->getManager();
Log::debug(sprintf('Old amount: %s, new amount: %s', $oldAmount, $newAmount));
Log::debug('Now in update routine for transaction group');
$data = $request->getAll();
$oldHash = $this->groupRepository->getCompareHash($transactionGroup);
$transactionGroup = $this->groupRepository->update($transactionGroup, $data);
$newHash = $this->groupRepository->getCompareHash($transactionGroup);
$manager = $this->getManager();
app('preferences')->mark();
$applyRules = $data['apply_rules'] ?? true;
$fireWebhooks = $data['fire_webhooks'] ?? true;
$amountChanged = 0 !== bccomp($oldAmount, $newAmount);
event(new UpdatedTransactionGroup($transactionGroup, $applyRules, $fireWebhooks, $amountChanged));
$applyRules = $data['apply_rules'] ?? true;
$fireWebhooks = $data['fire_webhooks'] ?? true;
$runRecalculations = $oldHash !== $newHash;
event(new UpdatedTransactionGroup($transactionGroup, $applyRules, $fireWebhooks, $runRecalculations));
/** @var User $admin */
$admin = auth()->user();
$admin = auth()->user();
// use new group collector:
/** @var GroupCollectorInterface $collector */
$collector = app(GroupCollectorInterface::class);
$collector = app(GroupCollectorInterface::class);
$collector
->setUser($admin)
// filter on transaction group.
@@ -101,20 +99,20 @@ class UpdateController extends Controller
->withAPIInformation()
;
$selectedGroup = $collector->getGroups()->first();
$selectedGroup = $collector->getGroups()->first();
if (null === $selectedGroup) {
throw new NotFoundHttpException();
}
// enrich
$enrichment = new TransactionGroupEnrichment();
$enrichment = new TransactionGroupEnrichment();
$enrichment->setUser($admin);
$selectedGroup = $enrichment->enrichSingle($selectedGroup);
$selectedGroup = $enrichment->enrichSingle($selectedGroup);
/** @var TransactionGroupTransformer $transformer */
$transformer = app(TransactionGroupTransformer::class);
$transformer = app(TransactionGroupTransformer::class);
$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);
}
@@ -32,6 +32,7 @@ use FireflyIII\Repositories\Currency\CurrencyRepositoryInterface;
use FireflyIII\Repositories\User\UserRepositoryInterface;
use FireflyIII\User;
use Illuminate\Http\JsonResponse;
use Illuminate\Validation\ValidationException;
/**
* Class DestroyController
@@ -65,6 +66,7 @@ class DestroyController extends Controller
* Remove the specified resource from storage.
*
* @throws FireflyException
* @throws ValidationException
*/
public function destroy(TransactionCurrency $currency): JsonResponse
{
@@ -250,10 +250,8 @@ class ListController extends Controller
$collection = $unfiltered->filter(
static function (Recurrence $recurrence) use ($currency) { // @phpstan-ignore-line
/** @var RecurrenceTransaction $transaction */
foreach ($recurrence->recurrenceTransactions as $transaction) {
if ($transaction->transaction_currency_id === $currency->id || $transaction->foreign_currency_id === $currency->id) {
return $recurrence;
}
if (array_any($recurrence->recurrenceTransactions, fn ($transaction) => $transaction->transaction_currency_id === $currency->id || $transaction->foreign_currency_id === $currency->id)) {
return $recurrence;
}
return null;
@@ -297,10 +295,8 @@ class ListController extends Controller
$collection = $unfiltered->filter(
static function (Rule $rule) use ($currency) { // @phpstan-ignore-line
/** @var RuleTrigger $trigger */
foreach ($rule->ruleTriggers as $trigger) {
if ('currency_is' === $trigger->trigger_type && $currency->name === $trigger->trigger_value) {
return $rule;
}
if (array_any($rule->ruleTriggers, fn ($trigger) => 'currency_is' === $trigger->trigger_type && $currency->name === $trigger->trigger_value)) {
return $rule;
}
return null;
@@ -27,13 +27,13 @@ namespace FireflyIII\Api\V1\Controllers\Models\TransactionLinkType;
use Illuminate\Support\Facades\Validator;
use FireflyIII\Api\V1\Controllers\Controller;
use FireflyIII\Api\V1\Requests\Models\TransactionLinkType\StoreRequest;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Repositories\LinkType\LinkTypeRepositoryInterface;
use FireflyIII\Repositories\User\UserRepositoryInterface;
use FireflyIII\Support\Http\Api\TransactionFilter;
use FireflyIII\Transformers\LinkTypeTransformer;
use FireflyIII\User;
use Illuminate\Http\JsonResponse;
use Illuminate\Validation\ValidationException;
use League\Fractal\Resource\Item;
/**
@@ -71,7 +71,7 @@ class StoreController extends Controller
*
* Store new object.
*
* @throws FireflyException
* @throws ValidationException
*/
public function store(StoreRequest $request): JsonResponse
{
@@ -35,6 +35,7 @@ use FireflyIII\Support\Http\Api\TransactionFilter;
use FireflyIII\Transformers\LinkTypeTransformer;
use FireflyIII\User;
use Illuminate\Http\JsonResponse;
use Illuminate\Validation\ValidationException;
use League\Fractal\Resource\Item;
/**
@@ -73,6 +74,7 @@ class UpdateController extends Controller
* Update object.
*
* @throws FireflyException
* @throws ValidationException
*/
public function update(UpdateRequest $request, LinkType $linkType): JsonResponse
{
@@ -30,6 +30,7 @@ use FireflyIII\Models\UserGroup;
use FireflyIII\Repositories\UserGroup\UserGroupRepositoryInterface;
use FireflyIII\Transformers\UserGroupTransformer;
use Illuminate\Http\JsonResponse;
use Illuminate\Support\Facades\Log;
class UpdateController extends Controller
{
@@ -54,7 +55,7 @@ class UpdateController extends Controller
public function update(UpdateRequest $request, UserGroup $userGroup): JsonResponse
{
app('log')->debug(sprintf('Now in %s', __METHOD__));
Log::debug(sprintf('Now in %s', __METHOD__));
$data = $request->getData();
$userGroup = $this->repository->update($userGroup, $data);
$userGroup->refresh();
@@ -34,6 +34,7 @@ use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Illuminate\Pagination\LengthAwarePaginator;
use Illuminate\Support\Facades\Log;
use League\Fractal\Pagination\IlluminatePaginatorAdapter;
use League\Fractal\Resource\Collection as FractalCollection;
@@ -71,7 +72,7 @@ class AccountController extends Controller
if ('' === $query || !in_array($field, $this->validFields, true)) {
return response(null, 422);
}
app('log')->debug(sprintf('Now in account search("%s", "%s")', $field, $query));
Log::debug(sprintf('Now in account search("%s", "%s")', $field, $query));
$types = $this->mapAccountTypes($type);
/** @var AccountSearch $search */
@@ -130,8 +130,6 @@ class BasicController extends Controller
$convertToNative = Amount::convertToNative();
$default = Amount::getNativeCurrency();
// prep some arrays:
$incomes = [];
$expenses = [];
$sums = [];
$return = [];
$currencies = [
@@ -24,6 +24,8 @@ declare(strict_types=1);
namespace FireflyIII\Api\V1\Controllers\System;
use FireflyIII\Support\Facades\FireflyConfig;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Validator;
use FireflyIII\Api\V1\Controllers\Controller;
use FireflyIII\Api\V1\Requests\System\UpdateRequest;
@@ -31,6 +33,7 @@ use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Repositories\User\UserRepositoryInterface;
use FireflyIII\Support\Binder\EitherConfigKey;
use Illuminate\Http\JsonResponse;
use Illuminate\Validation\ValidationException;
/**
* Class ConfigurationController
@@ -65,8 +68,8 @@ class ConfigurationController extends Controller
try {
$dynamicData = $this->getDynamicConfiguration();
} catch (FireflyException $e) {
app('log')->error($e->getMessage());
app('log')->error($e->getTraceAsString());
Log::error($e->getMessage());
Log::error($e->getTraceAsString());
throw new FireflyException('200030: Could not load config variables.', 0, $e);
}
@@ -92,13 +95,15 @@ class ConfigurationController extends Controller
/**
* Get all config values.
*
* @throws FireflyException
*/
private function getDynamicConfiguration(): array
{
$isDemoSite = app('fireflyconfig')->get('is_demo_site');
$updateCheck = app('fireflyconfig')->get('permission_update_check');
$lastCheck = app('fireflyconfig')->get('last_update_check');
$singleUser = app('fireflyconfig')->get('single_user_mode');
$isDemoSite = FireflyConfig::get('is_demo_site');
$updateCheck = FireflyConfig::get('permission_update_check');
$lastCheck = FireflyConfig::get('last_update_check');
$singleUser = FireflyConfig::get('single_user_mode');
return [
'is_demo_site' => $isDemoSite?->data,
@@ -153,6 +158,7 @@ class ConfigurationController extends Controller
* Update the configuration.
*
* @throws FireflyException
* @throws ValidationException
*/
public function update(UpdateRequest $request, string $name): JsonResponse
{
@@ -164,7 +170,7 @@ class ConfigurationController extends Controller
$data = $request->getAll();
$shortName = str_replace('configuration.', '', $name);
app('fireflyconfig')->set($shortName, $data['value']);
FireflyConfig::set($shortName, $data['value']);
// get updated config:
$newConfig = $this->getDynamicConfiguration();
@@ -28,6 +28,7 @@ use FireflyIII\Api\V1\Controllers\Controller;
use FireflyIII\Api\V1\Requests\System\CronRequest;
use FireflyIII\Support\Http\Controllers\CronRunner;
use Illuminate\Http\JsonResponse;
use Illuminate\Support\Facades\Log;
/**
* Class CronController
@@ -44,8 +45,8 @@ class CronController extends Controller
{
$config = $request->getAll();
app('log')->debug(sprintf('Now in %s', __METHOD__));
app('log')->debug(sprintf('Date is %s', $config['date']->toIsoString()));
Log::debug(sprintf('Now in %s', __METHOD__));
Log::debug(sprintf('Date is %s', $config['date']->toIsoString()));
$return = [];
$return['recurring_transactions'] = $this->runRecurring($config['force'], $config['date']);
$return['auto_budgets'] = $this->runAutoBudget($config['force'], $config['date']);
@@ -33,6 +33,7 @@ use FireflyIII\Transformers\UserTransformer;
use FireflyIII\User;
use Illuminate\Http\JsonResponse;
use Illuminate\Pagination\LengthAwarePaginator;
use Illuminate\Support\Facades\Log;
use League\Fractal\Pagination\IlluminatePaginatorAdapter;
use League\Fractal\Resource\Collection as FractalCollection;
use League\Fractal\Resource\Item;
@@ -174,7 +175,7 @@ class UserController extends Controller
// can only update 'blocked' when user is admin.
if (!$this->repository->hasRole(auth()->user(), 'owner')) {
app('log')->debug('Quietly drop fields "blocked" and "blocked_code" from request.');
Log::debug('Quietly drop fields "blocked" and "blocked_code" from request.');
unset($data['blocked'], $data['blocked_code']);
}
@@ -138,7 +138,7 @@ class ShowController extends Controller
throw new NotFoundHttpException('Webhooks are not enabled.');
}
app('log')->debug(sprintf('Now in triggerTransaction(%d, %d)', $webhook->id, $group->id));
Log::debug(sprintf('Now in triggerTransaction(%d, %d)', $webhook->id, $group->id));
Log::channel('audit')->info(sprintf('User triggers webhook #%d on transaction group #%d.', $webhook->id, $group->id));
/** @var MessageGeneratorInterface $engine */
@@ -155,7 +155,7 @@ class ShowController extends Controller
$engine->generateMessages();
// trigger event to send them:
app('log')->debug('send event RequestedSendWebhookMessages');
Log::debug('send event RequestedSendWebhookMessages');
event(new RequestedSendWebhookMessages());
return response()->json([], 204);
@@ -76,6 +76,6 @@ class SubmitController extends Controller
SendWebhookMessage::dispatch($message)->afterResponse();
}
return response()->json([]);
return response()->json();
}
}
@@ -54,8 +54,8 @@ class TransactionRequest extends FormRequest
'query' => json_decode($this->get('query'), true, 8, JSON_THROW_ON_ERROR),
];
} catch (JsonException $e) {
// dont really care. the validation should catch invalid json.
app('log')->error($e->getMessage());
// don't really care. the validation should catch invalid json.
Log::error($e->getMessage());
}
return $data;
@@ -47,7 +47,7 @@ class StoreRequest extends FormRequest
*/
public function getAll(): array
{
app('log')->debug('Raw fields in Bill StoreRequest', $this->all());
Log::debug('Raw fields in Bill StoreRequest', $this->all());
$fields = [
'name' => ['name', 'convertString'],
'amount_min' => ['amount_min', 'convertString'],
@@ -128,7 +128,6 @@ class StoreRequest extends FormRequest
$failed = $validator->fails();
} catch (TypeError $e) {
Log::error($e->getMessage());
$failed = false;
}
if ($failed) {
Log::channel('audit')->error(sprintf('Validation errors in %s', self::class), $validator->errors()->toArray());
@@ -76,7 +76,7 @@ class StoreRequest extends FormRequest
/**
* Returns the transaction data as it is found in the submitted data. It's a complex method according to code
* standards but it just has a lot of ??-statements because of the fields that may or may not exist.
* standards, but it just has a lot of ??-statements because of the fields that may or may not exist.
*/
private function getTransactionData(): array
{
@@ -122,7 +122,7 @@ class UpdateRequest extends FormRequest
/**
* Returns the transaction data as it is found in the submitted data. It's a complex method according to code
* standards but it just has a lot of ??-statements because of the fields that may or may not exist.
* standards, but it just has a lot of ??-statements because of the fields that may or may not exist.
*/
private function getTransactionData(): array
{
@@ -58,7 +58,7 @@ class StoreRequest extends FormRequest
*/
public function getAll(): array
{
app('log')->debug('get all data in TransactionStoreRequest');
Log::debug('get all data in TransactionStoreRequest');
return [
'group_title' => $this->convertString('group_title'),
@@ -175,7 +175,7 @@ class StoreRequest extends FormRequest
*/
public function rules(): array
{
app('log')->debug('Collect rules of TransactionStoreRequest');
Log::debug('Collect rules of TransactionStoreRequest');
$validProtocols = config('firefly.valid_url_protocols');
$locationRules = Location::requestRules([]);
@@ -276,9 +276,9 @@ class StoreRequest extends FormRequest
$this->validateTransactionArray($validator);
// must submit at least one transaction.
app('log')->debug('Now going to validateOneTransaction');
Log::debug('Now going to validateOneTransaction');
$this->validateOneTransaction($validator);
app('log')->debug('Now done with validateOneTransaction');
Log::debug('Now done with validateOneTransaction');
// all journals must have a description
$this->validateDescriptions($validator);
@@ -183,7 +183,7 @@ class UpdateRequest extends FormRequest
foreach ($this->dateFields as $fieldName) {
app('log')->debug(sprintf('Now at date field %s', $fieldName));
if (array_key_exists($fieldName, $transaction)) {
app('log')->debug(sprintf('New value: "%s"', (string) $transaction[$fieldName]));
Log::debug(sprintf('New value: "%s"', $transaction[$fieldName]));
$current[$fieldName] = $this->dateFromValue((string) $transaction[$fieldName]);
}
}
@@ -24,7 +24,6 @@ declare(strict_types=1);
namespace FireflyIII\Api\V1\Requests\Models\UserGroup;
use FireflyIII\Models\UserGroup;
use FireflyIII\Support\Request\ChecksLogin;
use FireflyIII\Support\Request\ConvertsDataTypes;
use Illuminate\Foundation\Http\FormRequest;
@@ -53,9 +52,6 @@ class UpdateRequest extends FormRequest
*/
public function rules(): array
{
/** @var UserGroup $userGroup */
$userGroup = $this->route()->parameter('userGroup');
return [
'title' => ['required', 'min:1', 'max:255'],
'native_currency_id' => 'exists:transaction_currencies,id',
+1 -2
View File
@@ -39,7 +39,6 @@ use League\Fractal\Resource\Collection as FractalCollection;
use League\Fractal\Resource\Item;
use League\Fractal\Serializer\JsonApiSerializer;
use Psr\Container\ContainerExceptionInterface;
use Psr\Container\NotFoundExceptionInterface;
use Symfony\Component\HttpFoundation\Exception\BadRequestException;
use Symfony\Component\HttpFoundation\ParameterBag;
@@ -82,7 +81,7 @@ class Controller extends BaseController
try {
$page = (int) request()->get('page');
} catch (ContainerExceptionInterface|NotFoundExceptionInterface $e) {
} catch (ContainerExceptionInterface) {
$page = 1;
}
@@ -53,7 +53,7 @@ class ListController extends Controller
*/
public function index(): JsonResponse
{
return response()->json([]);
return response()->json();
// throw new FireflyException('Needs refactoring, move to IndexController.');
// $pageSize = $this->parameters->get('limit');
// $dates = $request->getAll();
@@ -69,9 +69,8 @@ class UpdateController extends Controller
$transactionGroup = $this->groupRepository->update($transactionGroup, $data);
$applyRules = $data['apply_rules'] ?? true;
$fireWebhooks = $data['fire_webhooks'] ?? true;
$amountChanged = true;
event(new UpdatedTransactionGroup($transactionGroup, $applyRules, $fireWebhooks, $amountChanged));
event(new UpdatedTransactionGroup($transactionGroup, $applyRules, $fireWebhooks, true));
app('preferences')->mark();
/** @var User $admin */
@@ -31,6 +31,7 @@ use FireflyIII\Repositories\Currency\CurrencyRepositoryInterface;
use FireflyIII\Transformers\CurrencyTransformer;
use Illuminate\Http\JsonResponse;
use Illuminate\Pagination\LengthAwarePaginator;
use Illuminate\Support\Collection;
class IndexController extends Controller
{
@@ -56,6 +57,7 @@ class IndexController extends Controller
public function index(IndexRequest $request): JsonResponse
{
$settings = $request->getAll();
$currencies = new Collection();
if (true === $settings['enabled']) {
$currencies = $this->repository->get();
}
@@ -68,7 +68,7 @@ class UpdateRequest extends Request
#[Override]
public function getAll(): array
{
app('log')->debug(sprintf('Now in %s', __METHOD__));
Log::debug(sprintf('Now in %s', __METHOD__));
$this->integerFields = ['order', 'currency_id', 'foreign_currency_id', 'transaction_journal_id', 'source_id', 'destination_id', 'budget_id', 'category_id', 'bill_id', 'recurrence_id'];
$this->dateFields = ['date', 'interest_date', 'book_date', 'process_date', 'due_date', 'payment_date', 'invoice_date'];
$this->textareaFields = ['notes'];
@@ -101,7 +101,7 @@ class UpdateRequest extends Request
*/
private function getTransactionData(): array
{
app('log')->debug(sprintf('Now in %s', __METHOD__));
Log::debug(sprintf('Now in %s', __METHOD__));
$return = [];
/** @var null|array $transactions */
@@ -185,9 +185,9 @@ class UpdateRequest extends Request
private function getDateData(array $current, array $transaction): array
{
foreach ($this->dateFields as $fieldName) {
app('log')->debug(sprintf('Now at date field %s', $fieldName));
Log::debug(sprintf('Now at date field %s', $fieldName));
if (array_key_exists($fieldName, $transaction)) {
app('log')->debug(sprintf('New value: "%s"', (string) $transaction[$fieldName]));
Log::debug(sprintf('New value: "%s"', $transaction[$fieldName]));
$current[$fieldName] = $this->dateFromValue((string) $transaction[$fieldName]);
}
}
@@ -252,7 +252,7 @@ class UpdateRequest extends Request
#[Override]
public function rules(): array
{
app('log')->debug(sprintf('Now in %s', __METHOD__));
Log::debug(sprintf('Now in %s', __METHOD__));
$validProtocols = config('firefly.valid_url_protocols');
return [
@@ -336,7 +336,7 @@ class UpdateRequest extends Request
#[Override]
public function withValidator(Validator $validator): void
{
app('log')->debug('Now in withValidator');
Log::debug('Now in withValidator');
/** @var TransactionGroup $transactionGroup */
$transactionGroup = $this->route()->parameter('userGroupTransaction');
@@ -58,6 +58,7 @@ class CorrectsGroupAccounts extends Command
$handler = new UpdatedGroupEventHandler();
foreach ($groups as $groupId) {
$group = TransactionGroup::find($groupId);
// TODO in theory the "unifyAccounts" method could lead to the need for run recalculations.
$event = new UpdatedTransactionGroup($group, true, true, false);
$handler->unifyAccounts($event);
}
@@ -30,6 +30,7 @@ use FireflyIII\Enums\TransactionTypeEnum;
use FireflyIII\Models\Transaction;
use FireflyIII\Models\TransactionJournal;
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use FireflyIII\Support\Facades\Steam;
use FireflyIII\Support\Models\AccountBalanceCalculator;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\DB;
@@ -140,6 +141,7 @@ class CorrectsUnevenAmount extends Command
/** @var stdClass $entry */
foreach ($journals as $entry) {
$sum = (string) $entry->the_sum;
$sum = Steam::floatalize($sum);
if (!is_numeric($sum)
|| '' === $sum // @phpstan-ignore-line
|| str_contains($sum, 'e')
@@ -26,6 +26,7 @@ namespace FireflyIII\Console\Commands\Integrity;
use FireflyIII\Console\Commands\ShowsFriendlyMessages;
use FireflyIII\Repositories\User\UserRepositoryInterface;
use FireflyIII\Support\Facades\Steam;
use FireflyIII\User;
use Illuminate\Console\Command;
@@ -60,6 +61,8 @@ class ReportsSums extends Command
$foreign = (string) $user->transactions()->selectRaw('SUM(foreign_amount) as total')->value('total');
$sum = '' === $sum ? '0' : $sum;
$foreign = '' === $foreign ? '0' : $foreign;
$sum = Steam::floatalize($sum);
$foreign = Steam::floatalize($foreign);
$total = bcadd($sum, $foreign);
if (0 !== bccomp($total, '0')) {
@@ -87,6 +87,12 @@ class UpgradesMultiPiggyBanks extends Command
private function upgradePiggyBank(PiggyBank $piggyBank): void
{
if (null === $piggyBank->account) {
// #10432 account has been deleted, delete piggy bank.
$piggyBank->delete();
return;
}
$this->repository->setUser($piggyBank->account->user);
$this->accountRepository->setUser($piggyBank->account->user);
$repetition = $this->repository->getRepetition($piggyBank, true);
@@ -0,0 +1,16 @@
<?php
declare(strict_types=1);
namespace FireflyIII\Events\Model\PiggyBank;
use FireflyIII\Events\Event;
use FireflyIII\Models\PiggyBank;
use Illuminate\Queue\SerializesModels;
class ChangedName extends Event
{
use SerializesModels;
public function __construct(public PiggyBank $piggyBank, public string $oldName, public string $newName) {}
}
+1 -1
View File
@@ -37,5 +37,5 @@ class UpdatedTransactionGroup extends Event
/**
* Create a new event instance.
*/
public function __construct(public TransactionGroup $transactionGroup, public bool $applyRules, public bool $fireWebhooks, public bool $amountChanged) {}
public function __construct(public TransactionGroup $transactionGroup, public bool $applyRules, public bool $fireWebhooks, public bool $runRecalculations) {}
}
+11 -8
View File
@@ -58,11 +58,13 @@ use function Safe\parse_url;
*/
class Handler extends ExceptionHandler
{
public static ?Throwable $lastError = null;
/**
* @var array<int, class-string<Throwable>>
*/
protected $dontReport
= [
= [
AuthenticationException::class,
LaravelValidationException::class,
NotFoundHttpException::class,
@@ -123,7 +125,7 @@ class Handler extends ExceptionHandler
// somehow Laravel handler does not catch this:
app('log')->debug('Return JSON unauthenticated error.');
return response()->json(['message' => 'Unauthenticated', 'exception' => 'AuthenticationException'], 401);
return response()->json(['message' => $e->getMessage(), 'exception' => 'AuthenticationException'], 401);
}
if ($e instanceof OAuthServerException && $expectsJson) {
@@ -215,13 +217,14 @@ class Handler extends ExceptionHandler
#[Override]
public function report(Throwable $e): void
{
$doMailError = (bool) config('firefly.send_error_message');
self::$lastError = $e;
$doMailError = (bool) config('firefly.send_error_message');
if ($this->shouldntReportLocal($e) || !$doMailError) {
parent::report($e);
return;
}
$userData = [
$userData = [
'id' => 0,
'email' => 'unknown@example.com',
];
@@ -230,9 +233,9 @@ class Handler extends ExceptionHandler
$userData['email'] = auth()->user()->email;
}
$headers = request()->headers->all();
$headers = request()->headers->all();
$data = [
$data = [
'class' => $e::class,
'errorMessage' => $e->getMessage(),
'time' => Carbon::now()->format('r'),
@@ -250,8 +253,8 @@ class Handler extends ExceptionHandler
];
// create job that will mail.
$ipAddress = request()->ip() ?? '0.0.0.0';
$job = new MailError($userData, (string) config('firefly.site_owner'), $ipAddress, $data);
$ipAddress = request()->ip() ?? '0.0.0.0';
$job = new MailError($userData, (string) config('firefly.site_owner'), $ipAddress, $data);
dispatch($job);
parent::report($e);
+24 -14
View File
@@ -46,9 +46,9 @@ class PiggyBankFactory
{
use CreatesObjectGroups;
public User $user;
private AccountRepositoryInterface $accountRepository;
private CurrencyRepositoryInterface $currencyRepository;
public User $user;
private AccountRepositoryInterface $accountRepository;
private CurrencyRepositoryInterface $currencyRepository;
private PiggyBankRepositoryInterface $piggyBankRepository;
public function __construct()
@@ -78,7 +78,7 @@ class PiggyBankFactory
unset($piggyBankData['object_group_title'], $piggyBankData['transaction_currency_code'], $piggyBankData['transaction_currency_id'], $piggyBankData['accounts'], $piggyBankData['object_group_id'], $piggyBankData['notes']);
// validate amount:
if (array_key_exists('target_amount', $piggyBankData) && '' === (string) $piggyBankData['target_amount']) {
if (array_key_exists('target_amount', $piggyBankData) && '' === (string)$piggyBankData['target_amount']) {
$piggyBankData['target_amount'] = '0';
}
@@ -108,7 +108,7 @@ class PiggyBankFactory
}
}
// try also with ID
$objectGroupId = (int) ($data['object_group_id'] ?? 0);
$objectGroupId = (int)($data['object_group_id'] ?? 0);
if (0 !== $objectGroupId) {
$objectGroup = $this->findObjectGroupById($objectGroupId);
if ($objectGroup instanceof ObjectGroup) {
@@ -129,10 +129,10 @@ class PiggyBankFactory
$defaultCurrency = app('amount')->getNativeCurrency();
$currency = null;
if (array_key_exists('transaction_currency_code', $data)) {
$currency = $this->currencyRepository->findByCode((string) ($data['transaction_currency_code'] ?? ''));
$currency = $this->currencyRepository->findByCode((string)($data['transaction_currency_code'] ?? ''));
}
if (array_key_exists('transaction_currency_id', $data)) {
$currency = $this->currencyRepository->find((int) ($data['transaction_currency_id'] ?? 0));
$currency = $this->currencyRepository->find((int)($data['transaction_currency_id'] ?? 0));
}
$currency ??= $defaultCurrency;
@@ -141,8 +141,8 @@ class PiggyBankFactory
public function find(?int $piggyBankId, ?string $piggyBankName): ?PiggyBank
{
$piggyBankId = (int) $piggyBankId;
$piggyBankName = (string) $piggyBankName;
$piggyBankId = (int)$piggyBankId;
$piggyBankName = (string)$piggyBankName;
if ('' === $piggyBankName && 0 === $piggyBankId) {
return null;
}
@@ -221,7 +221,7 @@ class PiggyBankFactory
private function getMaxOrder(): int
{
return (int) $this->piggyBankRepository->getPiggyBanks()->max('order');
return (int)$this->piggyBankRepository->getPiggyBanks()->max('order');
}
@@ -230,12 +230,13 @@ class PiggyBankFactory
Log::debug(sprintf('Linking piggy bank #%d to %d accounts.', $piggyBank->id, count($accounts)), $accounts);
// collect current current_amount so the sync does not remove them.
// TODO this is a tedious check. Feels like a hack.
$toBeLinked = [];
$toBeLinked = [];
$oldSavedAmount = $this->piggyBankRepository->getCurrentAmount($piggyBank);
foreach ($piggyBank->accounts as $account) {
Log::debug(sprintf('Checking account #%d', $account->id));
foreach ($accounts as $info) {
Log::debug(sprintf(' Checking other account #%d', $info['account_id']));
if ((int) $account->id === (int) $info['account_id']) {
if ((int)$account->id === (int)$info['account_id']) {
$toBeLinked[$account->id] = ['current_amount' => $account->pivot->current_amount ?? '0'];
Log::debug(sprintf('Prefilled for account #%d with amount %s', $account->id, $account->pivot->current_amount ?? '0'));
}
@@ -244,9 +245,9 @@ class PiggyBankFactory
/** @var array $info */
foreach ($accounts as $info) {
$account = $this->accountRepository->find((int) ($info['account_id'] ?? 0));
$account = $this->accountRepository->find((int)($info['account_id'] ?? 0));
if (!$account instanceof Account) {
Log::debug(sprintf('Account #%d not found, skipping.', (int) ($info['account_id'] ?? 0)));
Log::debug(sprintf('Account #%d not found, skipping.', (int)($info['account_id'] ?? 0)));
continue;
}
@@ -290,7 +291,16 @@ class PiggyBankFactory
}
Log::debug(sprintf('Link information: %s', json_encode($toBeLinked)));
if (0 !== count($toBeLinked)) {
Log::debug('Syncing accounts to piggy bank.');
$piggyBank->accounts()->sync($toBeLinked);
$piggyBank->refresh();
$newSavedAmount = $this->piggyBankRepository->getCurrentAmount($piggyBank);
Log::debug(sprintf('Old saved amount: %s, new saved amount is %s', $oldSavedAmount, $newSavedAmount));
if (0 !== bccomp($oldSavedAmount, $newSavedAmount)) {
Log::debug('Amount changed, will create event for it.');
// create event for difference.
event(new ChangedAmount($piggyBank, bcsub($newSavedAmount, $oldSavedAmount), null, null));
}
}
if (0 === count($toBeLinked)) {
Log::warning('No accounts to link to piggy bank, will not change whatever is there now.');
@@ -24,6 +24,10 @@ declare(strict_types=1);
namespace FireflyIII\Handlers\Events\Model;
use FireflyIII\Events\Model\PiggyBank\ChangedName;
use FireflyIII\Models\Account;
use FireflyIII\Models\Rule;
use FireflyIII\Models\RuleAction;
use FireflyIII\Models\TransactionGroup;
use FireflyIII\Events\Model\PiggyBank\ChangedAmount;
use FireflyIII\Models\PiggyBankEvent;
@@ -33,6 +37,24 @@ use FireflyIII\Models\PiggyBankEvent;
*/
class PiggyBankEventHandler
{
public function changedPiggyBankName(ChangedName $event): void
{
// loop all accounts, collect all user's rules.
/** @var Account $account */
foreach ($event->piggyBank->accounts as $account) {
/** @var Rule $rule */
foreach ($account->user->rules as $rule) {
/** @var RuleAction $ruleAction */
foreach ($rule->ruleActions()->where('action_type', 'update_piggy')->get() as $ruleAction) {
if ($event->oldName === $ruleAction->action_value) {
$ruleAction->action_value = $event->newName;
$ruleAction->save();
}
}
}
}
}
public function changePiggyAmount(ChangedAmount $event): void
{
// find journal if group is present.
@@ -49,7 +49,7 @@ class UpdatedGroupEventHandler
$this->processRules($event);
$this->recalculateCredit($event);
$this->triggerWebhooks($event);
if ($event->amountChanged) {
if ($event->runRecalculations) {
$this->updateRunningBalance($event);
}
@@ -23,6 +23,7 @@ declare(strict_types=1);
namespace FireflyIII\Handlers\Events;
use Deprecated;
use Carbon\Carbon;
use FireflyIII\Events\RequestedVersionCheckStatus;
use FireflyIII\Exceptions\FireflyException;
@@ -42,9 +43,8 @@ class VersionCheckEventHandler
* Checks with GitHub to see if there is a new version.
*
* @throws FireflyException
*
* @deprecated ?
*/
#[Deprecated(message: '?')]
public function checkForUpdates(RequestedVersionCheckStatus $event): void
{
Log::debug('Now in checkForUpdates()');
+2 -3
View File
@@ -24,6 +24,7 @@ declare(strict_types=1);
namespace FireflyIII\Helpers\Report;
use Deprecated;
use Carbon\Carbon;
use FireflyIII\Enums\AccountTypeEnum;
use FireflyIII\Exceptions\FireflyException;
@@ -134,9 +135,7 @@ class NetWorth implements NetWorthInterface
$this->currencyRepos->setUserGroup($this->userGroup);
}
/**
* @deprecated
*/
#[Deprecated]
public function sumNetWorthByCurrency(Carbon $date): array
{
/**
+2 -2
View File
@@ -24,6 +24,7 @@ declare(strict_types=1);
namespace FireflyIII\Helpers\Report;
use Deprecated;
use Carbon\Carbon;
use FireflyIII\Models\UserGroup;
use FireflyIII\User;
@@ -53,8 +54,7 @@ interface NetWorthInterface
* TODO move to repository
*
* Same as above but cleaner function with less dependencies.
*
* @deprecated
*/
#[Deprecated]
public function sumNetWorthByCurrency(Carbon $date): array;
}
@@ -61,12 +61,12 @@ class ForgotPasswordController extends Controller
*
* @return Factory|RedirectResponse|View
*/
public function sendResetLinkEmail(Request $request, ?UserRepositoryInterface $repository = null)
public function sendResetLinkEmail(Request $request, UserRepositoryInterface $repository)
{
app('log')->info('Start of sendResetLinkEmail()');
if ('web' !== config('firefly.authentication_guard')) {
Log::info('Start of sendResetLinkEmail()');
if ('web' !== config('firefly.authentication_guard')) {
$message = sprintf('Cannot reset password when authenticating over "%s".', config('firefly.authentication_guard'));
app('log')->error($message);
Log::error($message);
return view('error', compact('message'));
}
@@ -89,7 +89,7 @@ class ForgotPasswordController extends Controller
// need to show to the user. Finally, we'll send out a proper response.
$result = $this->broker()->sendResetLink($request->only('email'));
if ('passwords.throttled' === $result) {
app('log')->error(sprintf('Cowardly refuse to send a password reset message to user #%d because the reset button has been throttled.', $user->id));
Log::error(sprintf('Cowardly refuse to send a password reset message to user #%d because the reset button has been throttled.', $user->id));
}
// always send the same response to the user:
@@ -223,7 +223,7 @@ class LoginController extends Controller
*
* @throws FireflyException
*/
public function showLoginForm(?Request $request = null)
public function showLoginForm(Request $request)
{
Log::channel('audit')->info('Show login form (1.1).');
@@ -91,7 +91,7 @@ class IndexController extends Controller
public function index(?Carbon $start = null, ?Carbon $end = null)
{
$this->abRepository->cleanup();
app('log')->debug(sprintf('Start of IndexController::index("%s", "%s")', $start?->format('Y-m-d'), $end?->format('Y-m-d')));
Log::debug(sprintf('Start of IndexController::index("%s", "%s")', $start?->format('Y-m-d'), $end?->format('Y-m-d')));
// collect some basic vars:
$range = app('navigation')->getViewRange(true);
@@ -199,12 +199,12 @@ class IndexController extends Controller
// get all budgets, and paginate them into $budgets.
$collection = $this->repository->getActiveBudgets();
$budgets = [];
app('log')->debug(sprintf('7) Start is "%s", end is "%s"', $start->format('Y-m-d H:i:s'), $end->format('Y-m-d H:i:s')));
Log::debug(sprintf('(getAllBudgets) Start is "%s", end is "%s"', $start->format('Y-m-d H:i:s'), $end->format('Y-m-d H:i:s')));
// complement budget with budget limits in range, and expenses in currency X in range.
/** @var Budget $current */
foreach ($collection as $current) {
app('log')->debug(sprintf('Working on budget #%d ("%s")', $current->id, $current->name));
Log::debug(sprintf('Working on budget #%d ("%s")', $current->id, $current->name));
$array = $current->toArray();
$array['spent'] = [];
$array['spent_total'] = [];
@@ -215,7 +215,7 @@ class IndexController extends Controller
/** @var BudgetLimit $limit */
foreach ($budgetLimits as $limit) {
app('log')->debug(sprintf('Working on budget limit #%d', $limit->id));
Log::debug(sprintf('Working on budget limit #%d', $limit->id));
$currency = $limit->transactionCurrency ?? $defaultCurrency;
$amount = app('steam')->bcround($limit->amount, $currency->decimal_places);
$array['budgeted'][] = [
@@ -225,14 +225,17 @@ class IndexController extends Controller
'start_date' => $limit->start_date->isoFormat($this->monthAndDayFormat),
'end_date' => $limit->end_date->isoFormat($this->monthAndDayFormat),
'in_range' => $limit->start_date->isSameDay($start) && $limit->end_date->isSameDay($end),
'total_days' => $limit->start_date->diffInDays($limit->end_date) + 1,
'currency_id' => $currency->id,
'currency_symbol' => $currency->symbol,
'currency_name' => $currency->name,
'currency_decimal_places' => $currency->decimal_places,
];
app('log')->debug(sprintf('The amount budgeted for budget limit #%d is %s %s', $limit->id, $currency->code, $amount));
Log::debug(sprintf('The amount budgeted for budget limit #%d is %s %s', $limit->id, $currency->code, $amount));
}
// #10463
/** @var TransactionCurrency $currency */
foreach ($currencies as $currency) {
$spentArr = $this->opsRepository->sumExpenses($start, $end, null, new Collection([$current]), $currency, false);
@@ -259,6 +262,8 @@ class IndexController extends Controller
/** @var array $budget */
foreach ($budgets as $budget) {
Log::debug(sprintf('Now working on budget #%d ("%s")', $budget['id'], $budget['name']));
/** @var array $spent */
foreach ($budget['spent'] as $spent) {
$currencyId = $spent['currency_id'];
+2 -2
View File
@@ -23,6 +23,7 @@ declare(strict_types=1);
namespace FireflyIII\Http\Controllers\Json;
use Deprecated;
use Carbon\Carbon;
use FireflyIII\Enums\AccountTypeEnum;
use FireflyIII\Enums\TransactionTypeEnum;
@@ -46,9 +47,8 @@ class BoxController extends Controller
/**
* Deprecated method, no longer in use.
*
* @deprecated
*/
#[Deprecated]
public function available(): JsonResponse
{
return response()->json([]);
@@ -75,13 +75,22 @@ class AmountController extends Controller
$totalSaved = $this->piggyRepos->getCurrentAmount($piggyBank);
foreach ($piggyBank->accounts as $account) {
$leftOnAccount = $this->piggyRepos->leftOnAccount($piggyBank, $account, $date);
$savedSoFar = $this->piggyRepos->getCurrentAmount($piggyBank, $account);
$leftToSave = bcsub($piggyBank->target_amount, $savedSoFar);
$leftToSave = bcsub($piggyBank->target_amount, $totalSaved);
$maxAmount = 0 === bccomp($piggyBank->target_amount, '0') ? $leftOnAccount : min($leftOnAccount, $leftToSave);
Log::debug(sprintf(
'Account "%s", left on account "%s", saved so far "%s", left to save "%s", max amount "%s".',
$account->name,
$leftOnAccount,
$totalSaved,
$leftToSave,
$maxAmount,
));
$accounts[] = [
'account' => $account,
'left_on_account' => $leftOnAccount,
'saved_so_far' => $savedSoFar,
'total_saved' => $totalSaved,
'left_to_save' => $leftToSave,
'max_amount' => $maxAmount,
];
@@ -100,18 +109,18 @@ class AmountController extends Controller
public function addMobile(PiggyBank $piggyBank)
{
/** @var Carbon $date */
$date = session('end', today(config('app.timezone')));
$accounts = [];
$total = '0';
$date = session('end', today(config('app.timezone')));
$accounts = [];
$total = '0';
$totalSaved = $this->piggyRepos->getCurrentAmount($piggyBank);
foreach ($piggyBank->accounts as $account) {
$leftOnAccount = $this->piggyRepos->leftOnAccount($piggyBank, $account, $date);
$savedSoFar = $this->piggyRepos->getCurrentAmount($piggyBank, $account);
$leftToSave = bcsub($piggyBank->target_amount, $savedSoFar);
$leftToSave = bcsub($piggyBank->target_amount, $totalSaved);
$maxAmount = 0 === bccomp($piggyBank->target_amount, '0') ? $leftOnAccount : min($leftOnAccount, $leftToSave);
$accounts[] = [
'account' => $account,
'left_on_account' => $leftOnAccount,
'saved_so_far' => $savedSoFar,
'total_saved' => $totalSaved,
'left_to_save' => $leftToSave,
'max_amount' => $maxAmount,
];
@@ -63,6 +63,14 @@ class EditController extends Controller
);
}
public function resetHistory(PiggyBank $piggyBank): RedirectResponse
{
$this->piggyRepos->resetHistory($piggyBank);
session()->flash('success', (string) trans('firefly.piggy_history_reset'));
return redirect(route('piggy-banks.show', [$piggyBank->id]));
}
/**
* Edit a piggy bank.
*
@@ -34,6 +34,7 @@ use FireflyIII\TransactionRules\Engine\RuleEngineInterface;
use FireflyIII\User;
use Illuminate\Contracts\View\Factory;
use Illuminate\Http\RedirectResponse;
use Illuminate\Support\Collection;
use Illuminate\View\View;
/**
@@ -75,7 +76,6 @@ class ExecutionController extends Controller
$accounts = implode(',', $request->get('accounts'));
$startDate = new Carbon($request->get('start'));
$endDate = new Carbon($request->get('end'));
$rules = $this->ruleGroupRepository->getActiveRules($ruleGroup);
// create new rule engine:
$newRuleEngine = app(RuleEngineInterface::class);
$newRuleEngine->setUser($user);
@@ -86,7 +86,9 @@ class ExecutionController extends Controller
$newRuleEngine->addOperator(['type' => 'account_id', 'value' => $accounts]);
// set rules:
$newRuleEngine->setRules($rules);
// #10427, file rule group and not the set of rules.
$collection = new Collection([$ruleGroup]);
$newRuleEngine->setRuleGroups($collection);
$newRuleEngine->fire();
// Tell the user that the job is queued
@@ -292,7 +292,7 @@ class ConvertController extends Controller
$group->refresh();
session()->flash('success', (string) trans('firefly.converted_to_'.$destinationType->type));
event(new UpdatedTransactionGroup($group, true, true, false));
event(new UpdatedTransactionGroup($group, true, true, true));
return redirect(route('transactions.show', [$group->id]));
}
@@ -191,15 +191,15 @@ class MassController extends Controller
*/
private function updateJournal(int $journalId, MassEditJournalRequest $request): void
{
$journal = $this->repository->find($journalId);
$journal = $this->repository->find($journalId);
if (!$journal instanceof TransactionJournal) {
throw new FireflyException(sprintf('Trying to edit non-existent or deleted journal #%d', $journalId));
}
$service = app(JournalUpdateService::class);
$service = app(JournalUpdateService::class);
// for each field, call the update service.
$service->setTransactionJournal($journal);
$data = [
$data = [
'date' => $this->getDateFromRequest($request, $journal->id, 'date'),
'description' => $this->getStringFromRequest($request, $journal->id, 'description'),
'source_id' => $this->getIntFromRequest($request, $journal->id, 'source_id'),
@@ -217,8 +217,8 @@ class MassController extends Controller
$service->setData($data);
$service->update();
// trigger rules
$amountChanged = $service->isAmountChanged();
event(new UpdatedTransactionGroup($journal->transactionGroup, true, true, $amountChanged));
$runRecalculations = $service->isCompareHashChanged();
event(new UpdatedTransactionGroup($journal->transactionGroup, true, true, $runRecalculations));
}
private function getDateFromRequest(MassEditJournalRequest $request, int $journalId, string $key): ?Carbon
+1 -1
View File
@@ -178,7 +178,7 @@ class Kernel extends HttpKernel
'api' => [
AcceptHeaders::class,
EnsureFrontendRequestsAreStateful::class,
'auth:api,sanctum',
'auth:api',
'bindings',
],
// do only bindings, no auth
+11 -4
View File
@@ -26,10 +26,12 @@ namespace FireflyIII\Http\Middleware;
use Closure;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Exceptions\Handler;
use FireflyIII\User;
use Illuminate\Auth\AuthenticationException;
use Illuminate\Contracts\Auth\Factory as Auth;
use Illuminate\Http\Request;
use League\OAuth2\Server\Exception\OAuthServerException;
/**
* Class Authenticate
@@ -84,6 +86,7 @@ class Authenticate
if ($this->auth->check()) {
// do an extra check on user object.
/** @noinspection PhpUndefinedMethodInspection */
/** @var User $user */
$user = $this->auth->authenticate();
$this->validateBlockedUser($user, $guards);
@@ -94,9 +97,6 @@ class Authenticate
}
foreach ($guards as $guard) {
if ('api' !== $guard) {
$this->auth->guard($guard)->authenticate();
}
$result = $this->auth->guard($guard)->check();
if ($result) {
$user = $this->auth->guard($guard)->user();
@@ -107,7 +107,14 @@ class Authenticate
}
}
throw new AuthenticationException('Unauthenticated.', $guards);
// this is a massive hack, but if the hander has the oauth exception
// at this point we can report its error instead of a generic one.
$message = 'Unauthenticated.';
if (Handler::$lastError instanceof OAuthServerException) {
$message = Handler::$lastError->getHint();
}
throw new AuthenticationException($message, $guards);
}
/**
@@ -24,7 +24,6 @@ declare(strict_types=1);
namespace FireflyIII\Http\Requests;
use Illuminate\Contracts\Validation\Validator;
use Carbon\Carbon;
use FireflyIII\Support\Request\ChecksLogin;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Support\Facades\Log;
@@ -41,15 +40,9 @@ class SelectTransactionsRequest extends FormRequest
*/
public function rules(): array
{
// fixed
/** @var Carbon $sessionFirst */
$sessionFirst = clone session('first');
$first = $sessionFirst->subDay()->format('Y-m-d');
$today = today(config('app.timezone'))->addDay()->format('Y-m-d');
return [
'start' => 'required|date|after:'.$first,
'end' => 'required|date|before:'.$today,
'start' => 'required|date|after:1900-01-01|before:2099-12-31|before:end|required_with:end',
'end' => 'required|date|after:1900-01-01|before:2099-12-31|after:start|required_with:start',
'accounts' => 'required',
'accounts.*' => 'required|exists:accounts,id|belongsToUser:accounts',
];
@@ -67,9 +67,10 @@ class UserFailedLoginAttempt extends Notification
{
$settings = ReturnsSettings::getSettings('ntfy', 'user', $notifiable);
$message = new Message();
$ip = Request::ip();
$message->topic($settings['ntfy_topic']);
$message->title((string) trans('email.failed_login_subject'));
$message->body((string) trans('email.failed_login_message', ['email' => $this->user->email]));
$message->body((string) trans('email.failed_login_message', ['ip' => $ip, 'email' => $this->user->email]));
return $message;
}
@@ -79,7 +80,9 @@ class UserFailedLoginAttempt extends Notification
*/
public function toPushover(User $notifiable): PushoverMessage
{
return PushoverMessage::create((string) trans('email.failed_login_message', ['email' => $this->user->email]))
$ip = Request::ip();
return PushoverMessage::create((string) trans('email.failed_login_message', ['ip' => $ip, 'email' => $this->user->email]))
->title((string) trans('email.failed_login_subject'))
;
}
@@ -89,7 +92,8 @@ class UserFailedLoginAttempt extends Notification
*/
public function toSlack(User $notifiable): SlackMessage
{
$message = (string) trans('email.failed_login_message', ['email' => $this->user->email]);
$ip = Request::ip();
$message = (string) trans('email.failed_login_message', ['ip' => $ip, 'email' => $this->user->email]);
return new SlackMessage()->content($message);
}
+4
View File
@@ -31,6 +31,7 @@ use FireflyIII\Events\Model\BudgetLimit\Created;
use FireflyIII\Events\Model\BudgetLimit\Deleted;
use FireflyIII\Events\Model\BudgetLimit\Updated;
use FireflyIII\Events\Model\PiggyBank\ChangedAmount;
use FireflyIII\Events\Model\PiggyBank\ChangedName;
use FireflyIII\Events\Model\Rule\RuleActionFailedOnArray;
use FireflyIII\Events\Model\Rule\RuleActionFailedOnObject;
use FireflyIII\Events\NewVersionAvailable;
@@ -210,6 +211,9 @@ class EventServiceProvider extends ServiceProvider
ChangedAmount::class => [
'FireflyIII\Handlers\Events\Model\PiggyBankEventHandler@changePiggyAmount',
],
ChangedName::class => [
'FireflyIII\Handlers\Events\Model\PiggyBankEventHandler@changedPiggyBankName',
],
// budget related events: CRUD budget limit
Created::class => [
@@ -24,6 +24,7 @@ declare(strict_types=1);
namespace FireflyIII\Repositories\Budget;
use Deprecated;
use Carbon\Carbon;
use FireflyIII\Models\AvailableBudget;
use FireflyIII\Models\TransactionCurrency;
@@ -205,9 +206,7 @@ class AvailableBudgetRepository implements AvailableBudgetRepositoryInterface, U
;
}
/**
* @deprecated
*/
#[Deprecated]
public function setAvailableBudget(TransactionCurrency $currency, Carbon $start, Carbon $end, string $amount): AvailableBudget
{
/** @var null|AvailableBudget */
@@ -24,6 +24,7 @@ declare(strict_types=1);
namespace FireflyIII\Repositories\Budget;
use Deprecated;
use Carbon\Carbon;
use FireflyIII\Enums\UserRoleEnum;
use FireflyIII\Models\AvailableBudget;
@@ -66,9 +67,7 @@ interface AvailableBudgetRepositoryInterface
*/
public function get(?Carbon $start = null, ?Carbon $end = null): Collection;
/**
* @deprecated
*/
#[Deprecated]
public function getAvailableBudget(TransactionCurrency $currency, Carbon $start, Carbon $end): string;
public function getAvailableBudgetWithCurrency(Carbon $start, Carbon $end): array;
@@ -90,9 +89,7 @@ interface AvailableBudgetRepositoryInterface
*/
public function getByCurrencyDate(Carbon $start, Carbon $end, TransactionCurrency $currency): ?AvailableBudget;
/**
* @deprecated
*/
#[Deprecated]
public function setAvailableBudget(TransactionCurrency $currency, Carbon $start, Carbon $end, string $amount): AvailableBudget;
public function store(array $data): ?AvailableBudget;
@@ -24,6 +24,7 @@ declare(strict_types=1);
namespace FireflyIII\Repositories\Budget;
use Deprecated;
use Carbon\Carbon;
use FireflyIII\Enums\UserRoleEnum;
use FireflyIII\Models\TransactionCurrency;
@@ -44,9 +45,7 @@ use Illuminate\Support\Collection;
*/
interface NoBudgetRepositoryInterface
{
/**
* @deprecated
*/
#[Deprecated]
public function getNoBudgetPeriodReport(Collection $accounts, Carbon $start, Carbon $end): array;
public function sumExpenses(Carbon $start, Carbon $end, ?Collection $accounts = null, ?TransactionCurrency $currency = null): array;
@@ -24,6 +24,7 @@ declare(strict_types=1);
namespace FireflyIII\Repositories\Budget;
use Deprecated;
use Carbon\Carbon;
use FireflyIII\Enums\TransactionTypeEnum;
use FireflyIII\Helpers\Collector\GroupCollectorInterface;
@@ -74,9 +75,8 @@ class OperationsRepository implements OperationsRepositoryInterface, UserGroupIn
/**
* This method is being used to generate the budget overview in the year/multi-year report. Its used
* in both the year/multi-year budget overview AND in the accompanying chart.
*
* @deprecated
*/
#[Deprecated]
public function getBudgetPeriodReport(Collection $budgets, Collection $accounts, Carbon $start, Carbon $end): array
{
$carbonFormat = app('navigation')->preferredCarbonFormat($start, $end);
@@ -204,7 +204,7 @@ class OperationsRepository implements OperationsRepositoryInterface, UserGroupIn
?TransactionCurrency $currency = null,
bool $convertToNative = false
): array {
Log::debug(sprintf('Start of %s(date, date, array, array, "%s", "%s").', __METHOD__, $currency?->code, var_export($convertToNative, true)));
Log::debug(sprintf('Start of %s(date, date, array, array, "%s", %s).', __METHOD__, $currency?->code, var_export($convertToNative, true)));
// 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.
// 2024-12-24 disable the exclusion for now.
@@ -24,6 +24,7 @@ declare(strict_types=1);
namespace FireflyIII\Repositories\Budget;
use Deprecated;
use Carbon\Carbon;
use FireflyIII\Enums\UserRoleEnum;
use FireflyIII\Models\Budget;
@@ -51,9 +52,7 @@ interface OperationsRepositoryInterface
*/
public function budgetedPerDay(Budget $budget): string;
/**
* @deprecated
*/
#[Deprecated]
public function getBudgetPeriodReport(Collection $budgets, Collection $accounts, Carbon $start, Carbon $end): array;
/**
@@ -71,6 +70,7 @@ interface OperationsRepositoryInterface
Carbon $end,
?Collection $accounts = null,
?Collection $budgets = null,
?TransactionCurrency $currency = null
?TransactionCurrency $currency = null,
bool $convertToNative = false
): array;
}
@@ -25,6 +25,7 @@ declare(strict_types=1);
namespace FireflyIII\Repositories\PiggyBank;
use FireflyIII\Events\Model\PiggyBank\ChangedAmount;
use FireflyIII\Events\Model\PiggyBank\ChangedName;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Factory\PiggyBankFactory;
use FireflyIII\Models\Account;
@@ -66,7 +67,7 @@ trait ModifiesPiggyBanks
{
$currentAmount = $this->getCurrentAmount($piggyBank, $account);
$pivot = $piggyBank->accounts()->where('accounts.id', $account->id)->first()->pivot;
$pivot->current_amount = bcsub((string) $currentAmount, $amount);
$pivot->current_amount = bcsub((string)$currentAmount, $amount);
$pivot->native_current_amount = null;
// also update native_current_amount.
@@ -89,7 +90,7 @@ trait ModifiesPiggyBanks
{
$currentAmount = $this->getCurrentAmount($piggyBank, $account);
$pivot = $piggyBank->accounts()->where('accounts.id', $account->id)->first()->pivot;
$pivot->current_amount = bcadd((string) $currentAmount, $amount);
$pivot->current_amount = bcadd((string)$currentAmount, $amount);
$pivot->native_current_amount = null;
// also update native_current_amount.
@@ -121,13 +122,13 @@ trait ModifiesPiggyBanks
if (0 !== bccomp($piggyBank->target_amount, '0')) {
$leftToSave = bcsub($piggyBank->target_amount, (string) $savedSoFar);
$maxAmount = 1 === bccomp((string) $leftOnAccount, $leftToSave) ? $leftToSave : $leftOnAccount;
$leftToSave = bcsub($piggyBank->target_amount, (string)$savedSoFar);
$maxAmount = 1 === bccomp((string)$leftOnAccount, $leftToSave) ? $leftToSave : $leftOnAccount;
Log::debug(sprintf('Left to save: %s', $leftToSave));
Log::debug(sprintf('Maximum amount: %s', $maxAmount));
}
$compare = bccomp($amount, (string) $maxAmount);
$compare = bccomp($amount, (string)$maxAmount);
$result = $compare <= 0;
Log::debug(sprintf('Compare <= 0? %d, so canAddAmount is %s', $compare, var_export($result, true)));
@@ -139,7 +140,7 @@ trait ModifiesPiggyBanks
{
$savedSoFar = $this->getCurrentAmount($piggyBank, $account);
return bccomp($amount, (string) $savedSoFar) <= 0;
return bccomp($amount, (string)$savedSoFar) <= 0;
}
/**
@@ -170,7 +171,7 @@ trait ModifiesPiggyBanks
if (1 === bccomp($amount, $max) && 0 !== bccomp($piggyBank->target_amount, '0')) {
$amount = $max;
}
$difference = bcsub($amount, (string) $repetition->current_amount);
$difference = bcsub($amount, (string)$repetition->current_amount);
$repetition->current_amount = $amount;
$repetition->save();
@@ -211,12 +212,12 @@ trait ModifiesPiggyBanks
{
$piggyBank = $this->updateProperties($piggyBank, $data);
if (array_key_exists('notes', $data)) {
$this->updateNote($piggyBank, (string) $data['notes']);
$this->updateNote($piggyBank, (string)$data['notes']);
}
// update the order of the piggy bank:
$oldOrder = $piggyBank->order;
$newOrder = (int) ($data['order'] ?? $oldOrder);
$newOrder = (int)($data['order'] ?? $oldOrder);
if ($oldOrder !== $newOrder) {
$this->setOrder($piggyBank, $newOrder);
}
@@ -233,9 +234,9 @@ trait ModifiesPiggyBanks
// if the piggy bank is now smaller than the sum of the money saved,
// remove money from all accounts until the piggy bank is the right amount.
$currentAmount = $this->getCurrentAmount($piggyBank);
if (1 === bccomp((string) $currentAmount, (string) $piggyBank->target_amount) && 0 !== bccomp((string) $piggyBank->target_amount, '0')) {
if (1 === bccomp((string)$currentAmount, (string)$piggyBank->target_amount) && 0 !== bccomp((string)$piggyBank->target_amount, '0')) {
Log::debug(sprintf('Current amount is %s, target amount is %s', $currentAmount, $piggyBank->target_amount));
$difference = bcsub((string) $piggyBank->target_amount, (string) $currentAmount);
$difference = bcsub((string)$piggyBank->target_amount, (string)$currentAmount);
// an amount will be removed, create "negative" event:
// Log::debug(sprintf('ChangedAmount: is triggered with difference "%s"', $difference));
@@ -248,7 +249,7 @@ trait ModifiesPiggyBanks
// update using name:
if (array_key_exists('object_group_title', $data)) {
$objectGroupTitle = (string) $data['object_group_title'];
$objectGroupTitle = (string)$data['object_group_title'];
if ('' !== $objectGroupTitle) {
$objectGroup = $this->findOrCreateObjectGroup($objectGroupTitle);
if (null !== $objectGroup) {
@@ -264,7 +265,7 @@ trait ModifiesPiggyBanks
// try also with ID:
if (array_key_exists('object_group_id', $data)) {
$objectGroupId = (int) ($data['object_group_id'] ?? 0);
$objectGroupId = (int)($data['object_group_id'] ?? 0);
if (0 !== $objectGroupId) {
$objectGroup = $this->findObjectGroupById($objectGroupId);
if (null !== $objectGroup) {
@@ -282,6 +283,7 @@ trait ModifiesPiggyBanks
private function updateProperties(PiggyBank $piggyBank, array $data): PiggyBank
{
if (array_key_exists('name', $data) && '' !== $data['name']) {
event(new ChangedName($piggyBank, $piggyBank->name, $data['name']));
$piggyBank->name = $data['name'];
}
if (array_key_exists('transaction_currency_id', $data) && is_int($data['transaction_currency_id'])) {
@@ -366,14 +368,14 @@ trait ModifiesPiggyBanks
foreach ($piggyBank->accounts as $account) {
$current = $account->pivot->current_amount;
// if this account contains more than the amount, remove the amount and return.
if (1 === bccomp((string) $current, $amount)) {
if (1 === bccomp((string)$current, $amount)) {
$this->removeAmount($piggyBank, $account, $amount);
return;
}
// if this account contains less than the amount, remove the current amount, update the amount and continue.
$this->removeAmount($piggyBank, $account, $current);
$amount = bcsub($amount, (string) $current);
$amount = bcsub($amount, (string)$current);
}
}
}
@@ -23,6 +23,7 @@ declare(strict_types=1);
namespace FireflyIII\Repositories\PiggyBank;
use FireflyIII\Events\Model\PiggyBank\ChangedAmount;
use FireflyIII\User;
use Carbon\Carbon;
use FireflyIII\Exceptions\FireflyException;
@@ -275,7 +276,7 @@ class PiggyBankRepository implements PiggyBankRepositoryInterface, UserGroupInte
$amount = '' === $amount ? '0' : $amount;
$sum = bcadd($sum, $amount);
}
// Log::debug(sprintf('Current amount in piggy bank #%d ("%s") is %s', $piggyBank->id, $piggyBank->name, $sum));
Log::debug(sprintf('Current amount in piggy bank #%d ("%s") is %s', $piggyBank->id, $piggyBank->name, $sum));
return $sum;
}
@@ -438,4 +439,14 @@ class PiggyBankRepository implements PiggyBankRepositoryInterface, UserGroupInte
return $search->take($limit)->get(['piggy_banks.*']);
}
public function resetHistory(PiggyBank $piggyBank): void
{
$piggyBank->piggyBankEvents()->delete();
foreach ($piggyBank->accounts as $account) {
if (0 !== bccomp('0', (string) $account->pivot->current_amount)) {
event(new ChangedAmount($piggyBank, $account->pivot->current_amount, null, null));
}
}
}
}
@@ -47,6 +47,8 @@ use Illuminate\Support\Collection;
*/
interface PiggyBankRepositoryInterface
{
public function resetHistory(PiggyBank $piggyBank): void;
public function addAmount(PiggyBank $piggyBank, Account $account, string $amount, ?TransactionJournal $journal = null): bool;
public function addAmountToPiggyBank(PiggyBank $piggyBank, string $amount, TransactionJournal $journal): void;
@@ -217,7 +217,7 @@ class TransactionGroupRepository implements TransactionGroupRepositoryInterface,
'link' => $entry->outward,
'group' => $entry->destination->transaction_group_id,
'description' => $entry->destination->description,
'editable' => 1 === (int) $entry->editable,
'editable' => 1 === (int)$entry->editable,
'amount' => $amount,
'foreign_amount' => $foreignAmount,
];
@@ -230,7 +230,7 @@ class TransactionGroupRepository implements TransactionGroupRepositoryInterface,
'link' => $entry->inward,
'group' => $entry->source->transaction_group_id,
'description' => $entry->source->description,
'editable' => 1 === (int) $entry->editable,
'editable' => 1 === (int)$entry->editable,
'amount' => $amount,
'foreign_amount' => $foreignAmount,
];
@@ -264,7 +264,7 @@ class TransactionGroupRepository implements TransactionGroupRepositoryInterface,
if (null === $transaction->foreign_amount || '' === $transaction->foreign_amount) {
return '';
}
if (0 === bccomp('0', (string) $transaction->foreign_amount)) {
if (0 === bccomp('0', (string)$transaction->foreign_amount)) {
return '';
}
$currency = $transaction->foreignCurrency;
@@ -305,7 +305,7 @@ class TransactionGroupRepository implements TransactionGroupRepositoryInterface,
$return = [];
foreach ($query as $row) {
$return[$row->name] = new Carbon(json_decode((string) $row->data, true, 512, JSON_THROW_ON_ERROR));
$return[$row->name] = new Carbon(json_decode((string)$row->data, true, 512, JSON_THROW_ON_ERROR));
}
return new NullArrayObject($return);
@@ -325,7 +325,7 @@ class TransactionGroupRepository implements TransactionGroupRepositoryInterface,
$return = [];
foreach ($query as $row) {
$return[$row->name] = json_decode((string) $row->data);
$return[$row->name] = json_decode((string)$row->data);
}
return new NullArrayObject($return);
@@ -433,20 +433,22 @@ class TransactionGroupRepository implements TransactionGroupRepositoryInterface,
return $service->update($transactionGroup, $data);
}
public function getTotalAmount(TransactionGroup $group): string
public function getCompareHash(TransactionGroup $group): string
{
$sum = '0';
$sum = '0';
$names = '';
/** @var TransactionJournal $journal */
foreach ($group->transactionJournals as $journal) {
/** @var Transaction $transaction */
foreach ($journal->transactions as $transaction) {
if (-1 === bccomp('0', (string) $transaction->amount)) {
$sum = bcadd($sum, $transaction->amount);
if (-1 === bccomp('0', (string)$transaction->amount)) {
$sum = bcadd($sum, (string) $transaction->amount);
$names = sprintf('%s%s', $names, $transaction->account->name);
}
}
}
return $sum;
return hash('sha256', sprintf('%s-%s', $names, $sum));
}
}
@@ -49,7 +49,10 @@ interface TransactionGroupRepositoryInterface
{
public function countAttachments(int $journalId): int;
public function getTotalAmount(TransactionGroup $group): string;
/**
* Small method that returns a hash that can be used to compare two transaction groups.
*/
public function getCompareHash(TransactionGroup $group): string;
public function destroy(TransactionGroup $group): void;
@@ -24,6 +24,7 @@ declare(strict_types=1);
namespace FireflyIII\Services\Internal\Support;
use Deprecated;
use Carbon\Carbon;
use FireflyIII\Enums\AccountTypeEnum;
use FireflyIII\Exceptions\DuplicateTransactionException;
@@ -193,8 +194,8 @@ trait AccountServiceTrait
/**
* @throws FireflyException
* *
* @deprecated
*/
#[Deprecated]
protected function createOBGroup(Account $account, array $data): TransactionGroup
{
app('log')->debug('Now going to create an OB group.');
@@ -43,6 +43,7 @@ use FireflyIII\Repositories\Bill\BillRepositoryInterface;
use FireflyIII\Repositories\Budget\BudgetRepositoryInterface;
use FireflyIII\Repositories\Category\CategoryRepositoryInterface;
use FireflyIII\Repositories\Currency\CurrencyRepositoryInterface;
use FireflyIII\Repositories\TransactionGroup\TransactionGroupRepositoryInterface;
use FireflyIII\Services\Internal\Support\JournalServiceTrait;
use FireflyIII\Support\Facades\FireflyConfig;
use FireflyIII\Support\NullArrayObject;
@@ -60,6 +61,7 @@ class JournalUpdateService
private BillRepositoryInterface $billRepository;
private CurrencyRepositoryInterface $currencyRepository;
private TransactionGroupRepositoryInterface $transactionGroupRepository;
private array $data;
private ?Account $destinationAccount;
private ?Transaction $destinationTransaction;
@@ -69,26 +71,27 @@ class JournalUpdateService
private ?Transaction $sourceTransaction;
private ?TransactionGroup $transactionGroup;
private ?TransactionJournal $transactionJournal;
private bool $amountChanged = false;
private string $startCompareHash = '';
/**
* JournalUpdateService constructor.
*/
public function __construct()
{
$this->destinationAccount = null;
$this->destinationTransaction = null;
$this->sourceAccount = null;
$this->sourceTransaction = null;
$this->transactionGroup = null;
$this->transactionJournal = null;
$this->billRepository = app(BillRepositoryInterface::class);
$this->categoryRepository = app(CategoryRepositoryInterface::class);
$this->budgetRepository = app(BudgetRepositoryInterface::class);
$this->tagFactory = app(TagFactory::class);
$this->accountRepository = app(AccountRepositoryInterface::class);
$this->currencyRepository = app(CurrencyRepositoryInterface::class);
$this->metaString = [
$this->destinationAccount = null;
$this->destinationTransaction = null;
$this->sourceAccount = null;
$this->sourceTransaction = null;
$this->transactionGroup = null;
$this->transactionJournal = null;
$this->billRepository = app(BillRepositoryInterface::class);
$this->categoryRepository = app(CategoryRepositoryInterface::class);
$this->budgetRepository = app(BudgetRepositoryInterface::class);
$this->tagFactory = app(TagFactory::class);
$this->accountRepository = app(AccountRepositoryInterface::class);
$this->currencyRepository = app(CurrencyRepositoryInterface::class);
$this->transactionGroupRepository = app(TransactionGroupRepositoryInterface::class);
$this->metaString = [
'sepa_cc',
'sepa_ct_op',
'sepa_ct_id',
@@ -103,7 +106,7 @@ class JournalUpdateService
'external_id',
'external_url',
];
$this->metaDate = ['interest_date', 'book_date', 'process_date', 'due_date', 'payment_date',
$this->metaDate = ['interest_date', 'book_date', 'process_date', 'due_date', 'payment_date',
'invoice_date', ];
}
@@ -120,10 +123,12 @@ class JournalUpdateService
$this->budgetRepository->setUser($transactionGroup->user);
$this->tagFactory->setUser($transactionGroup->user);
$this->accountRepository->setUser($transactionGroup->user);
$this->transactionGroupRepository->setUser($transactionGroup->user);
$this->destinationAccount = null;
$this->destinationTransaction = null;
$this->sourceAccount = null;
$this->sourceTransaction = null;
$this->startCompareHash = $this->transactionGroupRepository->getCompareHash($transactionGroup);
}
public function setTransactionJournal(TransactionJournal $transactionJournal): void
@@ -675,7 +680,6 @@ class JournalUpdateService
return;
}
$origSourceTransaction = $this->getSourceTransaction();
$this->amountChanged = 0 !== bccomp($origSourceTransaction->amount, app('steam')->negative($amount));
$origSourceTransaction->amount = app('steam')->negative($amount);
$origSourceTransaction->balance_dirty = true;
$origSourceTransaction->save();
@@ -818,8 +822,19 @@ class JournalUpdateService
return false;
}
public function isAmountChanged(): bool
public function isCompareHashChanged(): bool
{
return $this->amountChanged;
Log::debug(sprintf('Now in %s', __METHOD__));
$compareHash = hash('sha256', sprintf('%s', Carbon::now()->getTimestamp()));
if (!$this->transactionGroup instanceof TransactionGroup) {
$compareHash = $this->transactionGroupRepository->getCompareHash($this->transactionJournal->transactionGroup);
}
if ($this->transactionGroup instanceof TransactionGroup) {
$this->transactionGroupRepository->getCompareHash($this->transactionGroup);
}
Log::debug(sprintf('Compare hash is "%s".', $compareHash));
Log::debug(sprintf('Start compare hash is "%s".', $this->startCompareHash));
return $compareHash !== $this->startCompareHash;
}
}
+4 -9
View File
@@ -23,6 +23,7 @@ declare(strict_types=1);
namespace FireflyIII\Support;
use Deprecated;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Models\Transaction;
use FireflyIII\Models\TransactionCurrency;
@@ -195,25 +196,19 @@ class Amount
return $user->currencies()->orderBy('code', 'ASC')->get();
}
/**
* @deprecated
*/
#[Deprecated]
public function getDefaultCurrency(): TransactionCurrency
{
return $this->getNativeCurrency();
}
/**
* @deprecated use getDefaultCurrencyByUserGroup instead
*/
#[Deprecated(message: 'use getDefaultCurrencyByUserGroup instead')]
public function getDefaultCurrencyByUser(User $user): TransactionCurrency
{
return $this->getDefaultCurrencyByUserGroup($user->userGroup);
}
/**
* @deprecated
*/
#[Deprecated]
public function getDefaultCurrencyByUserGroup(UserGroup $userGroup): TransactionCurrency
{
return $this->getNativeCurrencyByUserGroup($userGroup);
+14 -12
View File
@@ -28,6 +28,8 @@ use Carbon\Carbon;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Jobs\CreateRecurringTransactions;
use FireflyIII\Models\Configuration;
use FireflyIII\Support\Facades\FireflyConfig;
use Illuminate\Support\Facades\Log;
/**
* Class RecurringCronjob
@@ -39,34 +41,34 @@ class RecurringCronjob extends AbstractCronjob
*/
public function fire(): void
{
app('log')->debug(sprintf('Now in %s', __METHOD__));
Log::debug(sprintf('Now in %s', __METHOD__));
/** @var Configuration $config */
$config = app('fireflyconfig')->get('last_rt_job', 0);
$config = FireflyConfig::get('last_rt_job', 0);
$lastTime = (int) $config->data;
$diff = Carbon::now()->getTimestamp() - $lastTime;
$diffForHumans = today(config('app.timezone'))->diffForHumans(Carbon::createFromTimestamp($lastTime), null, true);
if (0 === $lastTime) {
app('log')->info('Recurring transactions cron-job has never fired before.');
Log::info('Recurring transactions cron-job has never fired before.');
}
// less than half a day ago:
if ($lastTime > 0 && $diff <= 43200) {
app('log')->info(sprintf('It has been %s since the recurring transactions cron-job has fired.', $diffForHumans));
Log::info(sprintf('It has been "%s" since the recurring transactions cron-job has fired.', $diffForHumans));
if (false === $this->force) {
app('log')->info('The cron-job will not fire now.');
$this->message = sprintf('It has been %s since the recurring transactions cron-job has fired. It will not fire now.', $diffForHumans);
Log::info('The cron-job will not fire now.');
$this->message = sprintf('It has been "%s" since the recurring transactions cron-job has fired. It will not fire now.', $diffForHumans);
$this->jobFired = false;
$this->jobErrored = false;
$this->jobSucceeded = false;
return;
}
app('log')->info('Execution of the recurring transaction cron-job has been FORCED.');
Log::info('Execution of the recurring transaction cron-job has been FORCED.');
}
if ($lastTime > 0 && $diff > 43200) {
app('log')->info(sprintf('It has been %s since the recurring transactions cron-job has fired. It will fire now!', $diffForHumans));
Log::info(sprintf('It has been "%s" since the recurring transactions cron-job has fired. It will fire now!', $diffForHumans));
}
$this->fireRecurring();
@@ -76,7 +78,7 @@ class RecurringCronjob extends AbstractCronjob
private function fireRecurring(): void
{
app('log')->info(sprintf('Will now fire recurring cron job task for date "%s".', $this->date->format('Y-m-d H:i:s')));
Log::info(sprintf('Will now fire recurring cron job task for date "%s".', $this->date->format('Y-m-d H:i:s')));
$job = new CreateRecurringTransactions($this->date);
$job->setForce($this->force);
@@ -88,8 +90,8 @@ class RecurringCronjob extends AbstractCronjob
$this->jobSucceeded = true;
$this->message = 'Recurring transactions cron job fired successfully.';
app('fireflyconfig')->set('last_rt_job', (int) $this->date->format('U'));
app('log')->info(sprintf('Marked the last time this job has run as "%s" (%d)', $this->date->format('Y-m-d H:i:s'), (int) $this->date->format('U')));
app('log')->info('Done with recurring cron job task.');
FireflyConfig::set('last_rt_job', (int) $this->date->format('U'));
Log::info(sprintf('Marked the last time this job has run as "%s" (%d)', $this->date->format('Y-m-d H:i:s'), (int) $this->date->format('U')));
Log::info('Done with recurring cron job task.');
}
}
+2 -2
View File
@@ -39,7 +39,7 @@ class FireflyConfig
{
public function delete(string $name): void
{
$fullName = 'ff-config-'.$name;
$fullName = 'ff3-config-'.$name;
if (Cache::has($fullName)) {
Cache::forget($fullName);
}
@@ -81,7 +81,7 @@ class FireflyConfig
*/
public function get(string $name, mixed $default = null): ?Configuration
{
$fullName = 'ff-config-'.$name;
$fullName = 'ff3-config-'.$name;
if (Cache::has($fullName)) {
return Cache::get($fullName);
}
@@ -79,12 +79,12 @@ class ExchangeRateConverter
public function getCurrencyRate(TransactionCurrency $from, TransactionCurrency $to, Carbon $date): string
{
if (false === $this->enabled()) {
Log::debug('ExchangeRateConverter: disabled, return "1".');
// Log::debug('ExchangeRateConverter: disabled, return "1".');
return '1';
}
if ($from->id === $to->id) {
Log::debug('ExchangeRateConverter: From and to are the same, return "1".');
// Log::debug('ExchangeRateConverter: From and to are the same, return "1".');
return '1';
}
@@ -26,6 +26,7 @@ namespace FireflyIII\Support\Http\Controllers;
use Carbon\Carbon;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Support\Facades\FireflyConfig;
use Illuminate\Support\Facades\Log;
/**
@@ -205,7 +206,7 @@ trait GetConfigurationData
protected function verifyRecurringCronJob(): void
{
$config = app('fireflyconfig')->get('last_rt_job', 0);
$config = FireflyConfig::get('last_rt_job', 0);
$lastTime = (int) $config?->data;
$now = Carbon::now()->getTimestamp();
app('log')->debug(sprintf('verifyRecurringCronJob: last time is %d ("%s"), now is %d', $lastTime, $config?->data, $now));
@@ -35,6 +35,7 @@ use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use FireflyIII\Repositories\Journal\JournalRepositoryInterface;
use FireflyIII\Support\CacheProperties;
use FireflyIII\Support\Debug\Timer;
use Illuminate\Support\Facades\Log;
/**
* Trait PeriodOverview.
@@ -77,6 +78,7 @@ trait PeriodOverview
*/
protected function getAccountPeriodOverview(Account $account, Carbon $start, Carbon $end): array
{
Log::debug('Now in getAccountPeriodOverview()');
Timer::start('account-period-total');
$this->accountRepository = app(AccountRepositoryInterface::class);
$range = app('navigation')->getViewRange(true);
@@ -100,6 +102,7 @@ trait PeriodOverview
$transactions = $this->accountRepository->periodCollection($account, $start, $end);
// loop dates
Log::debug(sprintf('Count of loops: %d', count($dates)));
foreach ($dates as $currentDate) {
$title = app('navigation')->periodShow($currentDate['start'], $currentDate['period']);
[$transactions, $spent] = $this->filterTransactionsByType(TransactionTypeEnum::WITHDRAWAL, $transactions, $currentDate['start'], $currentDate['end']);
@@ -119,6 +122,7 @@ trait PeriodOverview
}
$cache->store($entries);
Timer::stop('account-period-total');
Log::debug('End of getAccountPeriodOverview()');
return $entries;
}
@@ -54,7 +54,7 @@ class TransactionGroupEnrichment implements EnrichmentInterface
private array $notes; // @phpstan-ignore-line
private array $tags;
private User $user;
private TransactionCurrency $nativeCurrency;
private readonly TransactionCurrency $nativeCurrency;
private UserGroup $userGroup;
public function __construct()
@@ -51,7 +51,7 @@ class TransactionSummarizer
public function groupByCurrencyId(array $journals, string $method = 'negative', bool $includeForeign = true): array
{
Log::debug(sprintf('Now in groupByCurrencyId([%d journals], "%s")', count($journals), $method));
Log::debug(sprintf('Now in groupByCurrencyId([%d journals], "%s", %s)', count($journals), $method, var_export($includeForeign, true)));
$array = [];
foreach ($journals as $journal) {
$field = 'amount';
+2
View File
@@ -278,6 +278,8 @@ class Steam
$carbonKey = $carbon->format('Y-m-d');
// make sure sum is a string:
$sumOfDay = (string) ($entry->sum_of_day ?? '0');
// #10426 make sure sum is not in scientific notation.
$sumOfDay = $this->floatalize($sumOfDay);
// find currency of this entry, does not have to exist.
$currencies[$entry->transaction_currency_id] ??= TransactionCurrency::find($entry->transaction_currency_id);
@@ -67,6 +67,16 @@ class UpdatePiggyBank implements ActionInterface
Log::debug(sprintf('Found piggy bank #%d ("%s")', $piggyBank->id, $piggyBank->name));
// piggy bank already has an event for this transaction journal?
if ($this->alreadyEventPresent($piggyBank, $journal)) {
Log::info(sprintf('Piggy bank #%d ("%s") already has an event for transaction journal #%d, so no action will be taken.', $piggyBank->id, $piggyBank->name, $journalObj->id));
event(new RuleActionFailedOnArray($this->action, $journal, trans('rules.cannot_find_piggy', ['name' => $actionValue])));
return false;
}
/** @var Transaction $destination */
$destination = $journalObj->transactions()->where('amount', '>', 0)->first();
@@ -231,4 +241,9 @@ class UpdatePiggyBank implements ActionInterface
$repository->addAmount($piggyBank, $account, $amount, $journal);
}
private function alreadyEventPresent(PiggyBank $piggyBank, array $journal): bool
{
return $piggyBank->piggyBankEvents()->where('transaction_journal_id', $journal['transaction_journal_id'])->exists();
}
}
@@ -64,13 +64,13 @@ class SearchRuleEngine implements RuleEngineInterface
public function addOperator(array $operator): void
{
app('log')->debug('Add extra operator: ', $operator);
Log::debug('Add extra operator: ', $operator);
$this->operators[] = $operator;
}
public function find(): Collection
{
app('log')->debug('SearchRuleEngine::find()');
Log::debug('SearchRuleEngine::find()');
$collection = new Collection();
foreach ($this->rules as $rule) {
$found = new Collection();
@@ -83,7 +83,7 @@ class SearchRuleEngine implements RuleEngineInterface
$collection = $collection->merge($found);
}
$result = $collection->unique();
app('log')->debug(sprintf('SearchRuleEngine::find() returns %d unique transactions.', $result->count()));
Log::debug(sprintf('SearchRuleEngine::find() returns %d unique transactions.', $result->count()));
return $result;
}
@@ -93,7 +93,7 @@ class SearchRuleEngine implements RuleEngineInterface
*/
private function findStrictRule(Rule $rule): Collection
{
app('log')->debug(sprintf('Now in findStrictRule(#%d)', $rule->id ?? 0));
Log::debug(sprintf('Now in findStrictRule(#%d)', $rule->id ?? 0));
$searchArray = [];
$triggers = [];
if ($this->refreshTriggers) {
@@ -116,18 +116,18 @@ class SearchRuleEngine implements RuleEngineInterface
// if the trigger needs no context, value is different:
$needsContext = (bool) (config(sprintf('search.operators.%s.needs_context', $contextSearch)) ?? true);
if (false === $needsContext) {
app('log')->debug(sprintf('SearchRuleEngine:: add a rule trigger (no context): %s:true', $ruleTrigger->trigger_type));
Log::debug(sprintf('SearchRuleEngine:: add a rule trigger (no context): %s:true', $ruleTrigger->trigger_type));
$searchArray[$ruleTrigger->trigger_type][] = 'true';
}
if (true === $needsContext) {
app('log')->debug(sprintf('SearchRuleEngine:: add a rule trigger (context): %s:"%s"', $ruleTrigger->trigger_type, $ruleTrigger->trigger_value));
Log::debug(sprintf('SearchRuleEngine:: add a rule trigger (context): %s:"%s"', $ruleTrigger->trigger_type, $ruleTrigger->trigger_value));
$searchArray[$ruleTrigger->trigger_type][] = sprintf('"%s"', $ruleTrigger->trigger_value);
}
}
// add local operators:
foreach ($this->operators as $operator) {
app('log')->debug(sprintf('SearchRuleEngine:: add local added operator: %s:"%s"', $operator['type'], $operator['value']));
Log::debug(sprintf('SearchRuleEngine:: add local added operator: %s:"%s"', $operator['type'], $operator['value']));
$searchArray[$operator['type']][] = sprintf('"%s"', $operator['value']);
}
$date = today(config('app.timezone'));
@@ -141,11 +141,11 @@ class SearchRuleEngine implements RuleEngineInterface
$searchEngine->setPage(1);
$searchEngine->setLimit(31337);
$searchEngine->setDate($date);
app('log')->debug('Search array', $searchArray);
Log::debug('Search array', $searchArray);
foreach ($searchArray as $type => $searches) {
foreach ($searches as $value) {
$query = sprintf('%s:%s', $type, $value);
app('log')->debug(sprintf('SearchRuleEngine:: add query "%s"', $query));
Log::debug(sprintf('SearchRuleEngine:: add query "%s"', $query));
$searchEngine->parseQuery($query);
}
}
@@ -162,33 +162,33 @@ class SearchRuleEngine implements RuleEngineInterface
*/
private function hasSpecificJournalTrigger(array $array): bool
{
app('log')->debug('Now in hasSpecificJournalTrigger.');
Log::debug('Now in hasSpecificJournalTrigger.');
$journalTrigger = false;
$dateTrigger = false;
foreach ($array as $triggerName => $values) {
if ('journal_id' === $triggerName && is_array($values) && 1 === count($values)) {
app('log')->debug('Found a journal_id trigger with 1 journal, true.');
Log::debug('Found a journal_id trigger with 1 journal, true.');
$journalTrigger = true;
}
if (in_array($triggerName, ['date_is', 'date', 'on', 'date_before', 'before', 'date_after', 'after'], true)) {
app('log')->debug('Found a date related trigger, set to true.');
Log::debug('Found a date related trigger, set to true.');
$dateTrigger = true;
}
}
$result = $journalTrigger && $dateTrigger;
app('log')->debug(sprintf('Result of hasSpecificJournalTrigger is %s.', var_export($result, true)));
Log::debug(sprintf('Result of hasSpecificJournalTrigger is %s.', var_export($result, true)));
return $result;
}
private function setDateFromJournalTrigger(array $array): Carbon
{
app('log')->debug('Now in setDateFromJournalTrigger()');
Log::debug('Now in setDateFromJournalTrigger()');
$journalId = 0;
foreach ($array as $triggerName => $values) {
if ('journal_id' === $triggerName && is_array($values) && 1 === count($values)) {
$journalId = (int) trim($values[0] ?? '"0"', '"'); // follows format "123".
app('log')->debug(sprintf('Found journal ID #%d', $journalId));
Log::debug(sprintf('Found journal ID #%d', $journalId));
}
}
if (0 !== $journalId) {
@@ -197,12 +197,12 @@ class SearchRuleEngine implements RuleEngineInterface
$journal = $repository->find($journalId);
if (null !== $journal) {
$date = $journal->date;
app('log')->debug(sprintf('Found journal #%d with date %s.', $journal->id, $journal->date->format('Y-m-d')));
Log::debug(sprintf('Found journal #%d with date %s.', $journal->id, $journal->date->format('Y-m-d')));
return $date;
}
}
app('log')->debug('Found no journal, return default date.');
Log::debug('Found no journal, return default date.');
return today(config('app.timezone'));
}
@@ -215,48 +215,48 @@ class SearchRuleEngine implements RuleEngineInterface
private function findNonStrictRule(Rule $rule): Collection
{
app('log')->debug(sprintf('findNonStrictRule(#%d)', $rule->id));
Log::debug(sprintf('findNonStrictRule(#%d)', $rule->id));
// start a search query for individual each trigger:
$total = new Collection();
$count = 0;
$triggers = [];
if ($this->refreshTriggers) {
app('log')->debug('Will refresh triggers.');
Log::debug('Will refresh triggers.');
$triggers = $rule->ruleTriggers()->orderBy('order', 'ASC')->get();
}
if (!$this->refreshTriggers) {
app('log')->debug('Will not refresh triggers.');
Log::debug('Will not refresh triggers.');
$triggers = $rule->ruleTriggers;
}
app('log')->debug(sprintf('Will run %d trigger(s).', count($triggers)));
Log::debug(sprintf('Will run %d trigger(s).', count($triggers)));
/** @var RuleTrigger $ruleTrigger */
foreach ($triggers as $ruleTrigger) {
app('log')->debug(sprintf('Now at rule trigger #%d: %s:"%s" (%s).', $ruleTrigger->id, $ruleTrigger->trigger_type, $ruleTrigger->trigger_value, var_export($ruleTrigger->stop_processing, true)));
Log::debug(sprintf('Now at rule trigger #%d: %s:"%s" (%s).', $ruleTrigger->id, $ruleTrigger->trigger_type, $ruleTrigger->trigger_value, var_export($ruleTrigger->stop_processing, true)));
if (false === $ruleTrigger->active) {
app('log')->debug('Trigger is not active, continue.');
Log::debug('Trigger is not active, continue.');
continue;
}
if ('user_action' === $ruleTrigger->trigger_type) {
app('log')->debug('Skip trigger type. continue.');
Log::debug('Skip trigger type. continue.');
continue;
}
$searchArray = [];
$needsContext = config(sprintf('search.operators.%s.needs_context', $ruleTrigger->trigger_type)) ?? true;
if (false === $needsContext) {
app('log')->debug(sprintf('SearchRuleEngine:: non strict, will search for: %s:true', $ruleTrigger->trigger_type));
Log::debug(sprintf('SearchRuleEngine:: non strict, will search for: %s:true', $ruleTrigger->trigger_type));
$searchArray[$ruleTrigger->trigger_type] = 'true';
}
if (true === $needsContext) {
app('log')->debug(sprintf('SearchRuleEngine:: non strict, will search for: %s:"%s"', $ruleTrigger->trigger_type, $ruleTrigger->trigger_value));
Log::debug(sprintf('SearchRuleEngine:: non strict, will search for: %s:"%s"', $ruleTrigger->trigger_type, $ruleTrigger->trigger_value));
$searchArray[$ruleTrigger->trigger_type] = sprintf('"%s"', $ruleTrigger->trigger_value);
}
// then, add local operators as well:
foreach ($this->operators as $operator) {
app('log')->debug(sprintf('SearchRuleEngine:: add local added operator: %s:"%s"', $operator['type'], $operator['value']));
Log::debug(sprintf('SearchRuleEngine:: add local added operator: %s:"%s"', $operator['type'], $operator['value']));
$searchArray[$operator['type']] = sprintf('"%s"', $operator['value']);
}
@@ -272,19 +272,19 @@ class SearchRuleEngine implements RuleEngineInterface
$result = $searchEngine->searchTransactions();
$collection = $result->getCollection();
app('log')->debug(sprintf('Found in this run, %d transactions', $collection->count()));
Log::debug(sprintf('Found in this run, %d transactions', $collection->count()));
$total = $total->merge($collection);
app('log')->debug(sprintf('Total collection is now %d transactions', $total->count()));
Log::debug(sprintf('Total collection is now %d transactions', $total->count()));
++$count;
// if trigger says stop processing, do so.
if (true === $ruleTrigger->stop_processing && $result->count() > 0) {
app('log')->debug('The trigger says to stop processing, so stop processing other triggers.');
Log::debug('The trigger says to stop processing, so stop processing other triggers.');
break;
}
}
app('log')->debug(sprintf('Total collection is now %d transactions', $total->count()));
app('log')->debug(sprintf('Done running %d trigger(s)', $count));
Log::debug(sprintf('Total collection is now %d transactions', $total->count()));
Log::debug(sprintf('Done running %d trigger(s)', $count));
// make collection unique
$unique = $total->unique(
@@ -295,11 +295,11 @@ class SearchRuleEngine implements RuleEngineInterface
}
return sprintf('%d%s', $group['id'], $str);
// app('log')->debug(sprintf('Return key: %s ', $key));
// Log::debug(sprintf('Return key: %s ', $key));
}
);
app('log')->debug(sprintf('SearchRuleEngine:: Found %d transactions using search engine.', $unique->count()));
Log::debug(sprintf('SearchRuleEngine:: Found %d transactions using search engine.', $unique->count()));
return $unique;
}
@@ -310,28 +310,28 @@ class SearchRuleEngine implements RuleEngineInterface
public function fire(): void
{
$this->resultCount = [];
app('log')->debug('SearchRuleEngine::fire()!');
Log::debug('SearchRuleEngine::fire()!');
// if rules and no rule groups, file each rule separately.
if (0 !== $this->rules->count()) {
app('log')->debug(sprintf('SearchRuleEngine:: found %d rule(s) to fire.', $this->rules->count()));
Log::debug(sprintf('SearchRuleEngine:: found %d rule(s) to fire.', $this->rules->count()));
/** @var Rule $rule */
foreach ($this->rules as $rule) {
$result = $this->fireRule($rule);
if (true === $result && true === $rule->stop_processing) {
app('log')->debug(sprintf('Rule #%d has triggered and executed, but calls to stop processing. Since not in the context of a group, do not stop.', $rule->id));
Log::debug(sprintf('Rule #%d has triggered and executed, but calls to stop processing. Since not in the context of a group, do not stop.', $rule->id));
}
if (false === $result && true === $rule->stop_processing) {
app('log')->debug(sprintf('Rule #%d has triggered and changed nothing, but calls to stop processing. Do not stop.', $rule->id));
Log::debug(sprintf('Rule #%d has triggered and changed nothing, but calls to stop processing. Do not stop.', $rule->id));
}
}
app('log')->debug('SearchRuleEngine:: done processing all rules!');
Log::debug('SearchRuleEngine:: done processing all rules!');
return;
}
if (0 !== $this->groups->count()) {
app('log')->debug(sprintf('SearchRuleEngine:: found %d rule group(s) to fire.', $this->groups->count()));
Log::debug(sprintf('SearchRuleEngine:: found %d rule group(s) to fire.', $this->groups->count()));
// fire each group:
/** @var RuleGroup $group */
@@ -339,7 +339,7 @@ class SearchRuleEngine implements RuleEngineInterface
$this->fireGroup($group);
}
}
app('log')->debug('SearchRuleEngine:: done processing all rules!');
Log::debug('SearchRuleEngine:: done processing all rules!');
}
/**
@@ -349,18 +349,18 @@ class SearchRuleEngine implements RuleEngineInterface
*/
private function fireRule(Rule $rule): bool
{
app('log')->debug(sprintf('Now going to fire rule #%d', $rule->id));
Log::debug(sprintf('Now going to fire rule #%d', $rule->id));
if (false === $rule->active) {
app('log')->debug(sprintf('Rule #%d is not active!', $rule->id));
Log::debug(sprintf('Rule #%d is not active!', $rule->id));
return false;
}
if (true === $rule->strict) {
app('log')->debug(sprintf('Rule #%d is a strict rule.', $rule->id));
Log::debug(sprintf('Rule #%d is a strict rule.', $rule->id));
return $this->fireStrictRule($rule);
}
app('log')->debug(sprintf('Rule #%d is not strict rule.', $rule->id));
Log::debug(sprintf('Rule #%d is not strict rule.', $rule->id));
return $this->fireNonStrictRule($rule);
}
@@ -372,19 +372,19 @@ class SearchRuleEngine implements RuleEngineInterface
*/
private function fireStrictRule(Rule $rule): bool
{
app('log')->debug(sprintf('SearchRuleEngine::fireStrictRule(%d)!', $rule->id));
Log::debug(sprintf('SearchRuleEngine::fireStrictRule(%d)!', $rule->id));
$collection = $this->findStrictRule($rule);
$this->processResults($rule, $collection);
app('log')->debug(sprintf('SearchRuleEngine:: done processing strict rule #%d', $rule->id));
Log::debug(sprintf('SearchRuleEngine:: done processing strict rule #%d', $rule->id));
$result = $collection->count() > 0;
if (true === $result) {
app('log')->debug(sprintf('SearchRuleEngine:: rule #%d was triggered (on %d transaction(s)).', $rule->id, $collection->count()));
Log::debug(sprintf('SearchRuleEngine:: rule #%d was triggered (on %d transaction(s)).', $rule->id, $collection->count()));
return true;
}
app('log')->debug(sprintf('SearchRuleEngine:: rule #%d was not triggered (on %d transaction(s)).', $rule->id, $collection->count()));
Log::debug(sprintf('SearchRuleEngine:: rule #%d was not triggered (on %d transaction(s)).', $rule->id, $collection->count()));
return false;
}
@@ -394,7 +394,7 @@ class SearchRuleEngine implements RuleEngineInterface
*/
private function processResults(Rule $rule, Collection $collection): void
{
app('log')->debug(sprintf('SearchRuleEngine:: Going to process %d results.', $collection->count()));
Log::debug(sprintf('SearchRuleEngine:: Going to process %d results.', $collection->count()));
/** @var array $group */
foreach ($collection as $group) {
@@ -407,7 +407,7 @@ class SearchRuleEngine implements RuleEngineInterface
*/
private function processTransactionGroup(Rule $rule, array $group): void
{
app('log')->debug(sprintf('SearchRuleEngine:: Will now execute actions on transaction group #%d', $group['id']));
Log::debug(sprintf('SearchRuleEngine:: Will now execute actions on transaction group #%d', $group['id']));
/** @var array $transaction */
foreach ($group['transactions'] as $transaction) {
@@ -420,7 +420,7 @@ class SearchRuleEngine implements RuleEngineInterface
*/
private function processTransactionJournal(Rule $rule, array $transaction): void
{
app('log')->debug(sprintf('SearchRuleEngine:: Will now execute actions on transaction journal #%d', $transaction['transaction_journal_id']));
Log::debug(sprintf('SearchRuleEngine:: Will now execute actions on transaction journal #%d', $transaction['transaction_journal_id']));
$actions = $rule->ruleActions()->orderBy('order', 'ASC')->get();
/** @var RuleAction $ruleAction */
@@ -440,14 +440,14 @@ class SearchRuleEngine implements RuleEngineInterface
*/
private function processRuleAction(RuleAction $ruleAction, array $transaction): bool
{
app('log')->debug(sprintf('Executing rule action "%s" with value "%s"', $ruleAction->action_type, $ruleAction->action_value));
Log::debug(sprintf('Executing rule action "%s" with value "%s"', $ruleAction->action_type, $ruleAction->action_value));
$transaction = $this->addNotes($transaction);
$actionClass = ActionFactory::getAction($ruleAction);
$result = $actionClass->actOnArray($transaction);
$journalId = $transaction['transaction_journal_id'] ?? 0;
if (true === $result) {
$this->resultCount[$journalId] = array_key_exists($journalId, $this->resultCount) ? $this->resultCount[$journalId]++ : 1;
app('log')->debug(
Log::debug(
sprintf(
'Action "%s" on journal #%d was executed, so count a result. Updated transaction journal count is now %d.',
$ruleAction->action_type,
@@ -457,17 +457,17 @@ class SearchRuleEngine implements RuleEngineInterface
);
}
if (false === $result) {
app('log')->debug(sprintf('Action "%s" reports NO changes were made.', $ruleAction->action_type));
Log::debug(sprintf('Action "%s" reports NO changes were made.', $ruleAction->action_type));
}
// pick up from the action if it actually acted or not:
if (true === $ruleAction->stop_processing && true === $result) {
app('log')->debug(sprintf('Rule action "%s" reports changes AND asks to break, so break!', $ruleAction->action_type));
Log::debug(sprintf('Rule action "%s" reports changes AND asks to break, so break!', $ruleAction->action_type));
return true;
}
if (true === $ruleAction->stop_processing && false === $result) {
app('log')->debug(sprintf('Rule action "%s" reports NO changes AND asks to break, but we wont break!', $ruleAction->action_type));
Log::debug(sprintf('Rule action "%s" reports NO changes AND asks to break, but we wont break!', $ruleAction->action_type));
}
return false;
@@ -492,11 +492,11 @@ class SearchRuleEngine implements RuleEngineInterface
*/
private function fireNonStrictRule(Rule $rule): bool
{
app('log')->debug(sprintf('SearchRuleEngine::fireNonStrictRule(%d)!', $rule->id));
Log::debug(sprintf('SearchRuleEngine::fireNonStrictRule(%d)!', $rule->id));
$collection = $this->findNonStrictRule($rule);
$this->processResults($rule, $collection);
app('log')->debug(sprintf('SearchRuleEngine:: done processing non-strict rule #%d', $rule->id));
Log::debug(sprintf('SearchRuleEngine:: done processing non-strict rule #%d', $rule->id));
return $collection->count() > 0;
}
@@ -506,14 +506,14 @@ class SearchRuleEngine implements RuleEngineInterface
*/
private function fireGroup(RuleGroup $group): void
{
app('log')->debug(sprintf('Going to fire group #%d with %d rule(s)', $group->id, $group->rules->count()));
Log::debug(sprintf('Going to fire group #%d with %d rule(s)', $group->id, $group->rules->count()));
/** @var Rule $rule */
foreach ($group->rules as $rule) {
app('log')->debug(sprintf('Going to fire rule #%d from group #%d', $rule->id, $group->id));
Log::debug(sprintf('Going to fire rule #%d from group #%d', $rule->id, $group->id));
$result = $this->fireRule($rule);
if (true === $result && true === $rule->stop_processing) {
app('log')->debug(sprintf('The rule was triggered and rule->stop_processing = true, so group #%d will stop processing further rules.', $group->id));
Log::debug(sprintf('The rule was triggered and rule->stop_processing = true, so group #%d will stop processing further rules.', $group->id));
return;
}
@@ -535,10 +535,10 @@ class SearchRuleEngine implements RuleEngineInterface
public function setRuleGroups(Collection $ruleGroups): void
{
app('log')->debug(__METHOD__);
Log::debug(__METHOD__);
foreach ($ruleGroups as $group) {
if ($group instanceof RuleGroup) {
app('log')->debug(sprintf('Adding a rule group to the SearchRuleEngine: #%d ("%s")', $group->id, $group->title));
Log::debug(sprintf('Adding a rule group to the SearchRuleEngine: #%d ("%s")', $group->id, $group->title));
$this->groups->push($group);
}
}
@@ -546,10 +546,10 @@ class SearchRuleEngine implements RuleEngineInterface
public function setRules(Collection $rules): void
{
app('log')->debug(__METHOD__);
Log::debug(__METHOD__);
foreach ($rules as $rule) {
if ($rule instanceof Rule) {
app('log')->debug(sprintf('Adding a rule to the SearchRuleEngine: #%d ("%s")', $rule->id, $rule->title));
Log::debug(sprintf('Adding a rule to the SearchRuleEngine: #%d ("%s")', $rule->id, $rule->title));
$this->rules->push($rule);
}
}
@@ -73,8 +73,8 @@ class PiggyBankEventTransformer extends AbstractTransformer
return [
'id' => (string) $event->id,
'created_at' => $event->created_at->toAtomString(),
'updated_at' => $event->updated_at->toAtomString(),
'created_at' => $event->created_at?->toAtomString(),
'updated_at' => $event->updated_at?->toAtomString(),
'amount' => app('steam')->bcround($event->amount, $currency->decimal_places),
'currency_id' => (string) $currency->id,
'currency_code' => $currency->code,
+7 -12
View File
@@ -24,6 +24,7 @@ declare(strict_types=1);
namespace FireflyIII;
use Deprecated;
use FireflyIII\Enums\UserRoleEnum;
use FireflyIII\Events\RequestedNewPassword;
use FireflyIII\Exceptions\FireflyException;
@@ -188,9 +189,8 @@ class User extends Authenticatable
* Get the models LDAP domain.
*
* @return string
*
* @deprecated
*/
#[Deprecated]
public function getLdapDomain()
{
return $this->{$this->getLdapDomainColumn()};
@@ -200,9 +200,8 @@ class User extends Authenticatable
* Get the database column name of the domain.
*
* @return string
*
* @deprecated
*/
#[Deprecated]
public function getLdapDomainColumn()
{
return 'domain';
@@ -212,9 +211,8 @@ class User extends Authenticatable
* Get the models LDAP GUID.
*
* @return string
*
* @deprecated
*/
#[Deprecated]
public function getLdapGuid()
{
return $this->{$this->getLdapGuidColumn()};
@@ -224,9 +222,8 @@ class User extends Authenticatable
* Get the models LDAP GUID database column name.
*
* @return string
*
* @deprecated
*/
#[Deprecated]
public function getLdapGuidColumn()
{
return 'objectguid';
@@ -468,9 +465,8 @@ class User extends Authenticatable
* Set the models LDAP domain.
*
* @param string $domain
*
* @deprecated
*/
#[Deprecated]
public function setLdapDomain($domain): void
{
$this->{$this->getLdapDomainColumn()} = $domain;
@@ -480,9 +476,8 @@ class User extends Authenticatable
* Set the models LDAP GUID.
*
* @param string $guid
*
* @deprecated
*/
#[Deprecated]
public function setLdapGuid($guid): void
{
$this->{$this->getLdapGuidColumn()} = $guid;
+39
View File
@@ -3,6 +3,45 @@
All notable changes to this project will be documented in this file.
This project adheres to [Semantic Versioning](http://semver.org/).
## 6.2.18 - 2025-06-20
### Changed
- Give more details about OAuth errors.
- Currency seeder adds "RMB" instead of "CNY" for Chinese Yuan.
### Fixed
- [Issue 10454](https://github.com/firefly-iii/firefly-iii/issues/10454) (Bulk edit individually give an error) reported by @Rick45
- [Issue 10470](https://github.com/firefly-iii/firefly-iii/issues/10470) (API endpoint `/api/v1/chart/account/overview` throws error) reported by @dreautall
- Remove some leftover debug info
## 6.2.17 - 2025-06-12
### Changed
- Firefly III will trim account numbers with spaces for better matching during imports
- Running balance is only updated when amounts or accounts change.
### Fixed
- Transactions can't be linked to a piggy bank twice.
- [Issue 10229](https://github.com/firefly-iii/firefly-iii/issues/10229) (Please show transaction ID in the Meta information) reported by @srikakulamts
- [Issue 10382](https://github.com/firefly-iii/firefly-iii/issues/10382) (Have a link to search page on mobile layout) reported by @sergeolkhovik
- [Issue 10399](https://github.com/firefly-iii/firefly-iii/issues/10399) (Can not apply rules to future dates) reported by @sanderr
- [Issue 10403](https://github.com/firefly-iii/firefly-iii/issues/10403) (Piggy banks over multiple accounts are too restrictive) reported by @sanderr
- [Issue 10413](https://github.com/firefly-iii/firefly-iii/issues/10413) (Piggy Bank math seems broken, deductions are not registered, Saved so far 0 but balance is positive) reported by @Skiri-ki
- [Issue 10419](https://github.com/firefly-iii/firefly-iii/issues/10419) (Add quarters to report view to prefill date ranges) reported by @othmar52
- [Issue 10426](https://github.com/firefly-iii/firefly-iii/issues/10426) (bcadd(): Argument #1 ($num1) is not well-formed) reported by @grgar
- [Discussion 10427](https://github.com/orgs/firefly-iii/discussions/10427) ("Stop processing" doesn't seem to work? (6.2.12)) started by @rarosalion
- [Issue 10432](https://github.com/firefly-iii/firefly-iii/issues/10432) (Error during upgrade 6.1.25 → 6.2.16: $piggyBank->account is null) reported by @Digi92
- [Issue 10433](https://github.com/firefly-iii/firefly-iii/issues/10433) (500 error when using forgot password link (running in Docker)) reported by @jegelandsdal
- [Issue 10441](https://github.com/firefly-iii/firefly-iii/issues/10441) (Missing spent per day info on mismatching budget limit periods) reported by @Kaotic3
### API
- Transactions now contain balance before/after.
## 6.2.16 - 2025-xx-xx
### Fixed
Generated
+148 -151
View File
@@ -129,16 +129,16 @@
},
{
"name": "brick/math",
"version": "0.12.3",
"version": "0.13.1",
"source": {
"type": "git",
"url": "https://github.com/brick/math.git",
"reference": "866551da34e9a618e64a819ee1e01c20d8a588ba"
"reference": "fc7ed316430118cc7836bf45faff18d5dfc8de04"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/brick/math/zipball/866551da34e9a618e64a819ee1e01c20d8a588ba",
"reference": "866551da34e9a618e64a819ee1e01c20d8a588ba",
"url": "https://api.github.com/repos/brick/math/zipball/fc7ed316430118cc7836bf45faff18d5dfc8de04",
"reference": "fc7ed316430118cc7836bf45faff18d5dfc8de04",
"shasum": ""
},
"require": {
@@ -177,7 +177,7 @@
],
"support": {
"issues": "https://github.com/brick/math/issues",
"source": "https://github.com/brick/math/tree/0.12.3"
"source": "https://github.com/brick/math/tree/0.13.1"
},
"funding": [
{
@@ -185,7 +185,7 @@
"type": "github"
}
],
"time": "2025-02-28T13:11:00+00:00"
"time": "2025-03-29T13:50:30+00:00"
},
{
"name": "carbonphp/carbon-doctrine-types",
@@ -939,16 +939,16 @@
},
{
"name": "filp/whoops",
"version": "2.18.0",
"version": "2.18.3",
"source": {
"type": "git",
"url": "https://github.com/filp/whoops.git",
"reference": "a7de6c3c6c3c022f5cfc337f8ede6a14460cf77e"
"reference": "59a123a3d459c5a23055802237cb317f609867e5"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/filp/whoops/zipball/a7de6c3c6c3c022f5cfc337f8ede6a14460cf77e",
"reference": "a7de6c3c6c3c022f5cfc337f8ede6a14460cf77e",
"url": "https://api.github.com/repos/filp/whoops/zipball/59a123a3d459c5a23055802237cb317f609867e5",
"reference": "59a123a3d459c5a23055802237cb317f609867e5",
"shasum": ""
},
"require": {
@@ -998,7 +998,7 @@
],
"support": {
"issues": "https://github.com/filp/whoops/issues",
"source": "https://github.com/filp/whoops/tree/2.18.0"
"source": "https://github.com/filp/whoops/tree/2.18.3"
},
"funding": [
{
@@ -1006,7 +1006,7 @@
"type": "github"
}
],
"time": "2025-03-15T12:00:00+00:00"
"time": "2025-06-16T00:02:10+00:00"
},
{
"name": "firebase/php-jwt",
@@ -1879,20 +1879,20 @@
},
{
"name": "laravel/framework",
"version": "v12.16.0",
"version": "v12.19.3",
"source": {
"type": "git",
"url": "https://github.com/laravel/framework.git",
"reference": "293bb1c70224faebfd3d4328e201c37115da055f"
"reference": "4e6ec689ef704bb4bd282f29d9dd658dfb4fb262"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/laravel/framework/zipball/293bb1c70224faebfd3d4328e201c37115da055f",
"reference": "293bb1c70224faebfd3d4328e201c37115da055f",
"url": "https://api.github.com/repos/laravel/framework/zipball/4e6ec689ef704bb4bd282f29d9dd658dfb4fb262",
"reference": "4e6ec689ef704bb4bd282f29d9dd658dfb4fb262",
"shasum": ""
},
"require": {
"brick/math": "^0.11|^0.12",
"brick/math": "^0.11|^0.12|^0.13",
"composer-runtime-api": "^2.2",
"doctrine/inflector": "^2.0.5",
"dragonmantank/cron-expression": "^3.4",
@@ -2090,7 +2090,7 @@
"issues": "https://github.com/laravel/framework/issues",
"source": "https://github.com/laravel/framework"
},
"time": "2025-05-27T15:49:44+00:00"
"time": "2025-06-18T12:56:23+00:00"
},
{
"name": "laravel/passport",
@@ -3473,22 +3473,22 @@
},
{
"name": "mailersend/laravel-driver",
"version": "v2.9.1",
"version": "v2.11.0",
"source": {
"type": "git",
"url": "https://github.com/mailersend/mailersend-laravel-driver.git",
"reference": "87fd5ab76808bbaac9221be0d306baef13e98725"
"reference": "63acebb5064745076df27b1a80423986b6d7b69e"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/mailersend/mailersend-laravel-driver/zipball/87fd5ab76808bbaac9221be0d306baef13e98725",
"reference": "87fd5ab76808bbaac9221be0d306baef13e98725",
"url": "https://api.github.com/repos/mailersend/mailersend-laravel-driver/zipball/63acebb5064745076df27b1a80423986b6d7b69e",
"reference": "63acebb5064745076df27b1a80423986b6d7b69e",
"shasum": ""
},
"require": {
"ext-json": "*",
"illuminate/support": "^9.0 || ^10.0 || ^11.0 || ^12.0",
"mailersend/mailersend": "^0.31.0",
"mailersend/mailersend": "^0.34.0",
"nyholm/psr7": "^1.5",
"php": ">=8.0",
"php-http/guzzle7-adapter": "^1.0",
@@ -3536,29 +3536,28 @@
],
"support": {
"issues": "https://github.com/mailersend/mailersend-laravel-driver/issues",
"source": "https://github.com/mailersend/mailersend-laravel-driver/tree/v2.9.1"
"source": "https://github.com/mailersend/mailersend-laravel-driver/tree/v2.11.0"
},
"time": "2025-04-09T09:33:07+00:00"
"time": "2025-06-04T08:47:41+00:00"
},
{
"name": "mailersend/mailersend",
"version": "v0.31.0",
"version": "v0.34.0",
"source": {
"type": "git",
"url": "https://github.com/mailersend/mailersend-php.git",
"reference": "513ff83ee768526055ad52987cde401ea7218c67"
"reference": "1cb8c42e5569e7455b1e0e794dcbf68e3b7898ab"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/mailersend/mailersend-php/zipball/513ff83ee768526055ad52987cde401ea7218c67",
"reference": "513ff83ee768526055ad52987cde401ea7218c67",
"url": "https://api.github.com/repos/mailersend/mailersend-php/zipball/1cb8c42e5569e7455b1e0e794dcbf68e3b7898ab",
"reference": "1cb8c42e5569e7455b1e0e794dcbf68e3b7898ab",
"shasum": ""
},
"require": {
"beberlei/assert": "^3.2",
"ext-json": "*",
"illuminate/collections": "^8.0 || ^9.0 || ^10.0 || ^11.0 || ^12.0",
"php": "^7.4|^8.0",
"php": "^7.4 || ^8.0 <8.5",
"php-http/client-common": "^2.2",
"php-http/discovery": "^1.9",
"php-http/httplug": "^2.1",
@@ -3603,9 +3602,9 @@
],
"support": {
"issues": "https://github.com/mailersend/mailersend-php/issues",
"source": "https://github.com/mailersend/mailersend-php/tree/v0.31.0"
"source": "https://github.com/mailersend/mailersend-php/tree/v0.34.0"
},
"time": "2025-04-03T12:16:11+00:00"
"time": "2025-06-04T07:53:52+00:00"
},
{
"name": "monolog/monolog",
@@ -3712,16 +3711,16 @@
},
{
"name": "nesbot/carbon",
"version": "3.9.1",
"version": "3.10.1",
"source": {
"type": "git",
"url": "https://github.com/CarbonPHP/carbon.git",
"reference": "ced71f79398ece168e24f7f7710462f462310d4d"
"reference": "1fd1935b2d90aef2f093c5e35f7ae1257c448d00"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/CarbonPHP/carbon/zipball/ced71f79398ece168e24f7f7710462f462310d4d",
"reference": "ced71f79398ece168e24f7f7710462f462310d4d",
"url": "https://api.github.com/repos/CarbonPHP/carbon/zipball/1fd1935b2d90aef2f093c5e35f7ae1257c448d00",
"reference": "1fd1935b2d90aef2f093c5e35f7ae1257c448d00",
"shasum": ""
},
"require": {
@@ -3729,9 +3728,9 @@
"ext-json": "*",
"php": "^8.1",
"psr/clock": "^1.0",
"symfony/clock": "^6.3 || ^7.0",
"symfony/clock": "^6.3.12 || ^7.0",
"symfony/polyfill-mbstring": "^1.0",
"symfony/translation": "^4.4.18 || ^5.2.1|| ^6.0 || ^7.0"
"symfony/translation": "^4.4.18 || ^5.2.1 || ^6.0 || ^7.0"
},
"provide": {
"psr/clock-implementation": "1.0"
@@ -3739,14 +3738,13 @@
"require-dev": {
"doctrine/dbal": "^3.6.3 || ^4.0",
"doctrine/orm": "^2.15.2 || ^3.0",
"friendsofphp/php-cs-fixer": "^3.57.2",
"friendsofphp/php-cs-fixer": "^3.75.0",
"kylekatarnls/multi-tester": "^2.5.3",
"ondrejmirtes/better-reflection": "^6.25.0.4",
"phpmd/phpmd": "^2.15.0",
"phpstan/extension-installer": "^1.3.1",
"phpstan/phpstan": "^1.11.2",
"phpunit/phpunit": "^10.5.20",
"squizlabs/php_codesniffer": "^3.9.0"
"phpstan/extension-installer": "^1.4.3",
"phpstan/phpstan": "^2.1.17",
"phpunit/phpunit": "^10.5.46",
"squizlabs/php_codesniffer": "^3.13.0"
},
"bin": [
"bin/carbon"
@@ -3814,7 +3812,7 @@
"type": "tidelift"
}
],
"time": "2025-05-01T19:51:51+00:00"
"time": "2025-06-21T15:19:35+00:00"
},
{
"name": "nette/schema",
@@ -3880,16 +3878,16 @@
},
{
"name": "nette/utils",
"version": "v4.0.6",
"version": "v4.0.7",
"source": {
"type": "git",
"url": "https://github.com/nette/utils.git",
"reference": "ce708655043c7050eb050df361c5e313cf708309"
"reference": "e67c4061eb40b9c113b218214e42cb5a0dda28f2"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/nette/utils/zipball/ce708655043c7050eb050df361c5e313cf708309",
"reference": "ce708655043c7050eb050df361c5e313cf708309",
"url": "https://api.github.com/repos/nette/utils/zipball/e67c4061eb40b9c113b218214e42cb5a0dda28f2",
"reference": "e67c4061eb40b9c113b218214e42cb5a0dda28f2",
"shasum": ""
},
"require": {
@@ -3960,29 +3958,29 @@
],
"support": {
"issues": "https://github.com/nette/utils/issues",
"source": "https://github.com/nette/utils/tree/v4.0.6"
"source": "https://github.com/nette/utils/tree/v4.0.7"
},
"time": "2025-03-30T21:06:30+00:00"
"time": "2025-06-03T04:55:08+00:00"
},
{
"name": "nunomaduro/collision",
"version": "v8.8.0",
"version": "v8.8.1",
"source": {
"type": "git",
"url": "https://github.com/nunomaduro/collision.git",
"reference": "4cf9f3b47afff38b139fb79ce54fc71799022ce8"
"reference": "44ccb82e3e21efb5446748d2a3c81a030ac22bd5"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/nunomaduro/collision/zipball/4cf9f3b47afff38b139fb79ce54fc71799022ce8",
"reference": "4cf9f3b47afff38b139fb79ce54fc71799022ce8",
"url": "https://api.github.com/repos/nunomaduro/collision/zipball/44ccb82e3e21efb5446748d2a3c81a030ac22bd5",
"reference": "44ccb82e3e21efb5446748d2a3c81a030ac22bd5",
"shasum": ""
},
"require": {
"filp/whoops": "^2.18.0",
"nunomaduro/termwind": "^2.3.0",
"filp/whoops": "^2.18.1",
"nunomaduro/termwind": "^2.3.1",
"php": "^8.2.0",
"symfony/console": "^7.2.5"
"symfony/console": "^7.3.0"
},
"conflict": {
"laravel/framework": "<11.44.2 || >=13.0.0",
@@ -3990,15 +3988,15 @@
},
"require-dev": {
"brianium/paratest": "^7.8.3",
"larastan/larastan": "^3.2",
"laravel/framework": "^11.44.2 || ^12.6",
"laravel/pint": "^1.21.2",
"laravel/sail": "^1.41.0",
"laravel/sanctum": "^4.0.8",
"larastan/larastan": "^3.4.2",
"laravel/framework": "^11.44.2 || ^12.18",
"laravel/pint": "^1.22.1",
"laravel/sail": "^1.43.1",
"laravel/sanctum": "^4.1.1",
"laravel/tinker": "^2.10.1",
"orchestra/testbench-core": "^9.12.0 || ^10.1",
"pestphp/pest": "^3.8.0",
"sebastian/environment": "^7.2.0 || ^8.0"
"orchestra/testbench-core": "^9.12.0 || ^10.4",
"pestphp/pest": "^3.8.2",
"sebastian/environment": "^7.2.1 || ^8.0"
},
"type": "library",
"extra": {
@@ -4061,7 +4059,7 @@
"type": "patreon"
}
],
"time": "2025-04-03T14:33:09+00:00"
"time": "2025-06-11T01:04:21+00:00"
},
{
"name": "nunomaduro/termwind",
@@ -4807,16 +4805,16 @@
},
{
"name": "phpseclib/phpseclib",
"version": "3.0.43",
"version": "3.0.45",
"source": {
"type": "git",
"url": "https://github.com/phpseclib/phpseclib.git",
"reference": "709ec107af3cb2f385b9617be72af8cf62441d02"
"reference": "bd81b90d5963c6b9d87de50357585375223f4dd8"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpseclib/phpseclib/zipball/709ec107af3cb2f385b9617be72af8cf62441d02",
"reference": "709ec107af3cb2f385b9617be72af8cf62441d02",
"url": "https://api.github.com/repos/phpseclib/phpseclib/zipball/bd81b90d5963c6b9d87de50357585375223f4dd8",
"reference": "bd81b90d5963c6b9d87de50357585375223f4dd8",
"shasum": ""
},
"require": {
@@ -4897,7 +4895,7 @@
],
"support": {
"issues": "https://github.com/phpseclib/phpseclib/issues",
"source": "https://github.com/phpseclib/phpseclib/tree/3.0.43"
"source": "https://github.com/phpseclib/phpseclib/tree/3.0.45"
},
"funding": [
{
@@ -4913,7 +4911,7 @@
"type": "tidelift"
}
],
"time": "2024-12-14T21:12:59+00:00"
"time": "2025-06-22T22:54:43+00:00"
},
{
"name": "pragmarx/google2fa",
@@ -5747,20 +5745,20 @@
},
{
"name": "ramsey/uuid",
"version": "4.7.6",
"version": "4.8.1",
"source": {
"type": "git",
"url": "https://github.com/ramsey/uuid.git",
"reference": "91039bc1faa45ba123c4328958e620d382ec7088"
"reference": "fdf4dd4e2ff1813111bd0ad58d7a1ddbb5b56c28"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/ramsey/uuid/zipball/91039bc1faa45ba123c4328958e620d382ec7088",
"reference": "91039bc1faa45ba123c4328958e620d382ec7088",
"url": "https://api.github.com/repos/ramsey/uuid/zipball/fdf4dd4e2ff1813111bd0ad58d7a1ddbb5b56c28",
"reference": "fdf4dd4e2ff1813111bd0ad58d7a1ddbb5b56c28",
"shasum": ""
},
"require": {
"brick/math": "^0.8.8 || ^0.9 || ^0.10 || ^0.11 || ^0.12",
"brick/math": "^0.8.8 || ^0.9 || ^0.10 || ^0.11 || ^0.12 || ^0.13",
"ext-json": "*",
"php": "^8.0",
"ramsey/collection": "^1.2 || ^2.0"
@@ -5769,26 +5767,23 @@
"rhumsaa/uuid": "self.version"
},
"require-dev": {
"captainhook/captainhook": "^5.10",
"captainhook/captainhook": "^5.25",
"captainhook/plugin-composer": "^5.3",
"dealerdirect/phpcodesniffer-composer-installer": "^0.7.0",
"doctrine/annotations": "^1.8",
"ergebnis/composer-normalize": "^2.15",
"mockery/mockery": "^1.3",
"dealerdirect/phpcodesniffer-composer-installer": "^1.0",
"ergebnis/composer-normalize": "^2.47",
"mockery/mockery": "^1.6",
"paragonie/random-lib": "^2",
"php-mock/php-mock": "^2.2",
"php-mock/php-mock-mockery": "^1.3",
"php-parallel-lint/php-parallel-lint": "^1.1",
"phpbench/phpbench": "^1.0",
"phpstan/extension-installer": "^1.1",
"phpstan/phpstan": "^1.8",
"phpstan/phpstan-mockery": "^1.1",
"phpstan/phpstan-phpunit": "^1.1",
"phpunit/phpunit": "^8.5 || ^9",
"ramsey/composer-repl": "^1.4",
"slevomat/coding-standard": "^8.4",
"squizlabs/php_codesniffer": "^3.5",
"vimeo/psalm": "^4.9"
"php-mock/php-mock": "^2.6",
"php-mock/php-mock-mockery": "^1.5",
"php-parallel-lint/php-parallel-lint": "^1.4.0",
"phpbench/phpbench": "^1.2.14",
"phpstan/extension-installer": "^1.4",
"phpstan/phpstan": "^2.1",
"phpstan/phpstan-mockery": "^2.0",
"phpstan/phpstan-phpunit": "^2.0",
"phpunit/phpunit": "^9.6",
"slevomat/coding-standard": "^8.18",
"squizlabs/php_codesniffer": "^3.13"
},
"suggest": {
"ext-bcmath": "Enables faster math with arbitrary-precision integers using BCMath.",
@@ -5823,19 +5818,9 @@
],
"support": {
"issues": "https://github.com/ramsey/uuid/issues",
"source": "https://github.com/ramsey/uuid/tree/4.7.6"
"source": "https://github.com/ramsey/uuid/tree/4.8.1"
},
"funding": [
{
"url": "https://github.com/ramsey",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/ramsey/uuid",
"type": "tidelift"
}
],
"time": "2024-04-27T21:32:50+00:00"
"time": "2025-06-01T06:28:46+00:00"
},
{
"name": "rcrowe/twigbridge",
@@ -10487,16 +10472,16 @@
},
{
"name": "larastan/larastan",
"version": "v3.4.0",
"version": "v3.5.0",
"source": {
"type": "git",
"url": "https://github.com/larastan/larastan.git",
"reference": "1042fa0c2ee490bb6da7381f3323f7292ad68222"
"reference": "e8ccd73008487ba91da9877b373f8c447743f1ce"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/larastan/larastan/zipball/1042fa0c2ee490bb6da7381f3323f7292ad68222",
"reference": "1042fa0c2ee490bb6da7381f3323f7292ad68222",
"url": "https://api.github.com/repos/larastan/larastan/zipball/e8ccd73008487ba91da9877b373f8c447743f1ce",
"reference": "e8ccd73008487ba91da9877b373f8c447743f1ce",
"shasum": ""
},
"require": {
@@ -10564,7 +10549,7 @@
],
"support": {
"issues": "https://github.com/larastan/larastan/issues",
"source": "https://github.com/larastan/larastan/tree/v3.4.0"
"source": "https://github.com/larastan/larastan/tree/v3.5.0"
},
"funding": [
{
@@ -10572,7 +10557,7 @@
"type": "github"
}
],
"time": "2025-04-22T09:44:59+00:00"
"time": "2025-06-19T22:41:50+00:00"
},
{
"name": "laravel-json-api/testing",
@@ -10784,16 +10769,16 @@
},
{
"name": "nikic/php-parser",
"version": "v5.4.0",
"version": "v5.5.0",
"source": {
"type": "git",
"url": "https://github.com/nikic/PHP-Parser.git",
"reference": "447a020a1f875a434d62f2a401f53b82a396e494"
"reference": "ae59794362fe85e051a58ad36b289443f57be7a9"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/447a020a1f875a434d62f2a401f53b82a396e494",
"reference": "447a020a1f875a434d62f2a401f53b82a396e494",
"url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/ae59794362fe85e051a58ad36b289443f57be7a9",
"reference": "ae59794362fe85e051a58ad36b289443f57be7a9",
"shasum": ""
},
"require": {
@@ -10836,9 +10821,9 @@
],
"support": {
"issues": "https://github.com/nikic/PHP-Parser/issues",
"source": "https://github.com/nikic/PHP-Parser/tree/v5.4.0"
"source": "https://github.com/nikic/PHP-Parser/tree/v5.5.0"
},
"time": "2024-12-30T11:07:19+00:00"
"time": "2025-05-31T08:24:38+00:00"
},
{
"name": "phar-io/manifest",
@@ -11231,16 +11216,16 @@
},
{
"name": "phpunit/php-code-coverage",
"version": "12.3.0",
"version": "12.3.1",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/php-code-coverage.git",
"reference": "9075a8efc66e11bc55c319062e147bdb06777267"
"reference": "ddec29dfc128eba9c204389960f2063f3b7fa170"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/9075a8efc66e11bc55c319062e147bdb06777267",
"reference": "9075a8efc66e11bc55c319062e147bdb06777267",
"url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/ddec29dfc128eba9c204389960f2063f3b7fa170",
"reference": "ddec29dfc128eba9c204389960f2063f3b7fa170",
"shasum": ""
},
"require": {
@@ -11296,7 +11281,7 @@
"support": {
"issues": "https://github.com/sebastianbergmann/php-code-coverage/issues",
"security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy",
"source": "https://github.com/sebastianbergmann/php-code-coverage/tree/12.3.0"
"source": "https://github.com/sebastianbergmann/php-code-coverage/tree/12.3.1"
},
"funding": [
{
@@ -11316,7 +11301,7 @@
"type": "tidelift"
}
],
"time": "2025-05-23T15:49:03+00:00"
"time": "2025-06-18T08:58:13+00:00"
},
{
"name": "phpunit/php-file-iterator",
@@ -11565,16 +11550,16 @@
},
{
"name": "phpunit/phpunit",
"version": "12.1.6",
"version": "12.2.3",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/phpunit.git",
"reference": "2fdf0056c673c8f0f1eed00030be5f8243c1e6e0"
"reference": "60a8ea2d8b2f070000051b56778009e11576e7d1"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/2fdf0056c673c8f0f1eed00030be5f8243c1e6e0",
"reference": "2fdf0056c673c8f0f1eed00030be5f8243c1e6e0",
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/60a8ea2d8b2f070000051b56778009e11576e7d1",
"reference": "60a8ea2d8b2f070000051b56778009e11576e7d1",
"shasum": ""
},
"require": {
@@ -11588,15 +11573,15 @@
"phar-io/manifest": "^2.0.4",
"phar-io/version": "^3.2.1",
"php": ">=8.3",
"phpunit/php-code-coverage": "^12.2.1",
"phpunit/php-code-coverage": "^12.3.1",
"phpunit/php-file-iterator": "^6.0.0",
"phpunit/php-invoker": "^6.0.0",
"phpunit/php-text-template": "^5.0.0",
"phpunit/php-timer": "^8.0.0",
"sebastian/cli-parser": "^4.0.0",
"sebastian/comparator": "^7.0.1",
"sebastian/comparator": "^7.1.0",
"sebastian/diff": "^7.0.0",
"sebastian/environment": "^8.0.1",
"sebastian/environment": "^8.0.2",
"sebastian/exporter": "^7.0.0",
"sebastian/global-state": "^8.0.0",
"sebastian/object-enumerator": "^7.0.0",
@@ -11610,7 +11595,7 @@
"type": "library",
"extra": {
"branch-alias": {
"dev-main": "12.1-dev"
"dev-main": "12.2-dev"
}
},
"autoload": {
@@ -11642,7 +11627,7 @@
"support": {
"issues": "https://github.com/sebastianbergmann/phpunit/issues",
"security": "https://github.com/sebastianbergmann/phpunit/security/policy",
"source": "https://github.com/sebastianbergmann/phpunit/tree/12.1.6"
"source": "https://github.com/sebastianbergmann/phpunit/tree/12.2.3"
},
"funding": [
{
@@ -11666,20 +11651,20 @@
"type": "tidelift"
}
],
"time": "2025-05-21T12:36:31+00:00"
"time": "2025-06-20T11:33:06+00:00"
},
{
"name": "rector/rector",
"version": "2.0.17",
"version": "2.0.18",
"source": {
"type": "git",
"url": "https://github.com/rectorphp/rector.git",
"reference": "caa4ffda1d48bde44434e6ba95d132ec32e7fd40"
"reference": "be3a452085b524a04056e3dfe72d861948711062"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/rectorphp/rector/zipball/caa4ffda1d48bde44434e6ba95d132ec32e7fd40",
"reference": "caa4ffda1d48bde44434e6ba95d132ec32e7fd40",
"url": "https://api.github.com/repos/rectorphp/rector/zipball/be3a452085b524a04056e3dfe72d861948711062",
"reference": "be3a452085b524a04056e3dfe72d861948711062",
"shasum": ""
},
"require": {
@@ -11717,7 +11702,7 @@
],
"support": {
"issues": "https://github.com/rectorphp/rector/issues",
"source": "https://github.com/rectorphp/rector/tree/2.0.17"
"source": "https://github.com/rectorphp/rector/tree/2.0.18"
},
"funding": [
{
@@ -11725,7 +11710,7 @@
"type": "github"
}
],
"time": "2025-05-30T10:59:08+00:00"
"time": "2025-06-11T11:19:37+00:00"
},
{
"name": "sebastian/cli-parser",
@@ -11786,16 +11771,16 @@
},
{
"name": "sebastian/comparator",
"version": "7.0.1",
"version": "7.1.0",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/comparator.git",
"reference": "b478f34614f934e0291598d0c08cbaba9644bee5"
"reference": "03d905327dccc0851c9a08d6a979dfc683826b6f"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/b478f34614f934e0291598d0c08cbaba9644bee5",
"reference": "b478f34614f934e0291598d0c08cbaba9644bee5",
"url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/03d905327dccc0851c9a08d6a979dfc683826b6f",
"reference": "03d905327dccc0851c9a08d6a979dfc683826b6f",
"shasum": ""
},
"require": {
@@ -11806,7 +11791,7 @@
"sebastian/exporter": "^7.0"
},
"require-dev": {
"phpunit/phpunit": "^12.0"
"phpunit/phpunit": "^12.2"
},
"suggest": {
"ext-bcmath": "For comparing BcMath\\Number objects"
@@ -11814,7 +11799,7 @@
"type": "library",
"extra": {
"branch-alias": {
"dev-main": "7.0-dev"
"dev-main": "7.1-dev"
}
},
"autoload": {
@@ -11854,15 +11839,27 @@
"support": {
"issues": "https://github.com/sebastianbergmann/comparator/issues",
"security": "https://github.com/sebastianbergmann/comparator/security/policy",
"source": "https://github.com/sebastianbergmann/comparator/tree/7.0.1"
"source": "https://github.com/sebastianbergmann/comparator/tree/7.1.0"
},
"funding": [
{
"url": "https://github.com/sebastianbergmann",
"type": "github"
},
{
"url": "https://liberapay.com/sebastianbergmann",
"type": "liberapay"
},
{
"url": "https://thanks.dev/u/gh/sebastianbergmann",
"type": "thanks_dev"
},
{
"url": "https://tidelift.com/funding/github/packagist/sebastian/comparator",
"type": "tidelift"
}
],
"time": "2025-03-07T07:00:32+00:00"
"time": "2025-06-17T07:41:58+00:00"
},
{
"name": "sebastian/complexity",
+1 -1
View File
@@ -78,7 +78,7 @@ return [
'running_balance_column' => env('USE_RUNNING_BALANCE', false),
// see cer.php for exchange rates feature flag.
],
'version' => 'develop/2025-05-31',
'version' => 'develop/2025-06-23',
'api_version' => '2.1.0', // field is no longer used.
'db_version' => 25,
@@ -67,6 +67,7 @@ class TransactionCurrencySeeder extends Seeder
// asian currencies
$currencies[] = ['code' => 'JPY', 'name' => 'Japanese yen', 'symbol' => '¥', 'decimal_places' => 0];
$currencies[] = ['code' => 'CNY', 'name' => 'Chinese yuan', 'symbol' => '¥', 'decimal_places' => 2];
// $currencies[] = ['code' => 'RMB', 'name' => 'Chinese yuan', 'symbol' => '¥', 'decimal_places' => 2];
$currencies[] = ['code' => 'RUB', 'name' => 'Russian ruble', 'symbol' => '₽', 'decimal_places' => 2];
$currencies[] = ['code' => 'INR', 'name' => 'Indian rupee', 'symbol' => '₹', 'decimal_places' => 2];
+394 -228
View File
File diff suppressed because it is too large Load Diff
+9 -1
View File
@@ -24,4 +24,12 @@ $(function () {
if (typeof(lineChart) === 'function' && typeof(piggyBankID) !== 'undefined') {
lineChart('chart/piggy-bank/' + piggyBankID, 'piggy-bank-history');
}
});
// on submit of logout button:
$('.reset-link').click(function(e) {
console.log('here we are');
e.preventDefault();
document.getElementById('reset-form').submit();
return false;
});
});
+6 -6
View File
@@ -1,11 +1,11 @@
{
"firefly": {
"administrations_page_title": "Financial administrations",
"administrations_index_menu": "Financial administrations",
"administrations_page_title": "Administracions financeres",
"administrations_index_menu": "Administracions financeres",
"expires_at": "Expires at",
"temp_administrations_introduction": "Firefly III will soon get the ability to manage multiple financial administrations. Right now, you only have the one. You can set the title of this administration and its native currency. This replaces the previous setting where you would set your \"default currency\". This setting is now tied to the financial administration and can be different per administration.",
"temp_administrations_introduction": "Firefly III aviat podr\u00e0 gestionar diverses administracions financeres. Ara mateix, nom\u00e9s en teniu una. Podeu definir el t\u00edtol d'aquesta administraci\u00f3 i la seva moneda nativa. Aix\u00f2 substitueix la configuraci\u00f3 anterior on definiu la vostra \"moneda predeterminada\". Aquesta configuraci\u00f3 ara est\u00e0 vinculada a l'administraci\u00f3 financera i pot ser diferent per a cada administraci\u00f3.",
"administration_currency_form_help": "It may take a long time for the page to load if you change the native currency because transaction may need to be converted to your (new) native currency.",
"administrations_page_edit_sub_title_js": "Edit financial administration \"{title}\"",
"administrations_page_edit_sub_title_js": "Edita l'administraci\u00f3 financera \"{title}\"",
"table": "Taula",
"welcome_back": "Qu\u00e8 est\u00e0 passant?",
"flash_error": "Error!",
@@ -20,7 +20,7 @@
"split": "Dividir",
"single_split": "Divisi\u00f3",
"not_enough_currencies": "Not enough currencies",
"not_enough_currencies_enabled": "If you have just one currency enabled, there is no need to add exchange rates.",
"not_enough_currencies_enabled": "Si tens nom\u00e9s una divisa habilitada, no cal afegir tipus de canvi.",
"transaction_stored_link": "La <a href=\"transactions\/show\/{ID}\">Transacci\u00f3 #{ID} (\"{title}\")<\/a> s'ha desat.",
"webhook_stored_link": "S'ha desat <a href=\"webhooks\/show\/{ID}\">el Webook #{ID} (\"{title}\")<\/a> correctament.",
"webhook_updated_link": "S'ha actualitzat el <a href=\"webhooks\/show\/{ID}\">Webook #{ID}<\/a> (\"{title}\").",
@@ -31,7 +31,7 @@
"apply_rules_checkbox": "Aplicar regles",
"fire_webhooks_checkbox": "Disparar webhooks",
"no_budget_pointer": "Sembla que encara no tens cap pressupost. N'hauries de crear alguns a la p\u00e0gina de <a href=\"budgets\">pressuposts<\/a>. Els pressupostos et poden ajudar a fer el seguiment de les teves despeses.",
"no_bill_pointer": "You seem to have no subscription yet. You should create some on the <a href=\"subscriptions\">subscription<\/a>-page. Subscriptions can help you keep track of expenses.",
"no_bill_pointer": "Sembla que encara no tens cap subscripci\u00f3. N'hauries de crear alguns a la p\u00e0gina de <a href=\"subscriptions\">subscripcions<\/a>. Les subscripcions et poden ajudar a fer el seguiment de les teves despeses.",
"source_account": "Compte d'origen",
"hidden_fields_preferences": "Pots habilitar m\u00e9s opcions de transacci\u00f3 a la <a href=\"preferences\">configuraci\u00f3<\/a>.",
"destination_account": "Compte de dest\u00ed",
+3 -3
View File
@@ -112,7 +112,7 @@
"webhook_trigger_DESTROY_TRANSACTION": "After transaction delete",
"webhook_response_TRANSACTIONS": "Transaction details",
"webhook_response_ACCOUNTS": "Account details",
"webhook_response_none_NONE": "No details",
"webhook_response_none_NONE": "Tidak ada detil",
"webhook_delivery_JSON": "JSON",
"actions": "Tindakan",
"meta_data": "Data meta",
@@ -129,7 +129,7 @@
"edit_webhook_js": "Edit webhook \"{title}\"",
"webhook_was_triggered": "The webhook was triggered on the indicated transaction. Please wait for results to appear.",
"view_message": "View message",
"view_attempts": "View failed attempts",
"view_attempts": "Lihat upaya yang gagal",
"message_content_title": "Webhook message content",
"message_content_help": "This is the content of the message that was sent (or tried) using this webhook.",
"attempt_content_title": "Webhook attempts",
@@ -137,7 +137,7 @@
"no_attempts": "There are no unsuccessful attempts. That's a good thing!",
"webhook_attempt_at": "Attempt at {moment}",
"logs": "Log",
"response": "Response",
"response": "Tanggapan",
"visit_webhook_url": "Visit webhook URL",
"reset_webhook_secret": "Reset webhook secret",
"header_exchange_rates": "Exchange rates",

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