Compare commits

...

28 Commits

Author SHA1 Message Date
github-actions
b7dad8166d Auto commit for release 'v6.2.6' on 2025-02-12 2025-02-12 20:06:45 +01:00
James Cole
2da1b43c37 Expand changelog. 2025-02-12 20:01:45 +01:00
James Cole
a606315884 Fix balance display #9826 2025-02-12 11:53:51 +01:00
github-actions
295feedd77 Auto commit for release 'develop' on 2025-02-12 2025-02-12 10:50:48 +01:00
James Cole
d3b2748c8f Ok this fix for #9797 goes out to @nebster9k who is delightfully stubborn and absolutely correct. 2025-02-12 06:38:21 +01:00
James Cole
1b4655fd70 Fix #9821 2025-02-12 06:06:28 +01:00
Sander Dorigo
05f67ef584 Fix #9810 2025-02-11 16:27:18 +01:00
Sander Dorigo
04ab7ba07d qMerge branch 'develop' of https://github.com/firefly-iii/firefly-iii into develop 2025-02-11 16:10:48 +01:00
Sander Dorigo
5806323970 Add some notes 2025-02-11 16:10:16 +01:00
github-actions
ee260a3df7 Auto commit for release 'develop' on 2025-02-11 2025-02-11 10:47:28 +01:00
Sander Dorigo
7cb41fb333 fix a null pointer 2025-02-11 10:41:32 +01:00
Sander Dorigo
d38adbfdc2 Fix #9808 2025-02-11 08:39:44 +01:00
Sander Dorigo
e6a6766ef1 update instructions 2025-02-11 08:36:24 +01:00
James Cole
a1e596491c Add debug logging. 2025-02-11 06:13:28 +01:00
James Cole
9c920908a6 Fix type errors 2025-02-11 06:06:30 +01:00
James Cole
0014bffeb8 Fix #9807 2025-02-11 06:06:09 +01:00
James Cole
63c17f99b2 Fix parse error 2025-02-11 06:05:47 +01:00
James Cole
ec1e0e2807 New notifications controller (not yet used) 2025-02-11 05:53:34 +01:00
Sander Dorigo
2f16419a7b Add debug logging to finalAccountBalance. 2025-02-10 16:47:59 +01:00
James Cole
02c13859e7 Update ValidatesUserGroupTrait.php
Signed-off-by: James Cole <james@firefly-iii.org>
2025-02-10 10:28:50 +01:00
github-actions
57ec9b8e36 Auto commit for release 'develop' on 2025-02-10 2025-02-10 04:10:23 +01:00
James Cole
41ad35880d Fix #9797 2025-02-09 17:39:18 +01:00
James Cole
3aa946e028 Fix nullpointer. 2025-02-09 09:35:26 +01:00
James Cole
53e46895aa Expand a few repositories to support user groups. 2025-02-09 09:30:44 +01:00
James Cole
c61389037d Small code cleanup. 2025-02-09 07:10:05 +01:00
James Cole
6172d60e00 Fix phpstan issues (or ignore them). 2025-02-09 07:02:12 +01:00
github-actions
f909f1d9ff Auto commit for release 'develop' on 2025-02-09 2025-02-09 06:14:15 +01:00
James Cole
55018ca046 Remove duplicate copyright statement. 2025-02-09 06:10:46 +01:00
72 changed files with 432 additions and 249 deletions

View File

@@ -189,7 +189,7 @@ SEND_REPORT_JOURNALS=true
ENABLE_EXTERNAL_MAP=false
#
# Enable or disable exchange rate conversion. This function isn't used yet by Firefly III
# Enable or disable exchange rate conversion.
#
ENABLE_EXCHANGE_RATES=false

View File

@@ -34,6 +34,7 @@ use FireflyIII\Support\Facades\Steam;
use FireflyIII\Support\Http\Api\AccountFilter;
use FireflyIII\User;
use Illuminate\Http\JsonResponse;
use Illuminate\Support\Facades\Log;
/**
* Class AccountController
@@ -83,8 +84,8 @@ class AccountController extends Controller
$return = [];
$result = $this->repository->searchAccount((string) $query, $types, $this->parameters->get('limit'));
// set date to end-of-day for account balance.
$date->endOfDay();
// set date to subday + end-of-day for account balance. so it is at $date 23:59:59
$date->subDay()->endOfDay();
/** @var Account $account */
foreach ($result as $account) {
@@ -92,6 +93,8 @@ class AccountController extends Controller
$currency = $this->repository->getAccountCurrency($account) ?? $this->nativeCurrency;
$useCurrency = $currency;
if (in_array($account->accountType->type, $this->balanceTypes, true)) {
// this one is correct.
Log::debug(sprintf('accounts: Call finalAccountBalance with date/time "%s"', $date->toIso8601String()));
$balance = Steam::finalAccountBalance($account, $date);
$key = $this->convertToNative && $currency->id !== $this->nativeCurrency->id ? 'native_balance' : 'balance';
$useCurrency = $this->convertToNative && $currency->id !== $this->nativeCurrency->id ? $this->nativeCurrency : $currency;

View File

@@ -26,6 +26,7 @@ namespace FireflyIII\Api\V1\Controllers\Autocomplete;
use FireflyIII\Api\V1\Controllers\Controller;
use FireflyIII\Api\V1\Requests\Autocomplete\AutocompleteRequest;
use FireflyIII\Enums\UserRoleEnum;
use FireflyIII\Models\TransactionJournal;
use FireflyIII\Repositories\Journal\JournalRepositoryInterface;
use FireflyIII\Repositories\TransactionGroup\TransactionGroupRepositoryInterface;
@@ -41,6 +42,8 @@ class TransactionController extends Controller
private TransactionGroupRepositoryInterface $groupRepository;
private JournalRepositoryInterface $repository;
protected array $acceptedRoles = [UserRoleEnum::READ_ONLY];
/**
* TransactionController constructor.
*/
@@ -51,10 +54,12 @@ class TransactionController extends Controller
function ($request, $next) {
/** @var User $user */
$user = auth()->user();
$userGroup = $this->validateUserGroup($request);
$this->repository = app(JournalRepositoryInterface::class);
$this->groupRepository = app(TransactionGroupRepositoryInterface::class);
$this->repository->setUser($user);
$this->groupRepository->setUser($user);
$this->groupRepository->setUserGroup($userGroup);
return $next($request);
}

View File

@@ -31,6 +31,7 @@ use FireflyIII\Models\Preference;
use FireflyIII\Models\TransactionCurrency;
use FireflyIII\Support\Facades\Amount;
use FireflyIII\Support\Facades\Steam;
use FireflyIII\Support\Http\Api\ValidatesUserGroupTrait;
use FireflyIII\Transformers\V2\AbstractTransformer;
use FireflyIII\User;
use Illuminate\Database\Eloquent\Model;
@@ -59,6 +60,7 @@ abstract class Controller extends BaseController
use AuthorizesRequests;
use DispatchesJobs;
use ValidatesRequests;
use ValidatesUserGroupTrait;
protected const string CONTENT_TYPE = 'application/vnd.api+json';
protected const string JSON_CONTENT_TYPE = 'application/json';

View File

@@ -26,6 +26,7 @@ namespace FireflyIII\Api\V1\Controllers\Models\Transaction;
use FireflyIII\Api\V1\Controllers\Controller;
use FireflyIII\Api\V1\Requests\Models\Transaction\StoreRequest;
use FireflyIII\Enums\UserRoleEnum;
use FireflyIII\Events\StoredTransactionGroup;
use FireflyIII\Exceptions\DuplicateTransactionException;
use FireflyIII\Exceptions\FireflyException;
@@ -37,6 +38,7 @@ use FireflyIII\Transformers\TransactionGroupTransformer;
use FireflyIII\User;
use Illuminate\Http\JsonResponse;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Validator;
use Illuminate\Validation\ValidationException;
use League\Fractal\Resource\Item;
@@ -49,6 +51,8 @@ class StoreController extends Controller
private TransactionGroupRepositoryInterface $groupRepository;
protected array $acceptedRoles = [UserRoleEnum::MANAGE_TRANSACTIONS];
/**
* TransactionController constructor.
*/
@@ -59,9 +63,11 @@ class StoreController extends Controller
function ($request, $next) {
/** @var User $admin */
$admin = auth()->user();
$userGroup = $this->validateUserGroup($request);
$this->groupRepository = app(TransactionGroupRepositoryInterface::class);
$this->groupRepository->setUser($admin);
$this->groupRepository->setUserGroup($userGroup);
return $next($request);
}
@@ -79,61 +85,58 @@ class StoreController extends Controller
public function store(StoreRequest $request): JsonResponse
{
app('log')->debug('Now in API StoreController::store()');
$data = $request->getAll();
$data['user'] = auth()->user()->id;
$data = $request->getAll();
$data['user'] = auth()->user();
$data['user_group'] = $this->userGroup;
Log::channel('audit')
->info('Store new transaction over API.', $data)
;
Log::channel('audit')->info('Store new transaction over API.', $data);
try {
$transactionGroup = $this->groupRepository->store($data);
} catch (DuplicateTransactionException $e) {
app('log')->warning('Caught a duplicate transaction. Return error message.');
$validator = \Validator::make(
['transactions' => [['description' => $e->getMessage()]]],
['transactions.0.description' => new IsDuplicateTransaction()]
);
$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());
$message = sprintf('Internal exception: %s', $e->getMessage());
$validator = \Validator::make(['transactions' => [['description' => $message]]], ['transactions.0.description' => new IsDuplicateTransaction()]);
$validator = Validator::make(['transactions' => [['description' => $message]]], ['transactions.0.description' => new IsDuplicateTransaction()]);
throw new ValidationException($validator);
}
app('preferences')->mark();
$applyRules = $data['apply_rules'] ?? true;
$fireWebhooks = $data['fire_webhooks'] ?? true;
$applyRules = $data['apply_rules'] ?? true;
$fireWebhooks = $data['fire_webhooks'] ?? true;
event(new StoredTransactionGroup($transactionGroup, $applyRules, $fireWebhooks));
$manager = $this->getManager();
$manager = $this->getManager();
/** @var User $admin */
$admin = auth()->user();
$admin = auth()->user();
// use new group collector:
/** @var GroupCollectorInterface $collector */
$collector = app(GroupCollectorInterface::class);
$collector = app(GroupCollectorInterface::class);
$collector
->setUser($admin)
->setUserGroup($this->userGroup)
// filter on transaction group.
->setTransactionGroup($transactionGroup)
// all info needed for the API:
->withAPIInformation()
;
$selectedGroup = $collector->getGroups()->first();
$selectedGroup = $collector->getGroups()->first();
if (null === $selectedGroup) {
throw new FireflyException('200032: Cannot find transaction. Possibly, a rule deleted this transaction after its creation.');
}
/** @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);
}

View File

@@ -21,25 +21,6 @@
*/
declare(strict_types=1);
/*
* ConvertDatesToUTC.php
* Copyright (c) 2024 james@firefly-iii.org.
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see https://www.gnu.org/licenses/.
*/
namespace FireflyIII\Console\Commands\Correction;

View File

@@ -21,25 +21,6 @@
*/
declare(strict_types=1);
/*
* AddTimezonesToDates.php
* Copyright (c) 2024 james@firefly-iii.org.
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see https://www.gnu.org/licenses/.
*/
namespace FireflyIII\Console\Commands\Correction;

View File

@@ -26,6 +26,7 @@ namespace FireflyIII\Factory;
use FireflyIII\Models\Location;
use FireflyIII\Models\Tag;
use FireflyIII\Models\UserGroup;
use FireflyIII\User;
/**
@@ -34,6 +35,7 @@ use FireflyIII\User;
class TagFactory
{
private User $user;
private UserGroup $userGroup;
public function findOrCreate(string $tag): ?Tag
{
@@ -101,6 +103,12 @@ class TagFactory
public function setUser(User $user): void
{
$this->user = $user;
$this->user = $user;
$this->userGroup = $user->userGroup;
}
public function setUserGroup(UserGroup $userGroup): void
{
$this->userGroup = $userGroup;
}
}

View File

@@ -31,7 +31,6 @@ use FireflyIII\Models\TransactionCurrency;
use FireflyIII\Models\TransactionJournal;
use FireflyIII\Rules\UniqueIban;
use FireflyIII\Services\Internal\Update\AccountUpdateService;
use FireflyIII\User;
use Illuminate\Database\QueryException;
/**
@@ -216,12 +215,4 @@ class TransactionFactory
{
$this->reconciled = $reconciled;
}
/**
* @SuppressWarnings("PHPMD.UnusedFormalParameter")
*/
public function setUser(User $user): void
{
// empty function.
}
}

View File

@@ -27,6 +27,7 @@ namespace FireflyIII\Factory;
use FireflyIII\Exceptions\DuplicateTransactionException;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Models\TransactionGroup;
use FireflyIII\Models\UserGroup;
use FireflyIII\User;
/**
@@ -36,6 +37,7 @@ class TransactionGroupFactory
{
private TransactionJournalFactory $journalFactory;
private User $user;
private UserGroup $userGroup;
/**
* TransactionGroupFactory constructor.
@@ -54,7 +56,8 @@ class TransactionGroupFactory
public function create(array $data): TransactionGroup
{
app('log')->debug('Now in TransactionGroupFactory::create()');
$this->journalFactory->setUser($this->user);
$this->journalFactory->setUser($data['user']);
$this->journalFactory->setUserGroup($data['user_group']);
$this->journalFactory->setErrorOnHash($data['error_if_duplicate_hash'] ?? false);
try {
@@ -76,7 +79,7 @@ class TransactionGroupFactory
$group = new TransactionGroup();
$group->user()->associate($this->user);
$group->userGroup()->associate($data['user_group'] ?? $this->user->userGroup);
$group->userGroup()->associate($data['user_group']);
$group->title = $title;
$group->save();
@@ -92,4 +95,9 @@ class TransactionGroupFactory
{
$this->user = $user;
}
public function setUserGroup(UserGroup $userGroup): void
{
$this->userGroup = $userGroup;
}
}

View File

@@ -34,6 +34,7 @@ use FireflyIII\Models\Transaction;
use FireflyIII\Models\TransactionCurrency;
use FireflyIII\Models\TransactionJournal;
use FireflyIII\Models\TransactionJournalMeta;
use FireflyIII\Models\UserGroup;
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use FireflyIII\Repositories\Bill\BillRepositoryInterface;
use FireflyIII\Repositories\Budget\BudgetRepositoryInterface;
@@ -69,6 +70,7 @@ class TransactionJournalFactory
private PiggyBankRepositoryInterface $piggyRepository;
private TransactionTypeRepositoryInterface $typeRepository;
private User $user;
private UserGroup $userGroup;
/**
* Constructor.
@@ -176,7 +178,6 @@ class TransactionJournalFactory
if (true === FireflyConfig::get('utc', false)->data) {
$carbon->setTimezone('UTC');
}
// $carbon->setTimezone('UTC');
try {
// validate source and destination using a new Validator.
@@ -228,7 +229,7 @@ class TransactionJournalFactory
$journal = TransactionJournal::create(
[
'user_id' => $this->user->id,
'user_group_id' => $this->user->user_group_id,
'user_group_id' => $this->userGroup->id,
'transaction_type_id' => $type->id,
'bill_id' => $billId,
'transaction_currency_id' => $currency->id,
@@ -244,7 +245,6 @@ class TransactionJournalFactory
/** Create two transactions. */
$transactionFactory = app(TransactionFactory::class);
$transactionFactory->setUser($this->user);
$transactionFactory->setJournal($journal);
$transactionFactory->setAccount($sourceAccount);
$transactionFactory->setCurrency($currency);
@@ -263,7 +263,6 @@ class TransactionJournalFactory
/** @var TransactionFactory $transactionFactory */
$transactionFactory = app(TransactionFactory::class);
$transactionFactory->setUser($this->user);
$transactionFactory->setJournal($journal);
$transactionFactory->setAccount($destinationAccount);
$transactionFactory->setAccountInformation($destInfo);
@@ -404,7 +403,8 @@ class TransactionJournalFactory
*/
public function setUser(User $user): void
{
$this->user = $user;
$this->user = $user;
$this->userGroup = $user->userGroup;
$this->currencyRepository->setUser($this->user);
$this->tagFactory->setUser($user);
$this->billRepository->setUser($this->user);
@@ -414,6 +414,18 @@ class TransactionJournalFactory
$this->accountRepository->setUser($this->user);
}
public function setUserGroup(UserGroup $userGroup): void
{
$this->userGroup = $userGroup;
$this->currencyRepository->setUserGroup($userGroup);
$this->tagFactory->setUserGroup($userGroup);
$this->billRepository->setUserGroup($userGroup);
$this->budgetRepository->setUserGroup($userGroup);
$this->categoryRepository->setUserGroup($userGroup);
$this->piggyRepository->setUserGroup($userGroup);
$this->accountRepository->setUserGroup($userGroup);
}
private function reconciliationSanityCheck(?Account $sourceAccount, ?Account $destinationAccount): array
{
app('log')->debug(sprintf('Now in %s', __METHOD__));

View File

@@ -33,6 +33,7 @@ use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use FireflyIII\Repositories\Journal\JournalRepositoryInterface;
use FireflyIII\Support\Facades\Steam;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Log;
/**
* Class MonthReportGenerator.
@@ -52,10 +53,9 @@ class MonthReportGenerator implements ReportGeneratorInterface
{
$auditData = [];
$dayBefore = clone $this->start;
$dayBefore->subDay();
// move to end of day
$dayBefore->endOfDay();
// set date to subday + end-of-day for account balance. so it is at $date 23:59:59
$dayBefore->subDay()->endOfDay();
/** @var Account $account */
foreach ($this->accounts as $account) {
@@ -136,6 +136,8 @@ class MonthReportGenerator implements ReportGeneratorInterface
;
$journals = $collector->getExtractedJournals();
$journals = array_reverse($journals, true);
// this call is correct.
Log::debug(sprintf('getAuditReport: Call finalAccountBalance with date/time "%s"', $date->toIso8601String()));
$dayBeforeBalance = Steam::finalAccountBalance($account, $date);
$startBalance = $dayBeforeBalance['balance'];
$defaultCurrency = app('amount')->getNativeCurrencyByUserGroup($account->user->userGroup);
@@ -170,6 +172,8 @@ class MonthReportGenerator implements ReportGeneratorInterface
$journals[$index]['invoice_date'] = $journalRepository->getMetaDateById($journal['transaction_journal_id'], 'invoice_date');
}
$locale = app('steam')->getLocale();
// call is correct.
Log::debug(sprintf('getAuditReport end: Call finalAccountBalance with date/time "%s"', $this->end->toIso8601String()));
return [
'journals' => $journals,

View File

@@ -25,6 +25,7 @@ declare(strict_types=1);
namespace FireflyIII\Handlers\Observer;
use FireflyIII\Models\Account;
use FireflyIII\Models\Attachment;
use FireflyIII\Models\PiggyBank;
use FireflyIII\Repositories\Attachment\AttachmentRepositoryInterface;
use FireflyIII\Repositories\UserGroups\Account\AccountRepositoryInterface;
@@ -81,6 +82,8 @@ class AccountObserver
foreach ($account->piggyBanks()->get() as $piggy) {
$piggy->accounts()->detach($account);
}
/** @var Attachment $attachment */
foreach ($account->attachments()->get() as $attachment) {
$repository->destroy($attachment);
}

View File

@@ -23,6 +23,7 @@ declare(strict_types=1);
namespace FireflyIII\Handlers\Observer;
use FireflyIII\Models\Attachment;
use FireflyIII\Models\Bill;
use FireflyIII\Repositories\Attachment\AttachmentRepositoryInterface;
use FireflyIII\Support\Facades\Amount;
@@ -46,6 +47,7 @@ class BillObserver
$repository->setUser($bill->user);
// app('log')->debug('Observe "deleting" of a bill.');
/** @var Attachment $attachment */
foreach ($bill->attachments()->get() as $attachment) {
$repository->destroy($attachment);
}

View File

@@ -23,6 +23,7 @@ declare(strict_types=1);
namespace FireflyIII\Handlers\Observer;
use FireflyIII\Models\Attachment;
use FireflyIII\Models\Budget;
use FireflyIII\Models\BudgetLimit;
use FireflyIII\Repositories\Attachment\AttachmentRepositoryInterface;
@@ -39,6 +40,7 @@ class BudgetObserver
$repository = app(AttachmentRepositoryInterface::class);
$repository->setUser($budget->user);
/** @var Attachment $attachment */
foreach ($budget->attachments()->get() as $attachment) {
$repository->destroy($attachment);
}

View File

@@ -23,6 +23,7 @@ declare(strict_types=1);
namespace FireflyIII\Handlers\Observer;
use FireflyIII\Models\Attachment;
use FireflyIII\Models\Category;
use FireflyIII\Repositories\Attachment\AttachmentRepositoryInterface;
@@ -38,6 +39,7 @@ class CategoryObserver
$repository = app(AttachmentRepositoryInterface::class);
$repository->setUser($category->user);
/** @var Attachment $attachment */
foreach ($category->attachments()->get() as $attachment) {
$repository->destroy($attachment);
}

View File

@@ -24,6 +24,7 @@ declare(strict_types=1);
namespace FireflyIII\Handlers\Observer;
use FireflyIII\Models\Attachment;
use FireflyIII\Models\PiggyBank;
use FireflyIII\Repositories\Attachment\AttachmentRepositoryInterface;
use FireflyIII\Support\Http\Api\ExchangeRateConverter;
@@ -50,6 +51,7 @@ class PiggyBankObserver
$repository = app(AttachmentRepositoryInterface::class);
$repository->setUser($piggyBank->accounts()->first()->user);
/** @var Attachment $attachment */
foreach ($piggyBank->attachments()->get() as $attachment) {
$repository->destroy($attachment);
}

View File

@@ -23,6 +23,7 @@ declare(strict_types=1);
namespace FireflyIII\Handlers\Observer;
use FireflyIII\Models\Attachment;
use FireflyIII\Models\Recurrence;
use FireflyIII\Repositories\Attachment\AttachmentRepositoryInterface;
@@ -38,6 +39,7 @@ class RecurrenceObserver
$repository = app(AttachmentRepositoryInterface::class);
$repository->setUser($recurrence->user);
/** @var Attachment $attachment */
foreach ($recurrence->attachments()->get() as $attachment) {
$repository->destroy($attachment);
}

View File

@@ -23,6 +23,7 @@ declare(strict_types=1);
namespace FireflyIII\Handlers\Observer;
use FireflyIII\Models\Attachment;
use FireflyIII\Models\Tag;
use FireflyIII\Repositories\Attachment\AttachmentRepositoryInterface;
@@ -38,6 +39,7 @@ class TagObserver
$repository = app(AttachmentRepositoryInterface::class);
$repository->setUser($tag->user);
/** @var Attachment $attachment */
foreach ($tag->attachments()->get() as $attachment) {
$repository->destroy($attachment);
}

View File

@@ -23,6 +23,7 @@ declare(strict_types=1);
namespace FireflyIII\Handlers\Observer;
use FireflyIII\Models\Attachment;
use FireflyIII\Models\TransactionJournal;
use FireflyIII\Repositories\Attachment\AttachmentRepositoryInterface;
@@ -45,6 +46,8 @@ class TransactionJournalObserver
$transaction->delete();
}
});
/** @var Attachment $attachment */
foreach ($transactionJournal->attachments()->get() as $attachment) {
$repository->destroy($attachment);
}

View File

@@ -258,7 +258,12 @@ trait AccountCollection
if (null === $account) {
continue;
}
$balance = Steam::finalAccountBalance($account, $transaction['date']);
// the balance must be found BEFORE the transaction date.
// so sub one second. This is not perfect, but works well enough.
$date = clone $transaction['date'];
$date->subSecond();
Log::debug(sprintf('accountBalanceIs: Call finalAccountBalance with date/time "%s"', $date->toIso8601String()));
$balance = Steam::finalAccountBalance($account, $date);
$result = bccomp($balance['balance'], $value);
Log::debug(sprintf('"%s" vs "%s" is %d', $balance['balance'], $value, $result));

View File

@@ -79,6 +79,7 @@ class NetWorth implements NetWorthInterface
Log::debug(sprintf('Now in byAccounts("%s", "%s")', $ids, $date->format('Y-m-d H:i:s')));
$default = Amount::getNativeCurrency();
$netWorth = [];
Log::debug(sprintf('NetWorth: finalAccountsBalance("%s")', $date->format('Y-m-d H:i:s')));
$balances = Steam::finalAccountsBalance($accounts, $date);
/** @var Account $account */
@@ -159,6 +160,7 @@ class NetWorth implements NetWorthInterface
*/
$accounts = $this->getAccounts();
$return = [];
Log::debug(sprintf('SumNetWorth: finalAccountsBalance("%s")', $date->format('Y-m-d H:i:s')));
$balances = Steam::finalAccountsBalance($accounts, $date);
foreach ($accounts as $account) {
$currency = $this->getRepository()->getAccountCurrency($account);

View File

@@ -33,6 +33,7 @@ use FireflyIII\Support\Http\Controllers\BasicDataSupport;
use Illuminate\Contracts\View\Factory;
use Illuminate\Http\Request;
use Illuminate\Pagination\LengthAwarePaginator;
use Illuminate\Support\Facades\Log;
use Illuminate\View\View;
/**
@@ -90,9 +91,11 @@ class IndexController extends Controller
$start->subDay();
$ids = $accounts->pluck('id')->toArray();
$startBalances = app('steam')->finalAccountsBalance($accounts, $start);
$endBalances = app('steam')->finalAccountsBalance($accounts, $end);
$activities = app('steam')->getLastActivities($ids);
Log::debug(sprintf('inactive start: finalAccountsBalance("%s")', $start->format('Y-m-d H:i:s')));
Log::debug(sprintf('inactive end: finalAccountsBalance("%s")', $end->format('Y-m-d H:i:s')));
$startBalances = Steam::finalAccountsBalance($accounts, $start);
$endBalances = Steam::finalAccountsBalance($accounts, $end);
$activities = Steam::getLastActivities($ids);
$accounts->each(
@@ -102,7 +105,7 @@ class IndexController extends Controller
$account->startBalances = Steam::filterAccountBalance($startBalances[$account->id] ?? [], $account, $this->convertToNative, $currency);
$account->endBalances = Steam::filterAccountBalance($endBalances[$account->id] ?? [], $account, $this->convertToNative, $currency);
$account->differences = $this->subtract($account->startBalances, $account->endBalances);
$account->interest = app('steam')->bcround($this->repository->getMetaValue($account, 'interest'), 4);
$account->interest = Steam::bcround($this->repository->getMetaValue($account, 'interest'), 4);
$account->interestPeriod = (string) trans(sprintf('firefly.interest_calc_%s', $this->repository->getMetaValue($account, 'interest_period')));
$account->accountTypeString = (string) trans(sprintf('firefly.account_type_%s', $account->accountType->type));
$account->current_debt = '0';
@@ -153,9 +156,11 @@ class IndexController extends Controller
$start->subDay();
$ids = $accounts->pluck('id')->toArray();
$startBalances = app('steam')->finalAccountsBalance($accounts, $start);
$endBalances = app('steam')->finalAccountsBalance($accounts, $end);
$activities = app('steam')->getLastActivities($ids);
Log::debug(sprintf('index start: finalAccountsBalance("%s")', $start->format('Y-m-d H:i:s')));
Log::debug(sprintf('index end: finalAccountsBalance("%s")', $end->format('Y-m-d H:i:s')));
$startBalances = Steam::finalAccountsBalance($accounts, $start);
$endBalances = Steam::finalAccountsBalance($accounts, $end);
$activities = Steam::getLastActivities($ids);
$accounts->each(
@@ -168,7 +173,7 @@ class IndexController extends Controller
$account->endBalances = Steam::filterAccountBalance($endBalances[$account->id] ?? [], $account, $this->convertToNative, $currency);
$account->differences = $this->subtract($account->startBalances, $account->endBalances);
$account->lastActivityDate = $this->isInArrayDate($activities, $account->id);
$account->interest = app('steam')->bcround($interest, 4);
$account->interest = Steam::bcround($interest, 4);
$account->interestPeriod = (string) trans(
sprintf('firefly.interest_calc_%s', $this->repository->getMetaValue($account, 'interest_period'))
);

View File

@@ -39,6 +39,7 @@ use FireflyIII\User;
use Illuminate\Contracts\View\Factory;
use Illuminate\Http\RedirectResponse;
use Illuminate\Routing\Redirector;
use Illuminate\Support\Facades\Log;
use Illuminate\View\View;
/**
@@ -113,7 +114,10 @@ class ReconcileController extends Controller
$end->endOfDay();
$startDate = clone $start;
$startDate->subDay()->endOfDay();
$startDate->subDay()->endOfDay(); // this is correct, subday endofday ends at 23:59:59
// both are validated and are correct.
Log::debug(sprintf('reconcile: Call finalAccountBalance with date/time "%s"', $startDate->toIso8601String()));
Log::debug(sprintf('reconcile2: Call finalAccountBalance with date/time "%s"', $end->toIso8601String()));
$startBalance = Steam::bcround(Steam::finalAccountBalance($account, $startDate)['balance'], $currency->decimal_places);
$endBalance = Steam::bcround(Steam::finalAccountBalance($account, $end)['balance'], $currency->decimal_places);
$subTitleIcon = config(sprintf('firefly.subIconsByIdentifier.%s', $account->accountType->type));

View File

@@ -37,6 +37,7 @@ use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Routing\Redirector;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Log;
use Illuminate\View\View;
/**
@@ -120,12 +121,7 @@ class ShowController extends Controller
/** @var GroupCollectorInterface $collector */
$collector = app(GroupCollectorInterface::class);
$collector
->setAccounts(new Collection([$account]))
->setLimit($pageSize)
->setPage($page)->withAccountInformation()->withCategoryInformation()
->setRange($start, $end)
;
$collector->setAccounts(new Collection([$account]))->setLimit($pageSize)->setPage($page)->withAccountInformation()->withCategoryInformation()->setRange($start, $end);
// this search will not include transaction groups where this asset account (or liability)
// is just part of ONE of the journals. To force this:
@@ -135,7 +131,14 @@ class ShowController extends Controller
$groups->setPath(route('accounts.show', [$account->id, $start->format('Y-m-d'), $end->format('Y-m-d')]));
$showAll = false;
$balances = Steam::filterAccountBalance(Steam::finalAccountBalance($account, $end), $account, $this->convertToNative, $accountCurrency);
// correct
$now = today()->endOfDay();
if ($now->gt($end) || $now->lt($start)) {
$now = $end;
}
Log::debug(sprintf('show: Call finalAccountBalance with date/time "%s"', $now->toIso8601String()));
$balances = Steam::filterAccountBalance(Steam::finalAccountBalance($account, $now), $account, $this->convertToNative, $accountCurrency);
return view(
'accounts.show',
@@ -200,6 +203,8 @@ class ShowController extends Controller
$groups->setPath(route('accounts.show.all', [$account->id]));
$chartUrl = route('chart.account.period', [$account->id, $start->format('Y-m-d'), $end->format('Y-m-d')]);
$showAll = true;
// correct
Log::debug(sprintf('showAll: Call finalAccountBalance with date/time "%s"', $end->toIso8601String()));
$balances = Steam::filterAccountBalance(Steam::finalAccountBalance($account, $end), $account, $this->convertToNative, $accountCurrency);
return view(

View File

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

View File

@@ -168,15 +168,14 @@ class BudgetController extends Controller
}
$locale = app('steam')->getLocale();
$entries = [];
$amount = $budgetLimit->amount;
$amount = $budgetLimit->amount ?? '0';
$budgetCollection = new Collection([$budget]);
$currency = $budgetLimit->transactionCurrency;
if ($this->convertToNative) {
$amount = $budgetLimit->native_amount;
$amount = $budgetLimit->native_amount ?? '0';
$currency = $this->defaultCurrency;
}
while ($start <= $end) {
$current = clone $start;
$expenses = $this->opsRepository->sumExpenses($current, $current, null, $budgetCollection, $budgetLimit->transactionCurrency);

View File

@@ -100,7 +100,10 @@ class ReportController extends Controller
while ($current < $end) {
// get balances by date, grouped by currency.
$result = $helper->byAccounts($filtered, $current);
$balanceCurrent = clone $current;
$balanceCurrent->subDay()->endOfDay(); // go to correct moment.
Log::debug(sprintf('Call byAccounts("%s")', $balanceCurrent->format('Y-m-d H:i:s')));
$result = $helper->byAccounts($filtered, $balanceCurrent);
// loop result, add to array.
/** @var array $netWorthItem */

View File

@@ -259,7 +259,7 @@ class DebugController extends Controller
$system = $this->getSystemInformation();
$docker = $this->getBuildInfo();
$app = $this->getAppInfo();
$user = $this->getuserInfo();
$user = $this->getUserInfo();
return (string) view('partials.debug-table', compact('system', 'docker', 'app', 'user'));
}

View File

@@ -195,15 +195,23 @@ class ReconcileController extends Controller
$startDate->subDay();
$currency = $this->accountRepos->getAccountCurrency($account) ?? $this->defaultCurrency;
// correct
Log::debug(sprintf('transactions: Call finalAccountBalance with date/time "%s"', $startDate->toIso8601String()));
Log::debug(sprintf('transactions2: Call finalAccountBalance with date/time "%s"', $end->toIso8601String()));
$startBalance = Steam::bcround(Steam::finalAccountBalance($account, $startDate)['balance'], $currency->decimal_places);
$endBalance = Steam::bcround(Steam::finalAccountBalance($account, $end)['balance'], $currency->decimal_places);
// get the transactions
$selectionStart = clone $start;
$selectionStart->startOfDay();
$selectionStart->subDays(3);
$selectionEnd = clone $end;
$selectionEnd->endOfDay();
$selectionEnd->addDays(3);
// to make sure the bar is in the right place:
$start->startOfDay();
// grab transactions:
/** @var GroupCollectorInterface $collector */
$collector = app(GroupCollectorInterface::class);

View File

@@ -0,0 +1,29 @@
<?php
/*
* NotificationsController.php
* Copyright (c) 2025 james@firefly-iii.org.
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see https://www.gnu.org/licenses/.
*/
declare(strict_types=1);
namespace FireflyIII\Http\Controllers\Preferences;
use FireflyIII\Http\Controllers\Controller;
class NotificationsController extends Controller {}

View File

@@ -43,6 +43,7 @@ use Illuminate\Contracts\View\Factory;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Routing\Redirector;
use Illuminate\Support\Facades\Log;
use Illuminate\View\View;
/**
@@ -223,7 +224,9 @@ class ConvertController extends Controller
// group accounts:
/** @var Account $account */
foreach ($accountList as $account) {
$balance = Steam::finalAccountBalance($account, today()->endOfDay())['balance'];
$date = today()->endOfDay();
Log::debug(sprintf('getLiabilities: Call finalAccountBalance with date/time "%s"', $date->toIso8601String()));
$balance = Steam::finalAccountBalance($account, $date)['balance'];
$currency = $this->accountRepository->getAccountCurrency($account) ?? $this->defaultCurrency;
$role = 'l_'.$account->accountType->type;
$key = (string) trans('firefly.opt_group_'.$role);
@@ -245,7 +248,9 @@ class ConvertController extends Controller
// group accounts:
/** @var Account $account */
foreach ($accountList as $account) {
$balance = Steam::finalAccountBalance($account, today()->endOfDay())['balance'];
$date = today()->endOfDay();
Log::debug(sprintf('getAssetAccounts: Call finalAccountBalance with date/time "%s"', $date->toIso8601String()));
$balance = Steam::finalAccountBalance($account, $date)['balance'];
$currency = $this->accountRepository->getAccountCurrency($account) ?? $this->defaultCurrency;
$role = (string) $this->accountRepository->getMetaValue($account, 'account_role');
if ('' === $role) {

View File

@@ -419,9 +419,7 @@ class CreateRecurringTransactions implements ShouldQueue
/** @var RecurrenceTransaction $transaction */
foreach ($transactions as $index => $transaction) {
$single = [
'type' => null === $transaction?->transactionType?->type ?
strtolower($recurrence->transactionType->type) :
strtolower($transaction->transactionType->type),
'type' => null === $transaction?->transactionType?->type ? strtolower($recurrence->transactionType->type) : strtolower($transaction->transactionType->type), // @phpstan-ignore-line
'date' => $date,
'user' => $recurrence->user_id,
'currency_id' => $transaction->transaction_currency_id,

View File

@@ -40,6 +40,7 @@ use FireflyIII\Models\TransactionJournal;
use FireflyIII\Services\Internal\Destroy\AccountDestroyService;
use FireflyIII\Services\Internal\Update\AccountUpdateService;
use FireflyIII\Support\Facades\Steam;
use FireflyIII\Support\Repositories\UserGroup\UserGroupTrait;
use FireflyIII\User;
use Illuminate\Contracts\Auth\Authenticatable;
use Illuminate\Database\Eloquent\Builder as EloquentBuilder;
@@ -51,7 +52,7 @@ use Illuminate\Support\Collection;
*/
class AccountRepository implements AccountRepositoryInterface
{
private User $user;
use UserGroupTrait;
/**
* Moved here from account CRUD.

View File

@@ -30,6 +30,7 @@ use FireflyIII\Models\Location;
use FireflyIII\Models\TransactionCurrency;
use FireflyIII\Models\TransactionGroup;
use FireflyIII\Models\TransactionJournal;
use FireflyIII\Models\UserGroup;
use FireflyIII\User;
use Illuminate\Contracts\Auth\Authenticatable;
use Illuminate\Support\Collection;
@@ -149,6 +150,8 @@ interface AccountRepositoryInterface
public function setUser(null|Authenticatable|User $user): void;
public function setUserGroup(UserGroup $userGroup): void;
public function store(array $data): Account;
public function update(Account $account, array $data): Account;

View File

@@ -29,9 +29,11 @@ use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Helpers\Collector\GroupCollectorInterface;
use FireflyIII\Models\Account;
use FireflyIII\Repositories\UserGroups\Currency\CurrencyRepositoryInterface;
use FireflyIII\Support\Facades\Steam;
use FireflyIII\User;
use Illuminate\Contracts\Auth\Authenticatable;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Log;
/**
* Class AccountTasker.
@@ -46,10 +48,13 @@ class AccountTasker implements AccountTaskerInterface
public function getAccountReport(Collection $accounts, Carbon $start, Carbon $end): array
{
$yesterday = clone $start;
$yesterday->subDay();
$startSet = app('steam')->finalAccountsBalance($accounts, $yesterday);
$endSet = app('steam')->finalAccountsBalance($accounts, $end);
app('log')->debug('Start of accountreport');
$yesterday->subDay()->endOfDay(); // exactly up until $start but NOT including.
$end->endOfDay(); // needs to be end of day to be correct.
Log::debug(sprintf('getAccountReport: finalAccountsBalance("%s")', $yesterday->format('Y-m-d H:i:s')));
Log::debug(sprintf('getAccountReport: finalAccountsBalance("%s")', $end->format('Y-m-d H:i:s')));
$startSet = Steam::finalAccountsBalance($accounts, $yesterday);
$endSet = Steam::finalAccountsBalance($accounts, $end);
Log::debug('Start of accountreport');
/** @var AccountRepositoryInterface $repository */
$repository = app(AccountRepositoryInterface::class);
@@ -90,10 +95,10 @@ class AccountTasker implements AccountTaskerInterface
$entry['end_balance'] = $endSet[$account->id]['balance'] ?? '0';
// first journal exists, and is on start, then this is the actual opening balance:
if (null !== $first && $first->date->isSameDay($start) && TransactionTypeEnum::OPENING_BALANCE->value === $first->transactionType->type) {
app('log')->debug(sprintf('Date of first journal for %s is %s', $account->name, $first->date->format('Y-m-d')));
if (null !== $first && $first->date->isSameDay($yesterday) && TransactionTypeEnum::OPENING_BALANCE->value === $first->transactionType->type) {
Log::debug(sprintf('Date of first journal for %s is %s', $account->name, $first->date->format('Y-m-d')));
$entry['start_balance'] = $first->transactions()->where('account_id', $account->id)->first()->amount;
app('log')->debug(sprintf('Account %s was opened on %s, so opening balance is %f', $account->name, $start->format('Y-m-d'), $entry['start_balance']));
Log::debug(sprintf('Account %s was opened on %s, so opening balance is %f', $account->name, $yesterday->format('Y-m-d'), $entry['start_balance']));
}
$return['sums'][$currency->id]['start'] = bcadd($return['sums'][$currency->id]['start'], $entry['start_balance']);
$return['sums'][$currency->id]['end'] = bcadd($return['sums'][$currency->id]['end'], $entry['end_balance']);
@@ -173,7 +178,7 @@ class AccountTasker implements AccountTaskerInterface
];
$report['accounts'][$key]['sum'] = bcadd($report['accounts'][$key]['sum'], $journal['amount']);
app('log')->debug(sprintf('Sum for %s is now %s', $journal['destination_account_name'], $report['accounts'][$key]['sum']));
Log::debug(sprintf('Sum for %s is now %s', $journal['destination_account_name'], $report['accounts'][$key]['sum']));
++$report['accounts'][$key]['count'];
}

View File

@@ -38,8 +38,7 @@ use FireflyIII\Services\Internal\Destroy\BillDestroyService;
use FireflyIII\Services\Internal\Update\BillUpdateService;
use FireflyIII\Support\CacheProperties;
use FireflyIII\Support\Facades\Amount;
use FireflyIII\User;
use Illuminate\Contracts\Auth\Authenticatable;
use FireflyIII\Support\Repositories\UserGroup\UserGroupTrait;
use Illuminate\Database\Query\JoinClause;
use Illuminate\Pagination\LengthAwarePaginator;
use Illuminate\Support\Collection;
@@ -51,8 +50,7 @@ use Illuminate\Support\Facades\Log;
class BillRepository implements BillRepositoryInterface
{
use CreatesObjectGroups;
private User $user;
use UserGroupTrait;
public function billEndsWith(string $query, int $limit): Collection
{
@@ -294,13 +292,6 @@ class BillRepository implements BillRepositoryInterface
return $result;
}
public function setUser(null|Authenticatable|User $user): void
{
if ($user instanceof User) {
$this->user = $user;
}
}
public function getPaginator(int $size): LengthAwarePaginator
{
return $this->user->bills()

View File

@@ -26,6 +26,7 @@ namespace FireflyIII\Repositories\Bill;
use Carbon\Carbon;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Models\Bill;
use FireflyIII\Models\UserGroup;
use FireflyIII\User;
use Illuminate\Contracts\Auth\Authenticatable;
use Illuminate\Pagination\LengthAwarePaginator;
@@ -40,6 +41,8 @@ interface BillRepositoryInterface
public function billStartsWith(string $query, int $limit): Collection;
public function setUserGroup(UserGroup $userGroup): void;
/**
* Add correct order to bills.
*/

View File

@@ -41,8 +41,7 @@ use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use FireflyIII\Repositories\UserGroups\Currency\CurrencyRepositoryInterface;
use FireflyIII\Services\Internal\Destroy\BudgetDestroyService;
use FireflyIII\Support\Http\Api\ExchangeRateConverter;
use FireflyIII\User;
use Illuminate\Contracts\Auth\Authenticatable;
use FireflyIII\Support\Repositories\UserGroup\UserGroupTrait;
use Illuminate\Database\QueryException;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Log;
@@ -52,7 +51,7 @@ use Illuminate\Support\Facades\Log;
*/
class BudgetRepository implements BudgetRepositoryInterface
{
private User $user;
use UserGroupTrait;
public function budgetEndsWith(string $query, int $limit): Collection
{
@@ -154,13 +153,6 @@ class BudgetRepository implements BudgetRepositoryInterface
return $return;
}
public function setUser(null|Authenticatable|User $user): void
{
if ($user instanceof User) {
$this->user = $user;
}
}
public function getActiveBudgets(): Collection
{
return $this->user->budgets()->where('active', true)

View File

@@ -27,6 +27,7 @@ use Carbon\Carbon;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Models\AutoBudget;
use FireflyIII\Models\Budget;
use FireflyIII\Models\UserGroup;
use FireflyIII\User;
use Illuminate\Contracts\Auth\Authenticatable;
use Illuminate\Support\Collection;
@@ -40,6 +41,8 @@ interface BudgetRepositoryInterface
public function budgetStartsWith(string $query, int $limit): Collection;
public function setUserGroup(UserGroup $userGroup): void;
/**
* Returns the amount that is budgeted in a period.
*/

View File

@@ -214,7 +214,6 @@ class OperationsRepository implements OperationsRepositoryInterface
Log::debug(sprintf('Start of %s.', __METHOD__));
// 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.
$repository = app(AccountRepositoryInterface::class);
@@ -245,7 +244,7 @@ class OperationsRepository implements OperationsRepositoryInterface
}
if (null !== $currency) {
Log::debug(sprintf('Limit to currency %s', $currency->code));
$collector->setNormalCurrency($currency);
$collector->setCurrency($currency);
}
$collector->setBudgets($budgets);
$journals = $collector->getExtractedJournals();

View File

@@ -33,6 +33,7 @@ use FireflyIII\Models\RecurrenceTransactionMeta;
use FireflyIII\Models\RuleAction;
use FireflyIII\Services\Internal\Destroy\CategoryDestroyService;
use FireflyIII\Services\Internal\Update\CategoryUpdateService;
use FireflyIII\Support\Repositories\UserGroup\UserGroupTrait;
use FireflyIII\User;
use Illuminate\Contracts\Auth\Authenticatable;
use Illuminate\Support\Collection;
@@ -43,7 +44,7 @@ use Illuminate\Support\Facades\Log;
*/
class CategoryRepository implements CategoryRepositoryInterface
{
private User $user;
use UserGroupTrait;
public function categoryEndsWith(string $query, int $limit): Collection
{

View File

@@ -26,6 +26,7 @@ namespace FireflyIII\Repositories\Category;
use Carbon\Carbon;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Models\Category;
use FireflyIII\Models\UserGroup;
use FireflyIII\User;
use Illuminate\Contracts\Auth\Authenticatable;
use Illuminate\Support\Collection;
@@ -88,6 +89,8 @@ interface CategoryRepositoryInterface
public function setUser(null|Authenticatable|User $user): void;
public function setUserGroup(UserGroup $userGroup): void;
/**
* @throws FireflyException
*/

View File

@@ -36,6 +36,7 @@ use FireflyIII\Models\TransactionJournal;
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use FireflyIII\Repositories\Journal\JournalRepositoryInterface;
use FireflyIII\Support\Facades\Steam;
use FireflyIII\Support\Repositories\UserGroup\UserGroupTrait;
use FireflyIII\User;
use Illuminate\Contracts\Auth\Authenticatable;
use Illuminate\Support\Collection;
@@ -48,7 +49,7 @@ class PiggyBankRepository implements PiggyBankRepositoryInterface
{
use ModifiesPiggyBanks;
private User $user;
use UserGroupTrait;
public function destroyAll(): void
{
@@ -370,6 +371,7 @@ class PiggyBankRepository implements PiggyBankRepositoryInterface
public function leftOnAccount(PiggyBank $piggyBank, Account $account, Carbon $date): string
{
Log::debug(sprintf('leftOnAccount("%s","%s","%s")', $piggyBank->name, $account->name, $date->format('Y-m-d H:i:s')));
Log::debug(sprintf('leftOnAccount: Call finalAccountBalance with date/time "%s"', $date->toIso8601String()));
$balance = Steam::finalAccountBalance($account, $date)['balance'];
Log::debug(sprintf('Balance is: %s', $balance));

View File

@@ -29,6 +29,7 @@ use FireflyIII\Models\Account;
use FireflyIII\Models\PiggyBank;
use FireflyIII\Models\PiggyBankRepetition;
use FireflyIII\Models\TransactionJournal;
use FireflyIII\Models\UserGroup;
use FireflyIII\User;
use Illuminate\Contracts\Auth\Authenticatable;
use Illuminate\Support\Collection;
@@ -137,6 +138,8 @@ interface PiggyBankRepositoryInterface
public function setUser(null|Authenticatable|User $user): void;
public function setUserGroup(UserGroup $userGroup): void;
/**
* Store new piggy bank.
*

View File

@@ -43,8 +43,7 @@ use FireflyIII\Repositories\Attachment\AttachmentRepositoryInterface;
use FireflyIII\Services\Internal\Destroy\TransactionGroupDestroyService;
use FireflyIII\Services\Internal\Update\GroupUpdateService;
use FireflyIII\Support\NullArrayObject;
use FireflyIII\User;
use Illuminate\Contracts\Auth\Authenticatable;
use FireflyIII\Support\Repositories\UserGroup\UserGroupTrait;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Support\Collection;
@@ -53,7 +52,7 @@ use Illuminate\Support\Collection;
*/
class TransactionGroupRepository implements TransactionGroupRepositoryInterface
{
private User $user;
use UserGroupTrait;
public function countAttachments(int $journalId): int
{
@@ -163,13 +162,6 @@ class TransactionGroupRepository implements TransactionGroupRepositoryInterface
return $result;
}
public function setUser(null|Authenticatable|User $user): void
{
if ($user instanceof User) {
$this->user = $user;
}
}
/**
* Get the note text for a journal (by ID).
*/
@@ -408,7 +400,8 @@ class TransactionGroupRepository implements TransactionGroupRepositoryInterface
{
/** @var TransactionGroupFactory $factory */
$factory = app(TransactionGroupFactory::class);
$factory->setUser($this->user);
$factory->setUser($data['user']);
$factory->setUserGroup($data['user_group']);
try {
return $factory->create($data);

View File

@@ -28,6 +28,7 @@ use FireflyIII\Exceptions\DuplicateTransactionException;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Models\Location;
use FireflyIII\Models\TransactionGroup;
use FireflyIII\Models\UserGroup;
use FireflyIII\Support\NullArrayObject;
use FireflyIII\User;
use Illuminate\Contracts\Auth\Authenticatable;
@@ -99,6 +100,8 @@ interface TransactionGroupRepositoryInterface
public function setUser(null|Authenticatable|User $user): void;
public function setUserGroup(UserGroup $userGroup): void;
/**
* Create a new transaction group.
*

View File

@@ -659,9 +659,10 @@ trait AccountServiceTrait
// submit to factory:
$submission = [
'group_title' => null,
'user' => $account->user_id,
'transactions' => [
'group_title' => null,
'user' => $account->user,
'user_group' => $account->user->userGroup,
'transactions' => [
[
'type' => 'Opening balance',
'date' => $openingBalanceDate,
@@ -669,7 +670,8 @@ trait AccountServiceTrait
'source_name' => $sourceName,
'destination_id' => $destId,
'destination_name' => $destName,
'user' => $account->user_id,
'user' => $account->user,
'user_group' => $account->user->userGroup,
'currency_id' => $currency->id,
'order' => 0,
'amount' => $amount,

View File

@@ -203,8 +203,7 @@ class FrontpageChartGenerator
$amount = $limit->native_amount;
Log::debug(sprintf('Amount is now "%s".', $amount));
}
$amount = null === $amount ? '0' : $amount;
$sumSpent = bcmul($entry['sum'], '-1'); // spent
$data[0]['entries'][$title] ??= '0';
$data[1]['entries'][$title] ??= '0';

View File

@@ -38,6 +38,8 @@ use Illuminate\Support\Facades\Log;
*/
trait ValidatesUserGroupTrait
{
protected ?UserGroup $userGroup = null;
/**
* An "undocumented" filter
*
@@ -59,7 +61,7 @@ trait ValidatesUserGroupTrait
$user = auth()->user();
$groupId = 0;
if (!$request->has('user_group_id')) {
$groupId = $user->user_group_id;
$groupId = (int) $user->user_group_id;
Log::debug(sprintf('validateUserGroup: no user group submitted, use default group #%d.', $groupId));
}
if ($request->has('user_group_id')) {
@@ -98,6 +100,7 @@ trait ValidatesUserGroupTrait
foreach ($roles as $role) {
if ($user->hasRoleInGroupOrOwner($group, $role)) {
Log::debug(sprintf('validateUserGroup: User has role "%s" in group #%d, return the group.', $role->value, $groupId));
$this->userGroup = $group;
return $group;
}

View File

@@ -77,8 +77,9 @@ trait ChartGeneration
Log::debug(sprintf('Now at account #%d ("%s)', $account->id, $account->name));
$currency = $accountRepos->getAccountCurrency($account) ?? $default;
$useNative = $convertToNative && $default->id !== $currency->id;
$field = $useNative ? 'native_balance' : 'balance';
$field = $convertToNative ? 'native_balance' : 'balance';
$currency = $useNative ? $default : $currency;
Log::debug(sprintf('Will use field %s', $field));
$currentSet = [
'label' => $account->name,
'currency_symbol' => $currency->symbol,

View File

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

View File

@@ -24,30 +24,48 @@ declare(strict_types=1);
namespace FireflyIII\Support\Repositories\UserGroup;
use FireflyIII\Enums\UserRoleEnum;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Models\GroupMembership;
use FireflyIII\Models\UserGroup;
use FireflyIII\User;
use Illuminate\Contracts\Auth\Authenticatable;
use Illuminate\Support\Facades\Log;
/**
* Trait UserGroupTrait
*/
trait UserGroupTrait
{
protected User $user;
protected UserGroup $userGroup;
protected ?User $user = null;
protected ?UserGroup $userGroup = null;
public function getUserGroup(): UserGroup
{
return $this->userGroup;
}
public function checkUserGroupAccess(UserRoleEnum $role): bool
{
$result = $this->user->hasRoleInGroupOrOwner($this->userGroup, $role);
if ($result) {
Log::debug(sprintf('User #%d has role %s in group #%d or is owner/full.', $this->user->id, $role->value, $this->userGroup->id));
return true;
}
Log::warning(sprintf('User #%d DOES NOT have role %s in group #%d.', $this->user->id, $role->value, $this->userGroup->id));
return false;
}
/**
* TODO This method does not check if the user has access to this particular user group.
*/
public function setUserGroup(UserGroup $userGroup): void
{
if (null === $this->user) {
Log::warning(sprintf('User is not set in repository %s', static::class));
}
$this->userGroup = $userGroup;
}
@@ -62,7 +80,11 @@ trait UserGroupTrait
throw new FireflyException(sprintf('User #%d has no user group.', $user->id));
}
$this->userGroup = $user->userGroup;
return;
}
throw new FireflyException(sprintf('Object is of class %s, not User.', get_class($user)));
}
/**
@@ -70,7 +92,7 @@ trait UserGroupTrait
*/
public function setUserGroupById(int $userGroupId): void
{
$memberships = GroupMembership::where('user_id', $this->user->id)
$memberships = GroupMembership::where('user_id', $this->user->id)
->where('user_group_id', $userGroupId)
->count()
;
@@ -79,10 +101,10 @@ trait UserGroupTrait
}
/** @var null|UserGroup $userGroup */
$userGroup = UserGroup::find($userGroupId);
$userGroup = UserGroup::find($userGroupId);
if (null === $userGroup) {
throw new FireflyException(sprintf('Cannot find administration for user #%d', $this->user->id));
}
$this->userGroup = $userGroup;
$this->setUserGroup($userGroup);
}
}

View File

@@ -63,13 +63,10 @@ abstract class Node
return false;
}
if ($compare instanceof NodeGroup) {
if ($compare instanceof NodeGroup && $this instanceof NodeGroup) {
if (count($compare->getNodes()) !== count($this->getNodes())) {
Log::debug(sprintf('Return false because node count is different. Original is %d, compare is %d', count($this->getNodes()), count($compare->getNodes())));
// var_dump($this);
// var_dump($compare);
// exit;
return false;
}
@@ -80,10 +77,6 @@ abstract class Node
foreach ($this->getNodes() as $index => $node) {
if (false === $node->equals($compare->getNodes()[$index])) {
Log::debug('Return false because nodes are different!');
var_dump($this);
var_dump($compare);
exit;
return false;
}

View File

@@ -152,12 +152,12 @@ class QueryParser implements QueryParserInterface
case ':':
$skipNext = false;
if ('' === $tokenUnderConstruction) { // @phpstan-ignore-line
if ('' === $tokenUnderConstruction) {
// In any other location, it's just a normal character
$tokenUnderConstruction .= $char;
$skipNext = true;
}
if ('' !== $tokenUnderConstruction && !$skipNext) {
if ('' !== $tokenUnderConstruction && !$skipNext) { // @phpstan-ignore-line
Log::debug(sprintf('Turns out that "%s" is a field name. Reset the token.', $tokenUnderConstruction));
// If we meet a colon with a left-hand side string, we know we're in a field and are about to set up the value
$fieldName = $tokenUnderConstruction;

View File

@@ -68,6 +68,7 @@ class Steam
$cache->addProperty($account->id);
$cache->addProperty('final-balance-in-range');
$cache->addProperty($start);
$cache->addProperty($convertToNative);
$cache->addProperty($end);
if ($cache->has()) {
return $cache->get();
@@ -75,7 +76,15 @@ class Steam
$balances = [];
$formatted = $start->format('Y-m-d');
$startBalance = $this->finalAccountBalance($account, $start);
/*
* To make sure the start balance is correct, we need to get the balance at the exact end of the previous day.
* Since we just did "startOfDay" we can do subDay()->endOfDay() to get the correct moment.
* THAT will be the start balance.
*/
$request = clone $start;
$request->subDay()->endOfDay();
Log::debug(sprintf('finalAccountBalanceInRange: Call finalAccountBalance with date/time "%s"', $request->toIso8601String()));
$startBalance = $this->finalAccountBalance($account, $request);
$nativeCurrency = app('amount')->getNativeCurrencyByUserGroup($account->user->userGroup);
$accountCurrency = $this->getAccountCurrency($account);
$hasCurrency = null !== $accountCurrency;
@@ -139,6 +148,8 @@ class Steam
$entryCurrency = $currencies[$entry->transaction_currency_id];
Log::debug(sprintf('Processing transaction(s) on moment %s', $carbon->format('Y-m-d H:i:s')));
// add amount to current balance in currency code.
$currentBalance[$entryCurrency->code] ??= '0';
$currentBalance[$entryCurrency->code] = bcadd($sumOfDay, $currentBalance[$entryCurrency->code]);
@@ -147,9 +158,14 @@ class Steam
$currentBalance['balance'] = bcadd($currentBalance['balance'], $sumOfDay);
}
// if convert to native add the converted amount to "native_balance".
// if there is a request to convert, convert to "native_balance" and use "balance" for whichever amount is in the native currency.
if ($convertToNative) {
$nativeSumOfDay = $converter->convert($entryCurrency, $nativeCurrency, $carbon, $sumOfDay);
$currentBalance['native_balance'] = bcadd($currentBalance['native_balance'], $nativeSumOfDay);
if ($currency->id === $entryCurrency->id) {
$currentBalance['balance'] = bcadd($currentBalance['balance'], $sumOfDay);
}
}
// just set it.
$balances[$carbonKey] = $currentBalance;
@@ -163,6 +179,7 @@ class Steam
public function finalAccountsBalance(Collection $accounts, Carbon $date): array
{
Log::debug(sprintf('finalAccountsBalance: Call finalAccountBalance with date/time "%s"', $date->toIso8601String()));
$balances = [];
foreach ($accounts as $account) {
$balances[$account->id] = $this->finalAccountBalance($account, $date);
@@ -259,6 +276,8 @@ class Steam
}
/**
* Returns smaller than or equal to, so be careful with END OF DAY.
*
* Returns the balance of an account at exact moment given. Array with at least one value.
* Always returns:
* "balance": balance in the account's currency OR user's native currency if the account has no currency
@@ -277,7 +296,7 @@ class Steam
$cache->addProperty($date);
if ($cache->has()) {
// Log::debug(sprintf('CACHED finalAccountBalance(#%d, %s)', $account->id, $date->format('Y-m-d H:i:s')));
// return $cache->get();
return $cache->get();
}
Log::debug(sprintf('finalAccountBalance(#%d, %s)', $account->id, $date->format('Y-m-d H:i:s')));
@@ -356,8 +375,8 @@ class Steam
$defaultCurrency = app('amount')->getNativeCurrency();
if ($convertToNative) {
if ($defaultCurrency->id === $currency?->id) {
Log::debug(sprintf('Unset "native_balance" and [%s] for account #%d', $defaultCurrency->code, $account->id));
unset($set['native_balance'], $set[$defaultCurrency->code]);
Log::debug(sprintf('Unset [%s] for account #%d (no longer unset "native_balance")', $defaultCurrency->code, $account->id));
unset($set[$defaultCurrency->code]);
}
// todo rethink this logic.
if (null !== $currency && $defaultCurrency->id !== $currency->id) {

View File

@@ -114,7 +114,7 @@ class AmountFormat extends AbstractExtension
static function (string $amount, string $code, ?bool $coloured = null): string {
$coloured ??= true;
/** @var TransactionCurrency $currency */
/** @var null|TransactionCurrency $currency */
$currency = TransactionCurrency::whereCode($code)->first();
if (null === $currency) {
Log::error(sprintf('Could not find currency with code "%s". Fallback to native currency.', $code));

View File

@@ -31,6 +31,7 @@ use FireflyIII\Repositories\User\UserRepositoryInterface;
use FireflyIII\Support\Facades\Amount;
use FireflyIII\Support\Facades\Steam;
use FireflyIII\Support\Search\OperatorQuerySearch;
use Illuminate\Support\Facades\Log;
use League\CommonMark\GithubFlavoredMarkdownConverter;
use Route;
use Twig\Extension\AbstractExtension;
@@ -67,6 +68,7 @@ class General extends AbstractExtension
/** @var Carbon $date */
$date = session('end', today(config('app.timezone'))->endOfMonth());
Log::debug(sprintf('twig balance: Call finalAccountBalance with date/time "%s"', $date->toIso8601String()));
$info = Steam::finalAccountBalance($account, $date);
$currency = Steam::getAccountCurrency($account);
$default = Amount::getNativeCurrency();

View File

@@ -31,6 +31,7 @@ use FireflyIII\Models\TransactionCurrency;
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use FireflyIII\Support\Facades\Amount;
use FireflyIII\Support\Facades\Steam;
use Illuminate\Support\Facades\Log;
use Symfony\Component\HttpFoundation\ParameterBag;
/**
@@ -106,6 +107,7 @@ class AccountTransformer extends AbstractTransformer
$order = null;
}
// balance, native balance, virtual balance, native virtual balance?
Log::debug(sprintf('transform: Call finalAccountBalance with date/time "%s"', $date->toIso8601String()));
$finalBalance = Steam::finalAccountBalance($account, $date);
if ($convertToNative) {
$finalBalance['balance'] = $finalBalance[$currencyCode] ?? '0';

View File

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

View File

@@ -183,6 +183,8 @@ class AccountTransformer extends AbstractTransformer
$bEnd = [];
try {
Log::debug(sprintf('v2 transformer: finalAccountsBalance("%s")', $start->format('Y-m-d H:i:s')));
Log::debug(sprintf('v2 transformer: finalAccountsBalance("%s")', $end->format('Y-m-d H:i:s')));
$bStart = app('steam')->finalAccountsBalance($accounts, $start);
$bEnd = app('steam')->finalAccountsBalance($accounts, $end);
} catch (FireflyException $e) {

View File

@@ -3,6 +3,18 @@
All notable changes to this project will be documented in this file.
This project adheres to [Semantic Versioning](http://semver.org/).
## 6.2.6 - 2025-02-13
### Fixed
- [Issue 9797](https://github.com/firefly-iii/firefly-iii/issues/9797) (All account charts show a horizontal line) reported by @avee87
- [Issue 9806](https://github.com/firefly-iii/firefly-iii/issues/9806) (Exchange Rates table fails to load when language is not English) reported by @polter-rnd
- [Issue 9807](https://github.com/firefly-iii/firefly-iii/issues/9807) (Start Date of Reconciliation Period Incorrectly Excludes Transactions for That Day) reported by @pwschattenberg
- [Issue 9808](https://github.com/firefly-iii/firefly-iii/issues/9808) (Default financial report line graph shows a different balance than the text) reported by @mtaygur
- [Issue 9810](https://github.com/firefly-iii/firefly-iii/issues/9810) (Foreign amount not taken into consideration for budget spent/leaving) reported by @M4xS0ch
- [Issue 9821](https://github.com/firefly-iii/firefly-iii/issues/9821) (piggy events api 500 error) reported by @4e868df3
- [Issue 9826](https://github.com/firefly-iii/firefly-iii/issues/9826) (Wrong account balance) reported by @fabienfitoussi
## 6.2.5 - 2025-02-08
### Fixed

76
composer.lock generated
View File

@@ -1874,16 +1874,16 @@
},
{
"name": "laravel/framework",
"version": "v11.41.3",
"version": "v11.42.0",
"source": {
"type": "git",
"url": "https://github.com/laravel/framework.git",
"reference": "3ef433d5865f30a19b6b1be247586068399b59cc"
"reference": "006375ba67e830e87daa7b52ab65163ba3508d26"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/laravel/framework/zipball/3ef433d5865f30a19b6b1be247586068399b59cc",
"reference": "3ef433d5865f30a19b6b1be247586068399b59cc",
"url": "https://api.github.com/repos/laravel/framework/zipball/006375ba67e830e87daa7b52ab65163ba3508d26",
"reference": "006375ba67e830e87daa7b52ab65163ba3508d26",
"shasum": ""
},
"require": {
@@ -1991,11 +1991,11 @@
"league/flysystem-read-only": "^3.25.1",
"league/flysystem-sftp-v3": "^3.25.1",
"mockery/mockery": "^1.6.10",
"orchestra/testbench-core": "^9.6",
"orchestra/testbench-core": "^9.9.4",
"pda/pheanstalk": "^5.0.6",
"php-http/discovery": "^1.15",
"phpstan/phpstan": "^1.11.5",
"phpunit/phpunit": "^10.5.35|^11.3.6",
"phpstan/phpstan": "^2.0",
"phpunit/phpunit": "^10.5.35|^11.3.6|^12.0.1",
"predis/predis": "^2.3",
"resend/resend-php": "^0.10.0",
"symfony/cache": "^7.0.3",
@@ -2027,7 +2027,7 @@
"mockery/mockery": "Required to use mocking (^1.6).",
"pda/pheanstalk": "Required to use the beanstalk queue driver (^5.0).",
"php-http/discovery": "Required to use PSR-7 bridging features (^1.15).",
"phpunit/phpunit": "Required to use assertions and run tests (^10.5|^11.0).",
"phpunit/phpunit": "Required to use assertions and run tests (^10.5.35|^11.3.6|^12.0.1).",
"predis/predis": "Required to use the predis connector (^2.3).",
"psr/http-message": "Required to allow Storage::put to accept a StreamInterface (^1.0).",
"pusher/pusher-php-server": "Required to use the Pusher broadcast driver (^6.0|^7.0).",
@@ -2085,7 +2085,7 @@
"issues": "https://github.com/laravel/framework/issues",
"source": "https://github.com/laravel/framework"
},
"time": "2025-01-30T13:25:22+00:00"
"time": "2025-02-11T17:17:56+00:00"
},
{
"name": "laravel/passport",
@@ -2165,16 +2165,16 @@
},
{
"name": "laravel/prompts",
"version": "v0.3.4",
"version": "v0.3.5",
"source": {
"type": "git",
"url": "https://github.com/laravel/prompts.git",
"reference": "abeaa2ba4294247d5409490d1ca1bc6248087011"
"reference": "57b8f7efe40333cdb925700891c7d7465325d3b1"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/laravel/prompts/zipball/abeaa2ba4294247d5409490d1ca1bc6248087011",
"reference": "abeaa2ba4294247d5409490d1ca1bc6248087011",
"url": "https://api.github.com/repos/laravel/prompts/zipball/57b8f7efe40333cdb925700891c7d7465325d3b1",
"reference": "57b8f7efe40333cdb925700891c7d7465325d3b1",
"shasum": ""
},
"require": {
@@ -2218,9 +2218,9 @@
"description": "Add beautiful and user-friendly forms to your command-line applications.",
"support": {
"issues": "https://github.com/laravel/prompts/issues",
"source": "https://github.com/laravel/prompts/tree/v0.3.4"
"source": "https://github.com/laravel/prompts/tree/v0.3.5"
},
"time": "2025-01-24T15:41:01+00:00"
"time": "2025-02-11T13:34:40+00:00"
},
{
"name": "laravel/sanctum",
@@ -2288,16 +2288,16 @@
},
{
"name": "laravel/serializable-closure",
"version": "v2.0.2",
"version": "v2.0.3",
"source": {
"type": "git",
"url": "https://github.com/laravel/serializable-closure.git",
"reference": "2e1a362527783bcab6c316aad51bf36c5513ae44"
"reference": "f379c13663245f7aa4512a7869f62eb14095f23f"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/laravel/serializable-closure/zipball/2e1a362527783bcab6c316aad51bf36c5513ae44",
"reference": "2e1a362527783bcab6c316aad51bf36c5513ae44",
"url": "https://api.github.com/repos/laravel/serializable-closure/zipball/f379c13663245f7aa4512a7869f62eb14095f23f",
"reference": "f379c13663245f7aa4512a7869f62eb14095f23f",
"shasum": ""
},
"require": {
@@ -2345,7 +2345,7 @@
"issues": "https://github.com/laravel/serializable-closure/issues",
"source": "https://github.com/laravel/serializable-closure"
},
"time": "2025-01-24T15:42:37+00:00"
"time": "2025-02-11T15:03:05+00:00"
},
{
"name": "laravel/slack-notification-channel",
@@ -3703,16 +3703,16 @@
},
{
"name": "nesbot/carbon",
"version": "3.8.4",
"version": "3.8.5",
"source": {
"type": "git",
"url": "https://github.com/CarbonPHP/carbon.git",
"reference": "129700ed449b1f02d70272d2ac802357c8c30c58"
"reference": "b1a53a27898639579a67de42e8ced5d5386aa9a4"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/CarbonPHP/carbon/zipball/129700ed449b1f02d70272d2ac802357c8c30c58",
"reference": "129700ed449b1f02d70272d2ac802357c8c30c58",
"url": "https://api.github.com/repos/CarbonPHP/carbon/zipball/b1a53a27898639579a67de42e8ced5d5386aa9a4",
"reference": "b1a53a27898639579a67de42e8ced5d5386aa9a4",
"shasum": ""
},
"require": {
@@ -3788,8 +3788,8 @@
],
"support": {
"docs": "https://carbon.nesbot.com/docs",
"issues": "https://github.com/briannesbitt/Carbon/issues",
"source": "https://github.com/briannesbitt/Carbon"
"issues": "https://github.com/CarbonPHP/carbon/issues",
"source": "https://github.com/CarbonPHP/carbon"
},
"funding": [
{
@@ -3805,7 +3805,7 @@
"type": "tidelift"
}
],
"time": "2024-12-27T09:25:35+00:00"
"time": "2025-02-11T16:28:45+00:00"
},
{
"name": "nette/schema",
@@ -10973,16 +10973,16 @@
},
{
"name": "myclabs/deep-copy",
"version": "1.12.1",
"version": "1.13.0",
"source": {
"type": "git",
"url": "https://github.com/myclabs/DeepCopy.git",
"reference": "123267b2c49fbf30d78a7b2d333f6be754b94845"
"reference": "024473a478be9df5fdaca2c793f2232fe788e414"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/123267b2c49fbf30d78a7b2d333f6be754b94845",
"reference": "123267b2c49fbf30d78a7b2d333f6be754b94845",
"url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/024473a478be9df5fdaca2c793f2232fe788e414",
"reference": "024473a478be9df5fdaca2c793f2232fe788e414",
"shasum": ""
},
"require": {
@@ -11021,7 +11021,7 @@
],
"support": {
"issues": "https://github.com/myclabs/DeepCopy/issues",
"source": "https://github.com/myclabs/DeepCopy/tree/1.12.1"
"source": "https://github.com/myclabs/DeepCopy/tree/1.13.0"
},
"funding": [
{
@@ -11029,7 +11029,7 @@
"type": "tidelift"
}
],
"time": "2024-11-08T17:47:46+00:00"
"time": "2025-02-12T12:17:51+00:00"
},
{
"name": "nikic/php-parser",
@@ -11344,16 +11344,16 @@
},
{
"name": "phpstan/phpstan",
"version": "2.1.3",
"version": "2.1.4",
"source": {
"type": "git",
"url": "https://github.com/phpstan/phpstan.git",
"reference": "64ae44e48214f3deebdaeebf2694297a10a2bea9"
"reference": "8f99e18eb775dbaf6460c95fa0b65312da9c746a"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/64ae44e48214f3deebdaeebf2694297a10a2bea9",
"reference": "64ae44e48214f3deebdaeebf2694297a10a2bea9",
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/8f99e18eb775dbaf6460c95fa0b65312da9c746a",
"reference": "8f99e18eb775dbaf6460c95fa0b65312da9c746a",
"shasum": ""
},
"require": {
@@ -11398,7 +11398,7 @@
"type": "github"
}
],
"time": "2025-02-07T15:05:24+00:00"
"time": "2025-02-10T08:25:21+00:00"
},
{
"name": "phpstan/phpstan-deprecation-rules",

View File

@@ -81,7 +81,7 @@ return [
'running_balance_column' => env('USE_RUNNING_BALANCE', false),
// see cer.php for exchange rates feature flag.
],
'version' => '6.2.5',
'version' => '6.2.6',
'api_version' => '2.1.0', // field is no longer used.
'db_version' => 25,

View File

@@ -159,7 +159,7 @@ return new class () extends Migration {
Schema::dropIfExists('account_piggy_bank');
}
protected static function hasForeign(string $table, string $column)
protected static function hasForeign(string $table, string $column): bool
{
$foreignKeysDefinitions = Schema::getForeignKeys($table);

30
package-lock.json generated
View File

@@ -4180,9 +4180,9 @@
"license": "MIT"
},
"node_modules/bootstrap5-autocomplete": {
"version": "1.1.35",
"resolved": "https://registry.npmjs.org/bootstrap5-autocomplete/-/bootstrap5-autocomplete-1.1.35.tgz",
"integrity": "sha512-vZAOef3lGrpGGnnIKTJlqiqv6wsx0Wr31/mc010mJmHF1eXJd28jzfGn7ol8eOI/7FiDcm3wd/1VTWku40vLbQ==",
"version": "1.1.36",
"resolved": "https://registry.npmjs.org/bootstrap5-autocomplete/-/bootstrap5-autocomplete-1.1.36.tgz",
"integrity": "sha512-fZpklymmrwAls3n6YDMua2msnBB4pwmJgJgqMayHLfnvvc2dhKWwp/qu0pGJI99S8TwC+ZDjYtEsfl+4/FEZhg==",
"license": "MIT"
},
"node_modules/bootstrap5-tags": {
@@ -4757,9 +4757,9 @@
}
},
"node_modules/compression": {
"version": "1.7.5",
"resolved": "https://registry.npmjs.org/compression/-/compression-1.7.5.tgz",
"integrity": "sha512-bQJ0YRck5ak3LgtnpKkiabX5pNF7tMUh1BSy2ZBOTh0Dim0BUu6aPPwByIns6/A5Prh8PufSPerMDUklpzes2Q==",
"version": "1.8.0",
"resolved": "https://registry.npmjs.org/compression/-/compression-1.8.0.tgz",
"integrity": "sha512-k6WLKfunuqCYD3t6AsuPGvQWaKwuLLh2/xHNcX4qE+vIfDNXpSqnrhwA7O53R7WVQUnt8dVAIW+YHr7xTgOgGA==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -5685,9 +5685,9 @@
"license": "MIT"
},
"node_modules/electron-to-chromium": {
"version": "1.5.96",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.96.tgz",
"integrity": "sha512-8AJUW6dh75Fm/ny8+kZKJzI1pgoE8bKLZlzDU2W1ENd+DXKJrx7I7l9hb8UWR4ojlnb5OlixMt00QWiYJoVw1w==",
"version": "1.5.97",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.97.tgz",
"integrity": "sha512-HKLtaH02augM7ZOdYRuO19rWDeY+QSJ1VxnXFa/XDFLf07HvM90pALIJFgrO+UVaajI3+aJMMpojoUTLZyQ7JQ==",
"dev": true,
"license": "ISC"
},
@@ -8876,9 +8876,9 @@
}
},
"node_modules/postcss": {
"version": "8.5.1",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.1.tgz",
"integrity": "sha512-6oz2beyjc5VMn/KV1pPw8fliQkhBXrVn1Z3TVyqZxU8kZpzEKhBdmCFqI6ZbmGtamQvQGuU1sgPTk8ZrXDD7jQ==",
"version": "8.5.2",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.2.tgz",
"integrity": "sha512-MjOadfU3Ys9KYoX0AdkBlFEF1Vx37uCCeN4ZHnmwm9FfpbsGWMZeBLMmmpY+6Ocqod7mkdZ0DT31OlbsFrLlkA==",
"dev": true,
"funding": [
{
@@ -10893,9 +10893,9 @@
}
},
"node_modules/terser": {
"version": "5.38.1",
"resolved": "https://registry.npmjs.org/terser/-/terser-5.38.1.tgz",
"integrity": "sha512-GWANVlPM/ZfYzuPHjq0nxT+EbOEDDN3Jwhwdg1D8TU8oSkktp8w64Uq4auuGLxFSoNTRDncTq2hQHX1Ld9KHkA==",
"version": "5.38.2",
"resolved": "https://registry.npmjs.org/terser/-/terser-5.38.2.tgz",
"integrity": "sha512-w8CXxxbFA5zfNsR/i8HZq5bvn18AK0O9jj7hyo1YqkovLxEFa0uP0LCVGZRqiRaKRFxXhELBp8SteeAjEnfeJg==",
"dev": true,
"license": "BSD-2-Clause",
"dependencies": {

View File

@@ -18,8 +18,8 @@
"is_reconciled": "Est rapproch\u00e9",
"split": "S\u00e9paration",
"single_split": "S\u00e9paration unique",
"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": "Pas assez de devises",
"not_enough_currencies_enabled": "Si vous n'avez qu'une seule devise activ\u00e9e, il n'y a pas besoin d'ajouter des taux de change.",
"transaction_stored_link": "<a href=\"transactions\/show\/{ID}\">L'op\u00e9ration n\u00b0{ID} (\"{title}\")<\/a> a \u00e9t\u00e9 enregistr\u00e9e.",
"webhook_stored_link": "<a href=\"webhooks\/show\/{ID}\">Le Webhook #{ID} (\"{title}\")<\/a> a \u00e9t\u00e9 enregistr\u00e9.",
"webhook_updated_link": "<a href=\"webhooks\/show\/{ID}\">Le webhook #{ID}<\/a> (\"{title}\") a \u00e9t\u00e9 mis \u00e0 jour.",

View File

@@ -18,8 +18,8 @@
"is_reconciled": "Is reconciled",
"split": "Feloszt\u00e1s",
"single_split": "Feloszt\u00e1s",
"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": "Nincs el\u00e9g p\u00e9nznem",
"not_enough_currencies_enabled": "Amennyiben csak egyetlen p\u00e9nznem enged\u00e9lyezett, akkor nincs sz\u00fcks\u00e9g \u00e1rfolyam be\u00e1ll\u00edt\u00e1sokra.",
"transaction_stored_link": "<a href=\"transactions\/show\/{ID}\">Transaction #{ID} (\"{title}\")<\/a> mentve.",
"webhook_stored_link": "<a href=\"webhooks\/show\/{ID}\">Webhook #{ID} (\"{title}\")<\/a> elt\u00e1rolva.",
"webhook_updated_link": "<a href=\"webhooks\/show\/{ID}\">Webhook #{ID}<\/a> (\"{title}\") friss\u00edtve.",

View File

@@ -182,6 +182,6 @@
},
"config": {
"html_language": "ru",
"date_time_fns": "D MMMM yyyy, @ HH:mm:ss"
"date_time_fns": "d MMMM yyyy, @ HH:mm:ss"
}
}

View File

@@ -18,8 +18,8 @@
"is_reconciled": "Je usklajena",
"split": "Razdeli",
"single_split": "Razdeli",
"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": "Ni dovolj valut",
"not_enough_currencies_enabled": "\u010ce imate omogo\u010deno samo eno valuto, menjalnih te\u010dajev ni treba dodajati.",
"transaction_stored_link": "<a href=\"transactions\/show\/{ID}\">Transakcija \u0161t. #{ID} (\"{title}\")<\/a> je bila shranjena.",
"webhook_stored_link": "<a href=\"webhooks\/show\/{ID}\">Webhook #{ID} (\"{title}\")<\/a> je bil shranjen.",
"webhook_updated_link": "<a href=\"webhooks\/show\/{ID}\">Webhook #{ID}<\/a> (\"{title}\") je bil posodobljen.",

View File

@@ -6,7 +6,7 @@
"administration_currency_form_help": "It may take a long time for the page to load if you change the native currency because transaction may need to be converted to your (new) native currency.",
"administrations_page_edit_sub_title_js": "Edit financial administration \"{title}\"",
"table": "\u8868\u683c",
"welcome_back": "What's playing?",
"welcome_back": "\u6b61\u8fce\u56de\u4f86\u7e7c\u7e8c\u7406\u8ca1\uff01",
"flash_error": "\u932f\u8aa4\uff01",
"flash_warning": "\u8b66\u544a\uff01",
"flash_success": "\u6210\u529f\uff01",

View File

@@ -69,9 +69,13 @@
{% for key, balance in account.endBalances %}
<span title="{{ key }}">
{% if 'balance' == key %}
{{ formatAmountBySymbol(balance, account.currency.symbol, account.currency.decimal_places) }}
{% if not convertToNative %}
{{ formatAmountBySymbol(balance, account.currency.symbol, account.currency.decimal_places) }}
{% endif %}
{% elseif 'native_balance' == key %}
{{ formatAmountBySymbol(balance, defaultCurrency.symbol, defaultCurrency.decimal_places) }}
{% if convertToNative %}
{{ formatAmountBySymbol(balance, defaultCurrency.symbol, defaultCurrency.decimal_places) }}
{% endif %}
{% else %}
({{ formatAmountByCode(balance, key) }})
{% endif %}