Auto commit for release 'develop' on 2024-12-30

This commit is contained in:
github-actions
2024-12-30 04:12:18 +01:00
parent 9f25880a59
commit 0579c8565d
40 changed files with 301 additions and 303 deletions

View File

@@ -406,16 +406,16 @@
}, },
{ {
"name": "friendsofphp/php-cs-fixer", "name": "friendsofphp/php-cs-fixer",
"version": "v3.65.0", "version": "v3.66.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer.git", "url": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer.git",
"reference": "79d4f3e77b250a7d8043d76c6af8f0695e8a469f" "reference": "5f5f2a142ff36b93c41885bca29cc5f861c013e6"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/79d4f3e77b250a7d8043d76c6af8f0695e8a469f", "url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/5f5f2a142ff36b93c41885bca29cc5f861c013e6",
"reference": "79d4f3e77b250a7d8043d76c6af8f0695e8a469f", "reference": "5f5f2a142ff36b93c41885bca29cc5f861c013e6",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -441,7 +441,7 @@
"symfony/polyfill-mbstring": "^1.28", "symfony/polyfill-mbstring": "^1.28",
"symfony/polyfill-php80": "^1.28", "symfony/polyfill-php80": "^1.28",
"symfony/polyfill-php81": "^1.28", "symfony/polyfill-php81": "^1.28",
"symfony/process": "^5.4 || ^6.0 || ^7.0", "symfony/process": "^5.4 || ^6.0 || ^7.0 <7.2",
"symfony/stopwatch": "^5.4 || ^6.0 || ^7.0" "symfony/stopwatch": "^5.4 || ^6.0 || ^7.0"
}, },
"require-dev": { "require-dev": {
@@ -497,7 +497,7 @@
], ],
"support": { "support": {
"issues": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/issues", "issues": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/issues",
"source": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/tree/v3.65.0" "source": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/tree/v3.66.0"
}, },
"funding": [ "funding": [
{ {
@@ -505,7 +505,7 @@
"type": "github" "type": "github"
} }
], ],
"time": "2024-11-25T00:39:24+00:00" "time": "2024-12-29T13:46:23+00:00"
}, },
{ {
"name": "psr/container", "name": "psr/container",
@@ -2246,16 +2246,16 @@
}, },
{ {
"name": "symfony/process", "name": "symfony/process",
"version": "v7.2.0", "version": "v7.1.8",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/process.git", "url": "https://github.com/symfony/process.git",
"reference": "d34b22ba9390ec19d2dd966c40aa9e8462f27a7e" "reference": "42783370fda6e538771f7c7a36e9fa2ee3a84892"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/process/zipball/d34b22ba9390ec19d2dd966c40aa9e8462f27a7e", "url": "https://api.github.com/repos/symfony/process/zipball/42783370fda6e538771f7c7a36e9fa2ee3a84892",
"reference": "d34b22ba9390ec19d2dd966c40aa9e8462f27a7e", "reference": "42783370fda6e538771f7c7a36e9fa2ee3a84892",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -2287,7 +2287,7 @@
"description": "Executes commands in sub-processes", "description": "Executes commands in sub-processes",
"homepage": "https://symfony.com", "homepage": "https://symfony.com",
"support": { "support": {
"source": "https://github.com/symfony/process/tree/v7.2.0" "source": "https://github.com/symfony/process/tree/v7.1.8"
}, },
"funding": [ "funding": [
{ {
@@ -2303,7 +2303,7 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2024-11-06T14:24:19+00:00" "time": "2024-11-06T14:23:19+00:00"
}, },
{ {
"name": "symfony/service-contracts", "name": "symfony/service-contracts",

View File

@@ -99,7 +99,7 @@ class AccountController extends Controller
); );
} }
$return[] = [ $return[] = [
'id' => (string) $account->id, 'id' => (string) $account->id,
'name' => $account->name, 'name' => $account->name,
'name_with_balance' => $nameWithBalance, 'name_with_balance' => $nameWithBalance,

View File

@@ -72,19 +72,19 @@ class AccountController extends Controller
public function overview(DateRequest $request): JsonResponse public function overview(DateRequest $request): JsonResponse
{ {
// parameters for chart: // parameters for chart:
$dates = $request->getAll(); $dates = $request->getAll();
/** @var Carbon $start */ /** @var Carbon $start */
$start = $dates['start']; $start = $dates['start'];
/** @var Carbon $end */ /** @var Carbon $end */
$end = $dates['end']; $end = $dates['end'];
// user's preferences // user's preferences
$defaultSet = $this->repository->getAccountsByType([AccountTypeEnum::ASSET->value])->pluck('id')->toArray(); $defaultSet = $this->repository->getAccountsByType([AccountTypeEnum::ASSET->value])->pluck('id')->toArray();
/** @var Preference $frontpage */ /** @var Preference $frontpage */
$frontpage = app('preferences')->get('frontpageAccounts', $defaultSet); $frontpage = app('preferences')->get('frontpageAccounts', $defaultSet);
if (!(is_array($frontpage->data) && count($frontpage->data) > 0)) { if (!(is_array($frontpage->data) && count($frontpage->data) > 0)) {
$frontpage->data = $defaultSet; $frontpage->data = $defaultSet;
@@ -92,14 +92,14 @@ class AccountController extends Controller
} }
// get accounts: // get accounts:
$accounts = $this->repository->getAccountsById($frontpage->data); $accounts = $this->repository->getAccountsById($frontpage->data);
$chartData = []; $chartData = [];
/** @var Account $account */ /** @var Account $account */
foreach ($accounts as $account) { foreach ($accounts as $account) {
$currency = $this->repository->getAccountCurrency($account) ?? $this->defaultCurrency; $currency = $this->repository->getAccountCurrency($account) ?? $this->defaultCurrency;
$field = $this->convertToNative && $currency->id !== $this->defaultCurrency->id ? 'native_balance' : 'balance'; $field = $this->convertToNative && $currency->id !== $this->defaultCurrency->id ? 'native_balance' : 'balance';
$currentSet = [ $currentSet = [
'label' => $account->name, 'label' => $account->name,
'currency_id' => (string) $currency->id, 'currency_id' => (string) $currency->id,
'currency_code' => $currency->code, 'currency_code' => $currency->code,
@@ -116,14 +116,14 @@ class AccountController extends Controller
$range = app('steam')->finalAccountBalanceInRange($account, $start, clone $end, $this->convertToNative); $range = app('steam')->finalAccountBalanceInRange($account, $start, clone $end, $this->convertToNative);
$previous = array_values($range)[0][$field]; $previous = array_values($range)[0][$field];
while ($currentStart <= $end) { while ($currentStart <= $end) {
$format = $currentStart->format('Y-m-d'); $format = $currentStart->format('Y-m-d');
$label = $currentStart->toAtomString(); $label = $currentStart->toAtomString();
$balance = array_key_exists($format, $range) ? $range[$format][$field] : $previous; $balance = array_key_exists($format, $range) ? $range[$format][$field] : $previous;
$previous = $balance; $previous = $balance;
$currentStart->addDay(); $currentStart->addDay();
$currentSet['entries'][$label] = $balance; $currentSet['entries'][$label] = $balance;
} }
$chartData[] = $currentSet; $chartData[] = $currentSet;
} }
return response()->json($chartData); return response()->json($chartData);

View File

@@ -94,8 +94,8 @@ abstract class Controller extends BaseController
if ($page < 1) { if ($page < 1) {
$page = 1; $page = 1;
} }
if ($page > pow(2,16)) { if ($page > 2 ** 16) {
$page = pow(2, 16); $page = 2 ** 16;
} }
$bag->set('page', $page); $bag->set('page', $page);

View File

@@ -63,8 +63,8 @@ class DestroyController extends Controller
*/ */
public function destroy(DestroyRequest $request): JsonResponse public function destroy(DestroyRequest $request): JsonResponse
{ {
$objects = $request->getObjects(); $objects = $request->getObjects();
$this->unused = $request->boolean('unused', false); $this->unused = $request->boolean('unused', false);
$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]; $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]; $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];
@@ -101,11 +101,11 @@ class DestroyController extends Controller
private function destroyBudgets(): void private function destroyBudgets(): void
{ {
/** @var AvailableBudgetRepositoryInterface $abRepository */ /** @var AvailableBudgetRepositoryInterface $abRepository */
$abRepository = app(AvailableBudgetRepositoryInterface::class); $abRepository = app(AvailableBudgetRepositoryInterface::class);
$abRepository->destroyAll(); $abRepository->destroyAll();
/** @var BudgetLimitRepositoryInterface $blRepository */ /** @var BudgetLimitRepositoryInterface $blRepository */
$blRepository = app(BudgetLimitRepositoryInterface::class); $blRepository = app(BudgetLimitRepositoryInterface::class);
$blRepository->destroyAll(); $blRepository->destroyAll();
/** @var BudgetRepositoryInterface $budgetRepository */ /** @var BudgetRepositoryInterface $budgetRepository */

View File

@@ -79,11 +79,11 @@ class BillController extends Controller
} }
// collect all expenses in this period (regardless of type) by the given bills and accounts. // collect all expenses in this period (regardless of type) by the given bills and accounts.
$collector = app(GroupCollectorInterface::class); $collector = app(GroupCollectorInterface::class);
$collector->setTypes([TransactionTypeEnum::WITHDRAWAL->value])->setRange($start, $end)->setSourceAccounts($accounts); $collector->setTypes([TransactionTypeEnum::WITHDRAWAL->value])->setRange($start, $end)->setSourceAccounts($accounts);
$collector->setBills($bills); $collector->setBills($bills);
$genericSet = $collector->getExtractedJournals(); $genericSet = $collector->getExtractedJournals();
foreach ($genericSet as $journal) { foreach ($genericSet as $journal) {
$billId = (int) $journal['bill_id']; $billId = (int) $journal['bill_id'];
$currencyId = (int) $journal['currency_id']; $currencyId = (int) $journal['currency_id'];
@@ -102,10 +102,10 @@ class BillController extends Controller
} }
Log::debug(sprintf('Journal #%d in bill #%d will use %s (%s %s)', $journal['transaction_group_id'], $billId, $field, $currencyCode, $journal[$field] ?? '0')); Log::debug(sprintf('Journal #%d in bill #%d will use %s (%s %s)', $journal['transaction_group_id'], $billId, $field, $currencyCode, $journal[$field] ?? '0'));
$key = sprintf('%d-%d', $billId, $currencyId); $key = sprintf('%d-%d', $billId, $currencyId);
if (0 !== $currencyId) { if (0 !== $currencyId) {
$response[$key] ??= [ $response[$key] ??= [
'id' => (string) $billId, 'id' => (string) $billId,
'name' => $journal['bill_name'], 'name' => $journal['bill_name'],
'difference' => '0', 'difference' => '0',
@@ -137,11 +137,11 @@ class BillController extends Controller
$response = []; $response = [];
// collect all expenses in this period (regardless of type) by the given bills and accounts. // collect all expenses in this period (regardless of type) by the given bills and accounts.
$collector = app(GroupCollectorInterface::class); $collector = app(GroupCollectorInterface::class);
$collector->setTypes([TransactionTypeEnum::WITHDRAWAL->value])->setRange($start, $end)->setSourceAccounts($accounts); $collector->setTypes([TransactionTypeEnum::WITHDRAWAL->value])->setRange($start, $end)->setSourceAccounts($accounts);
$collector->withoutBill(); $collector->withoutBill();
$genericSet = $collector->getExtractedJournals(); $genericSet = $collector->getExtractedJournals();
foreach ($genericSet as $journal) { foreach ($genericSet as $journal) {
$currencyId = (int) $journal['currency_id']; $currencyId = (int) $journal['currency_id'];
@@ -161,7 +161,7 @@ class BillController extends Controller
Log::debug(sprintf('Journal #%d will use %s (%s %s)', $journal['transaction_group_id'], $field, $currencyCode, $journal[$field] ?? '0')); Log::debug(sprintf('Journal #%d will use %s (%s %s)', $journal['transaction_group_id'], $field, $currencyCode, $journal[$field] ?? '0'));
if (0 !== $currencyId) { if (0 !== $currencyId) {
$response[$currencyId] ??= [ $response[$currencyId] ??= [
'difference' => '0', 'difference' => '0',
'difference_float' => 0, 'difference_float' => 0,
'currency_id' => (string) $currencyId, 'currency_id' => (string) $currencyId,

View File

@@ -51,14 +51,14 @@ class PeriodController extends Controller
$default = Amount::getDefaultCurrency(); $default = Amount::getDefaultCurrency();
// collect all expenses in this period (regardless of type) // collect all expenses in this period (regardless of type)
$collector = app(GroupCollectorInterface::class); $collector = app(GroupCollectorInterface::class);
$collector->setTypes([TransactionTypeEnum::WITHDRAWAL->value])->setRange($start, $end)->setSourceAccounts($accounts); $collector->setTypes([TransactionTypeEnum::WITHDRAWAL->value])->setRange($start, $end)->setSourceAccounts($accounts);
$genericSet = $collector->getExtractedJournals(); $genericSet = $collector->getExtractedJournals();
foreach ($genericSet as $journal) { foreach ($genericSet as $journal) {
// same code as many other sumExpense methods. I think this needs some kind of generic method. // same code as many other sumExpense methods. I think this needs some kind of generic method.
$amount = '0'; $amount = '0';
$currencyId = (int) $journal['currency_id']; $currencyId = (int) $journal['currency_id'];
$currencyCode = $journal['currency_code']; $currencyCode = $journal['currency_code'];
if ($convertToNative) { if ($convertToNative) {
$amount = Amount::getAmountFromJournal($journal); $amount = Amount::getAmountFromJournal($journal);
if ($default->id !== (int) $journal['currency_id'] && $default->id !== (int) $journal['foreign_currency_id']) { if ($default->id !== (int) $journal['currency_id'] && $default->id !== (int) $journal['foreign_currency_id']) {
@@ -78,7 +78,7 @@ class PeriodController extends Controller
} }
$response[$currencyId] ??= [ $response[$currencyId] ??= [
'difference' => '0', 'difference' => '0',
'difference_float' => 0, 'difference_float' => 0,
'currency_id' => (string) $currencyId, 'currency_id' => (string) $currencyId,

View File

@@ -72,17 +72,17 @@ class TagController extends Controller
$default = Amount::getDefaultCurrency(); $default = Amount::getDefaultCurrency();
// collect all expenses in this period (regardless of type) by the given bills and accounts. // collect all expenses in this period (regardless of type) by the given bills and accounts.
$collector = app(GroupCollectorInterface::class); $collector = app(GroupCollectorInterface::class);
$collector->setTypes([TransactionTypeEnum::WITHDRAWAL->value])->setRange($start, $end)->setSourceAccounts($accounts); $collector->setTypes([TransactionTypeEnum::WITHDRAWAL->value])->setRange($start, $end)->setSourceAccounts($accounts);
$collector->withoutTags(); $collector->withoutTags();
$genericSet = $collector->getExtractedJournals(); $genericSet = $collector->getExtractedJournals();
foreach ($genericSet as $journal) { foreach ($genericSet as $journal) {
// same code as many other sumExpense methods. I think this needs some kind of generic method. // same code as many other sumExpense methods. I think this needs some kind of generic method.
$amount = '0'; $amount = '0';
$currencyId = (int) $journal['currency_id']; $currencyId = (int) $journal['currency_id'];
$currencyCode = $journal['currency_code']; $currencyCode = $journal['currency_code'];
if ($convertToNative) { if ($convertToNative) {
$amount = Amount::getAmountFromJournal($journal); $amount = Amount::getAmountFromJournal($journal);
if ($default->id !== (int) $journal['currency_id'] && $default->id !== (int) $journal['foreign_currency_id']) { if ($default->id !== (int) $journal['currency_id'] && $default->id !== (int) $journal['foreign_currency_id']) {
@@ -101,7 +101,7 @@ class TagController extends Controller
$amount = $journal['amount']; $amount = $journal['amount'];
} }
$response[$currencyId] ??= [ $response[$currencyId] ??= [
'difference' => '0', 'difference' => '0',
'difference_float' => 0, 'difference_float' => 0,
'currency_id' => (string) $currencyId, 'currency_id' => (string) $currencyId,
@@ -122,11 +122,11 @@ class TagController extends Controller
*/ */
public function tag(GenericRequest $request): JsonResponse public function tag(GenericRequest $request): JsonResponse
{ {
$accounts = $request->getAssetAccounts(); $accounts = $request->getAssetAccounts();
$tags = $request->getTags(); $tags = $request->getTags();
$start = $request->getStart(); $start = $request->getStart();
$end = $request->getEnd(); $end = $request->getEnd();
$response = []; $response = [];
// get all tags: // get all tags:
if (0 === $tags->count()) { if (0 === $tags->count()) {
@@ -134,7 +134,7 @@ class TagController extends Controller
} }
// collect all expenses in this period (regardless of type) by the given bills and accounts. // collect all expenses in this period (regardless of type) by the given bills and accounts.
$collector = app(GroupCollectorInterface::class); $collector = app(GroupCollectorInterface::class);
$collector->setTypes([TransactionTypeEnum::WITHDRAWAL->value])->setRange($start, $end)->setSourceAccounts($accounts); $collector->setTypes([TransactionTypeEnum::WITHDRAWAL->value])->setRange($start, $end)->setSourceAccounts($accounts);
$collector->setTags($tags); $collector->setTags($tags);
$genericSet = $collector->getExtractedJournals(); $genericSet = $collector->getExtractedJournals();
@@ -152,7 +152,7 @@ class TagController extends Controller
// on currency ID // on currency ID
if (0 !== $currencyId) { if (0 !== $currencyId) {
$response[$key] ??= [ $response[$key] ??= [
'id' => (string) $tagId, 'id' => (string) $tagId,
'name' => $tag['name'], 'name' => $tag['name'],
'difference' => '0', 'difference' => '0',

View File

@@ -50,14 +50,14 @@ class PeriodController extends Controller
$default = Amount::getDefaultCurrency(); $default = Amount::getDefaultCurrency();
// collect all expenses in this period (regardless of type) // collect all expenses in this period (regardless of type)
$collector = app(GroupCollectorInterface::class); $collector = app(GroupCollectorInterface::class);
$collector->setTypes([TransactionTypeEnum::DEPOSIT->value])->setRange($start, $end)->setDestinationAccounts($accounts); $collector->setTypes([TransactionTypeEnum::DEPOSIT->value])->setRange($start, $end)->setDestinationAccounts($accounts);
$genericSet = $collector->getExtractedJournals(); $genericSet = $collector->getExtractedJournals();
foreach ($genericSet as $journal) { foreach ($genericSet as $journal) {
// currency // currency
$currencyId = $journal['currency_id']; $currencyId = $journal['currency_id'];
$currencyCode = $journal['currency_code']; $currencyCode = $journal['currency_code'];
$field = $convertToNative && $currencyId !== $default->id ? 'native_amount' : 'amount'; $field = $convertToNative && $currencyId !== $default->id ? 'native_amount' : 'amount';
// perhaps use default currency instead? // perhaps use default currency instead?
if ($convertToNative && $journal['currency_id'] !== $default->id) { if ($convertToNative && $journal['currency_id'] !== $default->id) {
@@ -69,7 +69,7 @@ class PeriodController extends Controller
$field = 'foreign_amount'; $field = 'foreign_amount';
} }
$response[$currencyId] ??= [ $response[$currencyId] ??= [
'difference' => '0', 'difference' => '0',
'difference_float' => 0, 'difference_float' => 0,
'currency_id' => (string) $currencyId, 'currency_id' => (string) $currencyId,

View File

@@ -64,25 +64,25 @@ class TagController extends Controller
*/ */
public function noTag(GenericRequest $request): JsonResponse public function noTag(GenericRequest $request): JsonResponse
{ {
$accounts = $request->getAssetAccounts(); $accounts = $request->getAssetAccounts();
$start = $request->getStart(); $start = $request->getStart();
$end = $request->getEnd(); $end = $request->getEnd();
$response = []; $response = [];
$convertToNative = Amount::convertToNative(); $convertToNative = Amount::convertToNative();
$default = Amount::getDefaultCurrency(); $default = Amount::getDefaultCurrency();
// collect all expenses in this period (regardless of type) by the given bills and accounts. // collect all expenses in this period (regardless of type) by the given bills and accounts.
$collector = app(GroupCollectorInterface::class); $collector = app(GroupCollectorInterface::class);
$collector->setTypes([TransactionTypeEnum::DEPOSIT->value])->setRange($start, $end)->setDestinationAccounts($accounts); $collector->setTypes([TransactionTypeEnum::DEPOSIT->value])->setRange($start, $end)->setDestinationAccounts($accounts);
$collector->withoutTags(); $collector->withoutTags();
$genericSet = $collector->getExtractedJournals(); $genericSet = $collector->getExtractedJournals();
foreach ($genericSet as $journal) { foreach ($genericSet as $journal) {
// currency // currency
$currencyId = $journal['currency_id']; $currencyId = $journal['currency_id'];
$currencyCode = $journal['currency_code']; $currencyCode = $journal['currency_code'];
$field = $convertToNative && $currencyId !== $default->id ? 'native_amount' : 'amount'; $field = $convertToNative && $currencyId !== $default->id ? 'native_amount' : 'amount';
// perhaps use default currency instead? // perhaps use default currency instead?
if ($convertToNative && $journal['currency_id'] !== $default->id) { if ($convertToNative && $journal['currency_id'] !== $default->id) {
@@ -95,13 +95,13 @@ class TagController extends Controller
} }
$response[$currencyId] ??= [ $response[$currencyId] ??= [
'difference' => '0', 'difference' => '0',
'difference_float' => 0, 'difference_float' => 0,
'currency_id' => (string) $currencyId, 'currency_id' => (string) $currencyId,
'currency_code' => $currencyCode, 'currency_code' => $currencyCode,
]; ];
$response[$currencyId]['difference'] = bcadd($response[$currencyId]['difference'], app('steam')->positive($journal[$field])); $response[$currencyId]['difference'] = bcadd($response[$currencyId]['difference'], app('steam')->positive($journal[$field]));
$response[$currencyId]['difference_float'] = (float) $response[$currencyId]['difference']; $response[$currencyId]['difference_float'] = (float) $response[$currencyId]['difference'];
} }

View File

@@ -42,22 +42,22 @@ class PeriodController extends Controller
*/ */
public function total(GenericRequest $request): JsonResponse public function total(GenericRequest $request): JsonResponse
{ {
$accounts = $request->getAssetAccounts(); $accounts = $request->getAssetAccounts();
$start = $request->getStart(); $start = $request->getStart();
$end = $request->getEnd(); $end = $request->getEnd();
$response = []; $response = [];
$convertToNative = Amount::convertToNative(); $convertToNative = Amount::convertToNative();
$default = Amount::getDefaultCurrency(); $default = Amount::getDefaultCurrency();
// collect all expenses in this period (regardless of type) // collect all expenses in this period (regardless of type)
$collector = app(GroupCollectorInterface::class); $collector = app(GroupCollectorInterface::class);
$collector->setTypes([TransactionType::TRANSFER])->setRange($start, $end)->setDestinationAccounts($accounts); $collector->setTypes([TransactionType::TRANSFER])->setRange($start, $end)->setDestinationAccounts($accounts);
$genericSet = $collector->getExtractedJournals(); $genericSet = $collector->getExtractedJournals();
foreach ($genericSet as $journal) { foreach ($genericSet as $journal) {
// currency // currency
$currencyId = $journal['currency_id']; $currencyId = $journal['currency_id'];
$currencyCode = $journal['currency_code']; $currencyCode = $journal['currency_code'];
$field = $convertToNative && $currencyId !== $default->id ? 'native_amount' : 'amount'; $field = $convertToNative && $currencyId !== $default->id ? 'native_amount' : 'amount';
// perhaps use default currency instead? // perhaps use default currency instead?
if ($convertToNative && $journal['currency_id'] !== $default->id) { if ($convertToNative && $journal['currency_id'] !== $default->id) {
@@ -69,14 +69,14 @@ class PeriodController extends Controller
$field = 'foreign_amount'; $field = 'foreign_amount';
} }
$response[$currencyId] ??= [ $response[$currencyId] ??= [
'difference' => '0', 'difference' => '0',
'difference_float' => 0, 'difference_float' => 0,
'currency_id' => (string) $currencyId, 'currency_id' => (string) $currencyId,
'currency_code' => $currencyCode, 'currency_code' => $currencyCode,
]; ];
$response[$currencyId]['difference'] = bcadd($response[$currencyId]['difference'], app('steam')->positive($journal[$field])); $response[$currencyId]['difference'] = bcadd($response[$currencyId]['difference'], app('steam')->positive($journal[$field]));
$response[$currencyId]['difference_float'] = (float) $response[$currencyId]['difference']; $response[$currencyId]['difference_float'] = (float) $response[$currencyId]['difference'];
} }

View File

@@ -71,17 +71,17 @@ class TagController extends Controller
// collect all expenses in this period (regardless of type) by the given bills and accounts. // collect all expenses in this period (regardless of type) by the given bills and accounts.
$collector = app(GroupCollectorInterface::class); $collector = app(GroupCollectorInterface::class);
$collector->setTypes([TransactionType::TRANSFER])->setRange($start, $end)->setDestinationAccounts($accounts); $collector->setTypes([TransactionType::TRANSFER])->setRange($start, $end)->setDestinationAccounts($accounts);
$collector->withoutTags(); $collector->withoutTags();
$genericSet = $collector->getExtractedJournals(); $genericSet = $collector->getExtractedJournals();
foreach ($genericSet as $journal) { foreach ($genericSet as $journal) {
// currency // currency
$currencyId = $journal['currency_id']; $currencyId = $journal['currency_id'];
$currencyCode = $journal['currency_code']; $currencyCode = $journal['currency_code'];
$field = $convertToNative && $currencyId !== $default->id ? 'native_amount' : 'amount'; $field = $convertToNative && $currencyId !== $default->id ? 'native_amount' : 'amount';
// perhaps use default currency instead? // perhaps use default currency instead?
if ($convertToNative && $journal['currency_id'] !== $default->id) { if ($convertToNative && $journal['currency_id'] !== $default->id) {
@@ -93,7 +93,7 @@ class TagController extends Controller
$field = 'foreign_amount'; $field = 'foreign_amount';
} }
$response[$currencyId] ??= [ $response[$currencyId] ??= [
'difference' => '0', 'difference' => '0',
'difference_float' => 0, 'difference_float' => 0,
'currency_id' => (string) $currencyId, 'currency_id' => (string) $currencyId,
@@ -115,11 +115,11 @@ class TagController extends Controller
*/ */
public function tag(GenericRequest $request): JsonResponse public function tag(GenericRequest $request): JsonResponse
{ {
$accounts = $request->getAssetAccounts(); $accounts = $request->getAssetAccounts();
$tags = $request->getTags(); $tags = $request->getTags();
$start = $request->getStart(); $start = $request->getStart();
$end = $request->getEnd(); $end = $request->getEnd();
$response = []; $response = [];
// get all tags: // get all tags:
if (0 === $tags->count()) { if (0 === $tags->count()) {
@@ -127,7 +127,7 @@ class TagController extends Controller
} }
// collect all expenses in this period (regardless of type) by the given bills and accounts. // collect all expenses in this period (regardless of type) by the given bills and accounts.
$collector = app(GroupCollectorInterface::class); $collector = app(GroupCollectorInterface::class);
$collector->setTypes([TransactionType::TRANSFER])->setRange($start, $end)->setDestinationAccounts($accounts); $collector->setTypes([TransactionType::TRANSFER])->setRange($start, $end)->setDestinationAccounts($accounts);
$collector->setTags($tags); $collector->setTags($tags);
$genericSet = $collector->getExtractedJournals(); $genericSet = $collector->getExtractedJournals();
@@ -145,7 +145,7 @@ class TagController extends Controller
// on currency ID // on currency ID
if (0 !== $currencyId) { if (0 !== $currencyId) {
$response[$key] ??= [ $response[$key] ??= [
'id' => (string) $tagId, 'id' => (string) $tagId,
'name' => $tag['name'], 'name' => $tag['name'],
'difference' => '0', 'difference' => '0',

View File

@@ -105,18 +105,18 @@ class ShowController extends Controller
public function show(TransactionCurrency $currency): JsonResponse public function show(TransactionCurrency $currency): JsonResponse
{ {
/** @var User $user */ /** @var User $user */
$user = auth()->user(); $user = auth()->user();
$manager = $this->getManager(); $manager = $this->getManager();
$this->parameters->set('defaultCurrency', $this->defaultCurrency); $this->parameters->set('defaultCurrency', $this->defaultCurrency);
// update fields with user info. // update fields with user info.
$currency->refreshForUser($user); $currency->refreshForUser($user);
/** @var CurrencyTransformer $transformer */ /** @var CurrencyTransformer $transformer */
$transformer = app(CurrencyTransformer::class); $transformer = app(CurrencyTransformer::class);
$transformer->setParameters($this->parameters); $transformer->setParameters($this->parameters);
$resource = new Item($currency, $transformer, 'currencies'); $resource = new Item($currency, $transformer, 'currencies');
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', self::CONTENT_TYPE); return response()->json($manager->createData($resource)->toArray())->header('Content-Type', self::CONTENT_TYPE);
} }

View File

@@ -93,8 +93,8 @@ class Controller extends BaseController
if ($page < 1) { if ($page < 1) {
$page = 1; $page = 1;
} }
if ($page > pow(2,16)) { if ($page > 2 ** 16) {
$page = pow(2, 16); $page = 2 ** 16;
} }
$bag->set('page', $page); $bag->set('page', $page);

View File

@@ -43,11 +43,11 @@ class PiggyBankFactory
public User $user { public User $user {
set(User $value) { set(User $value) {
$this->user = $value; $this->user = $value;
$this->currencyRepository->setUser($value); $this->currencyRepository->setUser($value);
$this->accountRepository->setUser($value); $this->accountRepository->setUser($value);
$this->piggyBankRepository->setUser($value); $this->piggyBankRepository->setUser($value);
} }
} }
private AccountRepositoryInterface $accountRepository; private AccountRepositoryInterface $accountRepository;
private CurrencyRepositoryInterface $currencyRepository; private CurrencyRepositoryInterface $currencyRepository;
@@ -62,15 +62,11 @@ class PiggyBankFactory
/** /**
* Store a piggy bank or come back with an exception. * Store a piggy bank or come back with an exception.
*
* @param array $data
*
* @return PiggyBank
*/ */
public function store(array $data): PiggyBank public function store(array $data): PiggyBank
{ {
$piggyBankData = $data; $piggyBankData = $data;
// unset some fields // unset some fields
unset($piggyBankData['object_group_title'], $piggyBankData['transaction_currency_code'], $piggyBankData['transaction_currency_id'], $piggyBankData['accounts'], $piggyBankData['object_group_id'], $piggyBankData['notes']); unset($piggyBankData['object_group_title'], $piggyBankData['transaction_currency_code'], $piggyBankData['transaction_currency_id'], $piggyBankData['accounts'], $piggyBankData['object_group_id'], $piggyBankData['notes']);
@@ -94,11 +90,11 @@ class PiggyBankFactory
throw new FireflyException('400005: Could not store new piggy bank.', 0, $e); throw new FireflyException('400005: Could not store new piggy bank.', 0, $e);
} }
$piggyBank = $this->setOrder($piggyBank, $data); $piggyBank = $this->setOrder($piggyBank, $data);
$this->linkToAccountIds($piggyBank, $data['accounts']); $this->linkToAccountIds($piggyBank, $data['accounts']);
$this->piggyBankRepository->updateNote($piggyBank, $data['notes']); $this->piggyBankRepository->updateNote($piggyBank, $data['notes']);
$objectGroupTitle = $data['object_group_title'] ?? ''; $objectGroupTitle = $data['object_group_title'] ?? '';
if ('' !== $objectGroupTitle) { if ('' !== $objectGroupTitle) {
$objectGroup = $this->findOrCreateObjectGroup($objectGroupTitle); $objectGroup = $this->findOrCreateObjectGroup($objectGroupTitle);
if (null !== $objectGroup) { if (null !== $objectGroup) {
@@ -106,7 +102,7 @@ class PiggyBankFactory
} }
} }
// try also with ID // try also with ID
$objectGroupId = (int) ($data['object_group_id'] ?? 0); $objectGroupId = (int) ($data['object_group_id'] ?? 0);
if (0 !== $objectGroupId) { if (0 !== $objectGroupId) {
$objectGroup = $this->findObjectGroupById($objectGroupId); $objectGroup = $this->findObjectGroupById($objectGroupId);
if (null !== $objectGroup) { if (null !== $objectGroup) {
@@ -114,9 +110,10 @@ class PiggyBankFactory
} }
} }
Log::debug('Touch piggy bank'); Log::debug('Touch piggy bank');
$piggyBank->encrypted = false; $piggyBank->encrypted = false;
$piggyBank->save(); $piggyBank->save();
$piggyBank->touch(); $piggyBank->touch();
return $piggyBank; return $piggyBank;
} }
@@ -132,6 +129,7 @@ class PiggyBankFactory
$currency = $this->currencyRepository->find((int) ($data['transaction_currency_id'] ?? 0)); $currency = $this->currencyRepository->find((int) ($data['transaction_currency_id'] ?? 0));
} }
$currency ??= $defaultCurrency; $currency ??= $defaultCurrency;
return $currency; return $currency;
} }
@@ -144,12 +142,12 @@ class PiggyBankFactory
} }
// first find by ID: // first find by ID:
if ($piggyBankId > 0) { if ($piggyBankId > 0) {
$piggyBank = PiggyBank $piggyBank = PiggyBank::leftJoin('account_piggy_bank', 'account_piggy_bank.piggy_bank_id', '=', 'piggy_banks.id')
::leftJoin('account_piggy_bank', 'account_piggy_bank.piggy_bank_id', '=', 'piggy_banks.id')
->leftJoin('accounts', 'accounts.id', '=', 'account_piggy_bank.account_id') ->leftJoin('accounts', 'accounts.id', '=', 'account_piggy_bank.account_id')
->where('accounts.user_id', $this->user->id) ->where('accounts.user_id', $this->user->id)
->where('piggy_banks.id', $piggyBankId) ->where('piggy_banks.id', $piggyBankId)
->first(['piggy_banks.*']); ->first(['piggy_banks.*'])
;
if (null !== $piggyBank) { if (null !== $piggyBank) {
return $piggyBank; return $piggyBank;
} }
@@ -169,23 +167,24 @@ class PiggyBankFactory
public function findByName(string $name): ?PiggyBank public function findByName(string $name): ?PiggyBank
{ {
return PiggyBank return PiggyBank::leftJoin('account_piggy_bank', 'account_piggy_bank.piggy_bank_id', '=', 'piggy_banks.id')
::leftJoin('account_piggy_bank', 'account_piggy_bank.piggy_bank_id', '=', 'piggy_banks.id')
->leftJoin('accounts', 'accounts.id', '=', 'account_piggy_bank.account_id') ->leftJoin('accounts', 'accounts.id', '=', 'account_piggy_bank.account_id')
->where('accounts.user_id', $this->user->id) ->where('accounts.user_id', $this->user->id)
->where('piggy_banks.name', $name) ->where('piggy_banks.name', $name)
->first(['piggy_banks.*']); ->first(['piggy_banks.*'])
;
} }
private function setOrder(PiggyBank $piggyBank, array $data): PiggyBank private function setOrder(PiggyBank $piggyBank, array $data): PiggyBank
{ {
$this->resetOrder(); $this->resetOrder();
$order = $this->getMaxOrder() + 1; $order = $this->getMaxOrder() + 1;
if (array_key_exists('order', $data)) { if (array_key_exists('order', $data)) {
$order = $data['order']; $order = $data['order'];
} }
$piggyBank->order = $order; $piggyBank->order = $order;
$piggyBank->saveQuietly(); $piggyBank->saveQuietly();
return $piggyBank; return $piggyBank;
} }
@@ -193,8 +192,7 @@ class PiggyBankFactory
public function resetOrder(): void public function resetOrder(): void
{ {
// TODO duplicate code // TODO duplicate code
$set = PiggyBank $set = PiggyBank::leftJoin('account_piggy_bank', 'account_piggy_bank.piggy_bank_id', '=', 'piggy_banks.id')
::leftJoin('account_piggy_bank', 'account_piggy_bank.piggy_bank_id', '=', 'piggy_banks.id')
->leftJoin('accounts', 'accounts.id', '=', 'account_piggy_bank.account_id') ->leftJoin('accounts', 'accounts.id', '=', 'account_piggy_bank.account_id')
->where('accounts.user_id', $this->user->id) ->where('accounts.user_id', $this->user->id)
->with( ->with(
@@ -202,7 +200,8 @@ class PiggyBankFactory
'objectGroups', 'objectGroups',
] ]
) )
->orderBy('piggy_banks.order', 'ASC')->get(['piggy_banks.*']); ->orderBy('piggy_banks.order', 'ASC')->get(['piggy_banks.*'])
;
$current = 1; $current = 1;
foreach ($set as $piggyBank) { foreach ($set as $piggyBank) {
if ($piggyBank->order !== $current) { if ($piggyBank->order !== $current) {
@@ -214,7 +213,6 @@ class PiggyBankFactory
} }
} }
private function getMaxOrder(): int private function getMaxOrder(): int
{ {
return (int) $this->piggyBankRepository->getPiggyBanks()->max('order'); return (int) $this->piggyBankRepository->getPiggyBanks()->max('order');

View File

@@ -99,7 +99,7 @@ class PreferencesEventHandler
{ {
$repository = app(BudgetRepositoryInterface::class); $repository = app(BudgetRepositoryInterface::class);
$repository->setUserGroup($userGroup); $repository->setUserGroup($userGroup);
$set = $repository->getBudgets(); $set = $repository->getBudgets();
/** @var Budget $budget */ /** @var Budget $budget */
foreach ($set as $budget) { foreach ($set as $budget) {
@@ -127,13 +127,15 @@ class PreferencesEventHandler
{ {
// custom query because of the potential size of this update. // custom query because of the potential size of this update.
$success = DB::table('transactions') $success = DB::table('transactions')
->join('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id') ->join('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id')
->where('transaction_journals.user_group_id', $userGroup->id) ->where('transaction_journals.user_group_id', $userGroup->id)
->where(static function (Builder $q): void { ->where(static function (Builder $q): void {
$q->whereNotNull('native_amount') $q->whereNotNull('native_amount')
->orWhereNotNull('native_foreign_amount'); ->orWhereNotNull('native_foreign_amount')
}) ;
->update(['native_amount' => null, 'native_foreign_amount' => null]); })
->update(['native_amount' => null, 'native_foreign_amount' => null])
;
Log::debug(sprintf('Reset %d transactions.', $success)); Log::debug(sprintf('Reset %d transactions.', $success));
} }
} }

View File

@@ -39,7 +39,7 @@ class AvailableBudgetObserver
public function updated(AvailableBudget $availableBudget): void public function updated(AvailableBudget $availableBudget): void
{ {
//Log::debug('Observe "updated" of an available budget.'); // Log::debug('Observe "updated" of an available budget.');
$this->updateNativeAmount($availableBudget); $this->updateNativeAmount($availableBudget);
} }

View File

@@ -234,9 +234,9 @@ class BudgetController extends Controller
$key = sprintf('%d-%d', $journal['source_account_id'], $journal['currency_id']); $key = sprintf('%d-%d', $journal['source_account_id'], $journal['currency_id']);
$amount = $journal['amount']; $amount = $journal['amount'];
$symbol = $journal['currency_symbol']; $symbol = $journal['currency_symbol'];
$code = $journal['currency_code']; $code = $journal['currency_code'];
$name = $journal['currency_name']; $name = $journal['currency_name'];
// if convert to native, use the native things, unless it's the foreign amount which is in the native currency. // if convert to native, use the native things, unless it's the foreign amount which is in the native currency.
if ($this->convertToNative && $journal['currency_id'] !== $this->defaultCurrency->id) { if ($this->convertToNative && $journal['currency_id'] !== $this->defaultCurrency->id) {

View File

@@ -50,13 +50,13 @@ class Account extends Model
protected $casts protected $casts
= [ = [
'created_at' => 'datetime', 'created_at' => 'datetime',
'updated_at' => 'datetime', 'updated_at' => 'datetime',
'user_id' => 'integer', 'user_id' => 'integer',
'deleted_at' => 'datetime', 'deleted_at' => 'datetime',
'active' => 'boolean', 'active' => 'boolean',
'encrypted' => 'boolean', 'encrypted' => 'boolean',
'virtual_balance' => 'string', 'virtual_balance' => 'string',
'native_virtual_balance' => 'string', 'native_virtual_balance' => 'string',
]; ];

View File

@@ -48,10 +48,10 @@ class AutoBudget extends Model
public const int AUTO_BUDGET_ROLLOVER = 2; public const int AUTO_BUDGET_ROLLOVER = 2;
protected $casts protected $casts
= [ = [
'amount' => 'string', 'amount' => 'string',
'native_amount' => 'string', 'native_amount' => 'string',
]; ];
protected $fillable = ['budget_id', 'amount', 'period','native_amount']; protected $fillable = ['budget_id', 'amount', 'period', 'native_amount'];
public function budget(): BelongsTo public function budget(): BelongsTo
{ {

View File

@@ -53,7 +53,7 @@ class AvailableBudget extends Model
'native_amount' => 'string', 'native_amount' => 'string',
]; ];
protected $fillable = ['user_id', 'user_group_id', 'transaction_currency_id', 'amount', 'start_date', 'end_date', 'start_date_tz', 'end_date_tz','native_amount']; protected $fillable = ['user_id', 'user_group_id', 'transaction_currency_id', 'amount', 'start_date', 'end_date', 'start_date_tz', 'end_date_tz', 'native_amount'];
/** /**
* Route binder. Converts the key in the URL to the specified object (or throw 404). * Route binder. Converts the key in the URL to the specified object (or throw 404).

View File

@@ -43,12 +43,12 @@ class BudgetLimit extends Model
protected $casts protected $casts
= [ = [
'created_at' => 'datetime', 'created_at' => 'datetime',
'updated_at' => 'datetime', 'updated_at' => 'datetime',
'start_date' => SeparateTimezoneCaster::class, 'start_date' => SeparateTimezoneCaster::class,
'end_date' => SeparateTimezoneCaster::class, 'end_date' => SeparateTimezoneCaster::class,
'auto_budget' => 'boolean', 'auto_budget' => 'boolean',
'amount' => 'string', 'amount' => 'string',
'native_amount' => 'string', 'native_amount' => 'string',
]; ];
protected $dispatchesEvents protected $dispatchesEvents

View File

@@ -44,19 +44,19 @@ class PiggyBank extends Model
protected $casts protected $casts
= [ = [
'created_at' => 'datetime', 'created_at' => 'datetime',
'updated_at' => 'datetime', 'updated_at' => 'datetime',
'deleted_at' => 'datetime', 'deleted_at' => 'datetime',
'start_date' => 'date', 'start_date' => 'date',
'target_date' => 'date', 'target_date' => 'date',
'order' => 'int', 'order' => 'int',
'active' => 'boolean', 'active' => 'boolean',
'encrypted' => 'boolean', 'encrypted' => 'boolean',
'target_amount' => 'string', 'target_amount' => 'string',
'native_target_amount' => 'string', 'native_target_amount' => 'string',
]; ];
protected $fillable = ['name', 'order', 'target_amount', 'start_date', 'start_date_tz', 'target_date', 'target_date_tz', 'active', 'transaction_currency_id','native_target_amount']; protected $fillable = ['name', 'order', 'target_amount', 'start_date', 'start_date_tz', 'target_date', 'target_date_tz', 'active', 'transaction_currency_id', 'native_target_amount'];
/** /**
* Route binder. Converts the key in the URL to the specified object (or throw 404). * Route binder. Converts the key in the URL to the specified object (or throw 404).

View File

@@ -45,7 +45,7 @@ class PiggyBankEvent extends Model
'amount' => 'native_string', 'amount' => 'native_string',
]; ];
protected $fillable = ['piggy_bank_id', 'transaction_journal_id', 'date', 'date_tz', 'amount','native_amount']; protected $fillable = ['piggy_bank_id', 'transaction_journal_id', 'date', 'date_tz', 'amount', 'native_amount'];
protected $hidden = ['amount_encrypted']; protected $hidden = ['amount_encrypted'];

View File

@@ -28,12 +28,10 @@ use Carbon\Carbon;
use FireflyIII\Enums\TransactionTypeEnum; use FireflyIII\Enums\TransactionTypeEnum;
use FireflyIII\Helpers\Collector\GroupCollectorInterface; use FireflyIII\Helpers\Collector\GroupCollectorInterface;
use FireflyIII\Models\TransactionCurrency; use FireflyIII\Models\TransactionCurrency;
use FireflyIII\Support\Facades\Amount;
use FireflyIII\Support\Report\Summarizer\TransactionSummarizer; use FireflyIII\Support\Report\Summarizer\TransactionSummarizer;
use FireflyIII\User; use FireflyIII\User;
use Illuminate\Contracts\Auth\Authenticatable; use Illuminate\Contracts\Auth\Authenticatable;
use Illuminate\Support\Collection; use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Log;
/** /**
* Class OperationsRepository * Class OperationsRepository
@@ -68,7 +66,7 @@ class OperationsRepository implements OperationsRepositoryInterface
return $collector->getExtractedJournals(); return $collector->getExtractedJournals();
} }
public function setUser(null | Authenticatable | User $user): void public function setUser(null|Authenticatable|User $user): void
{ {
if ($user instanceof User) { if ($user instanceof User) {
$this->user = $user; $this->user = $user;
@@ -79,8 +77,8 @@ class OperationsRepository implements OperationsRepositoryInterface
{ {
$array = []; $array = [];
foreach ($journals as $journal) { foreach ($journals as $journal) {
$currencyId = (int) $journal['currency_id']; $currencyId = (int) $journal['currency_id'];
$journalId = (int) $journal['transaction_journal_id']; $journalId = (int) $journal['transaction_journal_id'];
$array[$currencyId] ??= [ $array[$currencyId] ??= [
'currency_id' => $journal['currency_id'], 'currency_id' => $journal['currency_id'],
'currency_name' => $journal['currency_name'], 'currency_name' => $journal['currency_name'],
@@ -132,8 +130,7 @@ class OperationsRepository implements OperationsRepositoryInterface
?Collection $accounts = null, ?Collection $accounts = null,
?Collection $expense = null, ?Collection $expense = null,
?TransactionCurrency $currency = null ?TransactionCurrency $currency = null
): array ): array {
{
$journals = $this->getTransactionsForSum(TransactionTypeEnum::WITHDRAWAL->value, $start, $end, $accounts, $expense, $currency); $journals = $this->getTransactionsForSum(TransactionTypeEnum::WITHDRAWAL->value, $start, $end, $accounts, $expense, $currency);
return $this->groupByCurrency($journals, 'negative'); return $this->groupByCurrency($journals, 'negative');
@@ -150,8 +147,7 @@ class OperationsRepository implements OperationsRepositoryInterface
?Collection $accounts = null, ?Collection $accounts = null,
?Collection $opposing = null, ?Collection $opposing = null,
?TransactionCurrency $currency = null ?TransactionCurrency $currency = null
): array ): array {
{
$start->startOfDay(); $start->startOfDay();
$end->endOfDay(); $end->endOfDay();
@@ -184,14 +180,15 @@ class OperationsRepository implements OperationsRepositoryInterface
if (null !== $currency) { if (null !== $currency) {
$collector->setCurrency($currency); $collector->setCurrency($currency);
} }
$journals = $collector->getExtractedJournals(); $journals = $collector->getExtractedJournals();
// same but for foreign currencies: // same but for foreign currencies:
if (null !== $currency) { if (null !== $currency) {
/** @var GroupCollectorInterface $collector */ /** @var GroupCollectorInterface $collector */
$collector = app(GroupCollectorInterface::class); $collector = app(GroupCollectorInterface::class);
$collector->setUser($this->user)->setRange($start, $end)->setTypes([$type])->withAccountInformation() $collector->setUser($this->user)->setRange($start, $end)->setTypes([$type])->withAccountInformation()
->setForeignCurrency($currency); ->setForeignCurrency($currency)
;
if (TransactionTypeEnum::WITHDRAWAL->value === $type) { if (TransactionTypeEnum::WITHDRAWAL->value === $type) {
if (null !== $accounts) { if (null !== $accounts) {
$collector->setSourceAccounts($accounts); $collector->setSourceAccounts($accounts);
@@ -209,10 +206,10 @@ class OperationsRepository implements OperationsRepositoryInterface
} }
} }
$result = $collector->getExtractedJournals(); $result = $collector->getExtractedJournals();
// do not use array_merge because you want keys to overwrite (otherwise you get double results): // do not use array_merge because you want keys to overwrite (otherwise you get double results):
$journals = $result + $journals; $journals = $result + $journals;
} }
return $journals; return $journals;
@@ -221,6 +218,7 @@ class OperationsRepository implements OperationsRepositoryInterface
private function groupByCurrency(array $journals, string $direction): array private function groupByCurrency(array $journals, string $direction): array
{ {
$summarizer = new TransactionSummarizer($this->user); $summarizer = new TransactionSummarizer($this->user);
return $summarizer->groupByCurrencyId($journals, $direction); return $summarizer->groupByCurrencyId($journals, $direction);
} }
@@ -233,8 +231,7 @@ class OperationsRepository implements OperationsRepositoryInterface
?Collection $accounts = null, ?Collection $accounts = null,
?Collection $expense = null, ?Collection $expense = null,
?TransactionCurrency $currency = null ?TransactionCurrency $currency = null
): array ): array {
{
$journals = $this->getTransactionsForSum(TransactionTypeEnum::WITHDRAWAL->value, $start, $end, $accounts, $expense, $currency); $journals = $this->getTransactionsForSum(TransactionTypeEnum::WITHDRAWAL->value, $start, $end, $accounts, $expense, $currency);
return $this->groupByDirection($journals, 'destination', 'negative'); return $this->groupByDirection($journals, 'destination', 'negative');
@@ -243,6 +240,7 @@ class OperationsRepository implements OperationsRepositoryInterface
private function groupByDirection(array $journals, string $direction, string $method): array private function groupByDirection(array $journals, string $direction, string $method): array
{ {
$summarizer = new TransactionSummarizer($this->user); $summarizer = new TransactionSummarizer($this->user);
return $summarizer->groupByDirection($journals, $method, $direction); return $summarizer->groupByDirection($journals, $method, $direction);
} }
@@ -255,8 +253,7 @@ class OperationsRepository implements OperationsRepositoryInterface
?Collection $accounts = null, ?Collection $accounts = null,
?Collection $expense = null, ?Collection $expense = null,
?TransactionCurrency $currency = null ?TransactionCurrency $currency = null
): array ): array {
{
$journals = $this->getTransactionsForSum(TransactionTypeEnum::WITHDRAWAL->value, $start, $end, $accounts, $expense, $currency); $journals = $this->getTransactionsForSum(TransactionTypeEnum::WITHDRAWAL->value, $start, $end, $accounts, $expense, $currency);
return $this->groupByDirection($journals, 'source', 'negative'); return $this->groupByDirection($journals, 'source', 'negative');
@@ -271,8 +268,7 @@ class OperationsRepository implements OperationsRepositoryInterface
?Collection $accounts = null, ?Collection $accounts = null,
?Collection $revenue = null, ?Collection $revenue = null,
?TransactionCurrency $currency = null ?TransactionCurrency $currency = null
): array ): array {
{
$journals = $this->getTransactionsForSum(TransactionTypeEnum::DEPOSIT->value, $start, $end, $accounts, $revenue, $currency); $journals = $this->getTransactionsForSum(TransactionTypeEnum::DEPOSIT->value, $start, $end, $accounts, $revenue, $currency);
return $this->groupByCurrency($journals, 'positive'); return $this->groupByCurrency($journals, 'positive');
@@ -287,8 +283,7 @@ class OperationsRepository implements OperationsRepositoryInterface
?Collection $accounts = null, ?Collection $accounts = null,
?Collection $revenue = null, ?Collection $revenue = null,
?TransactionCurrency $currency = null ?TransactionCurrency $currency = null
): array ): array {
{
$journals = $this->getTransactionsForSum(TransactionTypeEnum::DEPOSIT->value, $start, $end, $accounts, $revenue, $currency); $journals = $this->getTransactionsForSum(TransactionTypeEnum::DEPOSIT->value, $start, $end, $accounts, $revenue, $currency);
return $this->groupByDirection($journals, 'destination', 'positive'); return $this->groupByDirection($journals, 'destination', 'positive');
@@ -303,8 +298,7 @@ class OperationsRepository implements OperationsRepositoryInterface
?Collection $accounts = null, ?Collection $accounts = null,
?Collection $revenue = null, ?Collection $revenue = null,
?TransactionCurrency $currency = null ?TransactionCurrency $currency = null
): array ): array {
{
$journals = $this->getTransactionsForSum(TransactionTypeEnum::DEPOSIT->value, $start, $end, $accounts, $revenue, $currency); $journals = $this->getTransactionsForSum(TransactionTypeEnum::DEPOSIT->value, $start, $end, $accounts, $revenue, $currency);
return $this->groupByDirection($journals, 'source', 'positive'); return $this->groupByDirection($journals, 'source', 'positive');
@@ -325,7 +319,7 @@ class OperationsRepository implements OperationsRepositoryInterface
foreach ($journals as $journal) { foreach ($journals as $journal) {
$return = $this->groupByEitherJournal($return, $journal); $return = $this->groupByEitherJournal($return, $journal);
} }
$final = []; $final = [];
foreach ($return as $array) { foreach ($return as $array) {
$array['difference_float'] = (float) $array['difference']; $array['difference_float'] = (float) $array['difference'];
$array['in_float'] = (float) $array['in']; $array['in_float'] = (float) $array['in'];
@@ -338,12 +332,12 @@ class OperationsRepository implements OperationsRepositoryInterface
private function groupByEitherJournal(array $return, array $journal): array private function groupByEitherJournal(array $return, array $journal): array
{ {
$sourceId = $journal['source_account_id']; $sourceId = $journal['source_account_id'];
$destinationId = $journal['destination_account_id']; $destinationId = $journal['destination_account_id'];
$currencyId = $journal['currency_id']; $currencyId = $journal['currency_id'];
$sourceKey = sprintf('%d-%d', $currencyId, $sourceId); $sourceKey = sprintf('%d-%d', $currencyId, $sourceId);
$destKey = sprintf('%d-%d', $currencyId, $destinationId); $destKey = sprintf('%d-%d', $currencyId, $destinationId);
$amount = app('steam')->positive($journal['amount']); $amount = app('steam')->positive($journal['amount']);
// source first // source first
$return[$sourceKey] ??= [ $return[$sourceKey] ??= [
@@ -360,7 +354,7 @@ class OperationsRepository implements OperationsRepositoryInterface
]; ];
// dest next: // dest next:
$return[$destKey] ??= [ $return[$destKey] ??= [
'id' => (string) $destinationId, 'id' => (string) $destinationId,
'name' => $journal['destination_account_name'], 'name' => $journal['destination_account_name'],
'difference' => '0', 'difference' => '0',
@@ -378,15 +372,15 @@ class OperationsRepository implements OperationsRepositoryInterface
$return[$sourceKey]['difference'] = bcadd($return[$sourceKey]['out'], $return[$sourceKey]['in']); $return[$sourceKey]['difference'] = bcadd($return[$sourceKey]['out'], $return[$sourceKey]['in']);
// destination account? money comes in: // destination account? money comes in:
$return[$destKey]['in'] = bcadd($return[$destKey]['in'], $amount); $return[$destKey]['in'] = bcadd($return[$destKey]['in'], $amount);
$return[$destKey]['difference'] = bcadd($return[$destKey]['out'], $return[$destKey]['in']); $return[$destKey]['difference'] = bcadd($return[$destKey]['out'], $return[$destKey]['in']);
// foreign currency // foreign currency
if (null !== $journal['foreign_currency_id'] && null !== $journal['foreign_amount']) { if (null !== $journal['foreign_currency_id'] && null !== $journal['foreign_amount']) {
$currencyId = $journal['foreign_currency_id']; $currencyId = $journal['foreign_currency_id'];
$sourceKey = sprintf('%d-%d', $currencyId, $sourceId); $sourceKey = sprintf('%d-%d', $currencyId, $sourceId);
$destKey = sprintf('%d-%d', $currencyId, $destinationId); $destKey = sprintf('%d-%d', $currencyId, $destinationId);
$amount = app('steam')->positive($journal['foreign_amount']); $amount = app('steam')->positive($journal['foreign_amount']);
// same as above: // same as above:
// source first // source first
@@ -404,7 +398,7 @@ class OperationsRepository implements OperationsRepositoryInterface
]; ];
// dest next: // dest next:
$return[$destKey] ??= [ $return[$destKey] ??= [
'id' => (string) $destinationId, 'id' => (string) $destinationId,
'name' => $journal['destination_account_name'], 'name' => $journal['destination_account_name'],
'difference' => '0', 'difference' => '0',
@@ -421,8 +415,8 @@ class OperationsRepository implements OperationsRepositoryInterface
$return[$sourceKey]['difference'] = bcadd($return[$sourceKey]['out'], $return[$sourceKey]['in']); $return[$sourceKey]['difference'] = bcadd($return[$sourceKey]['out'], $return[$sourceKey]['in']);
// destination account? money comes in: // destination account? money comes in:
$return[$destKey]['in'] = bcadd($return[$destKey]['in'], $amount); $return[$destKey]['in'] = bcadd($return[$destKey]['in'], $amount);
$return[$destKey]['difference'] = bcadd($return[$destKey]['out'], $return[$destKey]['in']); $return[$destKey]['difference'] = bcadd($return[$destKey]['out'], $return[$destKey]['in']);
} }
return $return; return $return;

View File

@@ -586,7 +586,7 @@ class BillRepository implements BillRepositoryInterface
$minField = $convertToNative && $bill->transactionCurrency->id !== $default->id ? 'native_amount_min' : 'amount_min'; $minField = $convertToNative && $bill->transactionCurrency->id !== $default->id ? 'native_amount_min' : 'amount_min';
$maxField = $convertToNative && $bill->transactionCurrency->id !== $default->id ? 'native_amount_max' : 'amount_max'; $maxField = $convertToNative && $bill->transactionCurrency->id !== $default->id ? 'native_amount_max' : 'amount_max';
Log::debug(sprintf('min field is %s, max field is %s', $minField, $maxField)); Log::debug(sprintf('min field is %s, max field is %s', $minField, $maxField));
if ($total > 0) { if ($total > 0) {
$currency = $convertToNative && $bill->transactionCurrency->id !== $default->id ? $default : $bill->transactionCurrency; $currency = $convertToNative && $bill->transactionCurrency->id !== $default->id ? $default : $bill->transactionCurrency;

View File

@@ -29,12 +29,10 @@ use FireflyIII\Enums\TransactionTypeEnum;
use FireflyIII\Helpers\Collector\GroupCollectorInterface; use FireflyIII\Helpers\Collector\GroupCollectorInterface;
use FireflyIII\Models\TransactionCurrency; use FireflyIII\Models\TransactionCurrency;
use FireflyIII\Models\TransactionType; use FireflyIII\Models\TransactionType;
use FireflyIII\Support\Facades\Amount;
use FireflyIII\Support\Report\Summarizer\TransactionSummarizer; use FireflyIII\Support\Report\Summarizer\TransactionSummarizer;
use FireflyIII\User; use FireflyIII\User;
use Illuminate\Contracts\Auth\Authenticatable; use Illuminate\Contracts\Auth\Authenticatable;
use Illuminate\Support\Collection; use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Log;
/** /**
* Class NoBudgetRepository * Class NoBudgetRepository
@@ -93,7 +91,7 @@ class NoBudgetRepository implements NoBudgetRepositoryInterface
public function sumExpenses(Carbon $start, Carbon $end, ?Collection $accounts = null, ?TransactionCurrency $currency = null): array public function sumExpenses(Carbon $start, Carbon $end, ?Collection $accounts = null, ?TransactionCurrency $currency = null): array
{ {
/** @var GroupCollectorInterface $collector */ /** @var GroupCollectorInterface $collector */
$collector = app(GroupCollectorInterface::class); $collector = app(GroupCollectorInterface::class);
$collector->setUser($this->user)->setRange($start, $end)->setTypes([TransactionType::WITHDRAWAL]); $collector->setUser($this->user)->setRange($start, $end)->setTypes([TransactionType::WITHDRAWAL]);
if (null !== $accounts && $accounts->count() > 0) { if (null !== $accounts && $accounts->count() > 0) {
@@ -104,8 +102,9 @@ class NoBudgetRepository implements NoBudgetRepositoryInterface
} }
$collector->withoutBudget(); $collector->withoutBudget();
$collector->withBudgetInformation(); $collector->withBudgetInformation();
$journals = $collector->getExtractedJournals(); $journals = $collector->getExtractedJournals();
$summarizer = new TransactionSummarizer($this->user); $summarizer = new TransactionSummarizer($this->user);
return $summarizer->groupByCurrencyId($journals); return $summarizer->groupByCurrencyId($journals);
} }
} }

View File

@@ -218,10 +218,10 @@ class OperationsRepository implements OperationsRepositoryInterface
// 2024-12-24 disable the exclusion for now. // 2024-12-24 disable the exclusion for now.
$repository = app(AccountRepositoryInterface::class); $repository = app(AccountRepositoryInterface::class);
$repository->setUser($this->user); $repository->setUser($this->user);
$subset = $repository->getAccountsByType(config('firefly.valid_liabilities')); $subset = $repository->getAccountsByType(config('firefly.valid_liabilities'));
$selection = new Collection(); $selection = new Collection();
/** @var Account $account */ /** @var Account $account */
foreach ($subset as $account) { foreach ($subset as $account) {
@@ -231,7 +231,7 @@ class OperationsRepository implements OperationsRepositoryInterface
} }
/** @var GroupCollectorInterface $collector */ /** @var GroupCollectorInterface $collector */
$collector = app(GroupCollectorInterface::class); $collector = app(GroupCollectorInterface::class);
$collector->setUser($this->user) $collector->setUser($this->user)
->setRange($start, $end) ->setRange($start, $end)
// ->excludeDestinationAccounts($selection) // ->excludeDestinationAccounts($selection)
@@ -249,13 +249,14 @@ class OperationsRepository implements OperationsRepositoryInterface
$collector->setNormalCurrency($currency); $collector->setNormalCurrency($currency);
} }
$collector->setBudgets($budgets); $collector->setBudgets($budgets);
$journals = $collector->getExtractedJournals(); $journals = $collector->getExtractedJournals();
// same but for transactions in the foreign currency: // same but for transactions in the foreign currency:
if (null !== $currency) { if (null !== $currency) {
Log::debug('STOP looking for transactions in the foreign currency.'); Log::debug('STOP looking for transactions in the foreign currency.');
} }
$summarizer = new TransactionSummarizer($this->user); $summarizer = new TransactionSummarizer($this->user);
return $summarizer->groupByCurrencyId($journals); return $summarizer->groupByCurrencyId($journals);
} }
} }

View File

@@ -27,12 +27,10 @@ namespace FireflyIII\Repositories\Category;
use Carbon\Carbon; use Carbon\Carbon;
use FireflyIII\Helpers\Collector\GroupCollectorInterface; use FireflyIII\Helpers\Collector\GroupCollectorInterface;
use FireflyIII\Models\TransactionType; use FireflyIII\Models\TransactionType;
use FireflyIII\Support\Facades\Amount;
use FireflyIII\Support\Report\Summarizer\TransactionSummarizer; use FireflyIII\Support\Report\Summarizer\TransactionSummarizer;
use FireflyIII\User; use FireflyIII\User;
use Illuminate\Contracts\Auth\Authenticatable; use Illuminate\Contracts\Auth\Authenticatable;
use Illuminate\Support\Collection; use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Log;
/** /**
* Class NoCategoryRepository * Class NoCategoryRepository
@@ -146,14 +144,15 @@ class NoCategoryRepository implements NoCategoryRepositoryInterface
public function sumExpenses(Carbon $start, Carbon $end, ?Collection $accounts = null): array public function sumExpenses(Carbon $start, Carbon $end, ?Collection $accounts = null): array
{ {
/** @var GroupCollectorInterface $collector */ /** @var GroupCollectorInterface $collector */
$collector = app(GroupCollectorInterface::class); $collector = app(GroupCollectorInterface::class);
$collector->setUser($this->user)->setRange($start, $end)->setTypes([TransactionType::WITHDRAWAL])->withoutCategory(); $collector->setUser($this->user)->setRange($start, $end)->setTypes([TransactionType::WITHDRAWAL])->withoutCategory();
if (null !== $accounts && $accounts->count() > 0) { if (null !== $accounts && $accounts->count() > 0) {
$collector->setAccounts($accounts); $collector->setAccounts($accounts);
} }
$journals = $collector->getExtractedJournals(); $journals = $collector->getExtractedJournals();
$summarizer = new TransactionSummarizer($this->user); $summarizer = new TransactionSummarizer($this->user);
return $summarizer->groupByCurrencyId($journals); return $summarizer->groupByCurrencyId($journals);
} }

View File

@@ -328,7 +328,7 @@ class OperationsRepository implements OperationsRepositoryInterface
public function sumExpenses(Carbon $start, Carbon $end, ?Collection $accounts = null, ?Collection $categories = null): array public function sumExpenses(Carbon $start, Carbon $end, ?Collection $accounts = null, ?Collection $categories = null): array
{ {
/** @var GroupCollectorInterface $collector */ /** @var GroupCollectorInterface $collector */
$collector = app(GroupCollectorInterface::class); $collector = app(GroupCollectorInterface::class);
$collector->setUser($this->user)->setRange($start, $end)->setTypes([TransactionTypeEnum::WITHDRAWAL->value]); $collector->setUser($this->user)->setRange($start, $end)->setTypes([TransactionTypeEnum::WITHDRAWAL->value]);
if (null !== $accounts && $accounts->count() > 0) { if (null !== $accounts && $accounts->count() > 0) {
@@ -339,8 +339,9 @@ class OperationsRepository implements OperationsRepositoryInterface
} }
$collector->setCategories($categories); $collector->setCategories($categories);
$collector->withCategoryInformation(); $collector->withCategoryInformation();
$journals = $collector->getExtractedJournals(); $journals = $collector->getExtractedJournals();
$summarizer = new TransactionSummarizer($this->user); $summarizer = new TransactionSummarizer($this->user);
return $summarizer->groupByCurrencyId($journals); return $summarizer->groupByCurrencyId($journals);
} }

View File

@@ -85,16 +85,16 @@ class Amount
*/ */
public function getAmountFromJournalObject(TransactionJournal $journal): string public function getAmountFromJournalObject(TransactionJournal $journal): string
{ {
$convertToNative = $this->convertToNative(); $convertToNative = $this->convertToNative();
$currency = $this->getDefaultCurrency(); $currency = $this->getDefaultCurrency();
$field = $convertToNative && $currency->id !== $journal->transaction_currency_id ? 'native_amount' : 'amount'; $field = $convertToNative && $currency->id !== $journal->transaction_currency_id ? 'native_amount' : 'amount';
/** @var null|Transaction $sourceTransaction */ /** @var null|Transaction $sourceTransaction */
$sourceTransaction = $journal->transactions()->where('amount', '<', 0)->first(); $sourceTransaction = $journal->transactions()->where('amount', '<', 0)->first();
if (null === $sourceTransaction) { if (null === $sourceTransaction) {
return '0'; return '0';
} }
$amount = $sourceTransaction->{$field} ?? '0'; $amount = $sourceTransaction->{$field} ?? '0';
if ((int) $sourceTransaction->foreign_currency_id === $currency->id) { if ((int) $sourceTransaction->foreign_currency_id === $currency->id) {
// use foreign amount instead! // use foreign amount instead!
$amount = (string) $sourceTransaction->foreign_amount; // hard coded to be foreign amount. $amount = (string) $sourceTransaction->foreign_amount; // hard coded to be foreign amount.
@@ -113,15 +113,15 @@ class Amount
*/ */
public function formatFlat(string $symbol, int $decimalPlaces, string $amount, ?bool $coloured = null): string public function formatFlat(string $symbol, int $decimalPlaces, string $amount, ?bool $coloured = null): string
{ {
$locale = app('steam')->getLocale(); $locale = app('steam')->getLocale();
$rounded = app('steam')->bcround($amount, $decimalPlaces); $rounded = app('steam')->bcround($amount, $decimalPlaces);
$coloured ??= true; $coloured ??= true;
$fmt = new \NumberFormatter($locale, \NumberFormatter::CURRENCY); $fmt = new \NumberFormatter($locale, \NumberFormatter::CURRENCY);
$fmt->setSymbol(\NumberFormatter::CURRENCY_SYMBOL, $symbol); $fmt->setSymbol(\NumberFormatter::CURRENCY_SYMBOL, $symbol);
$fmt->setAttribute(\NumberFormatter::MIN_FRACTION_DIGITS, $decimalPlaces); $fmt->setAttribute(\NumberFormatter::MIN_FRACTION_DIGITS, $decimalPlaces);
$fmt->setAttribute(\NumberFormatter::MAX_FRACTION_DIGITS, $decimalPlaces); $fmt->setAttribute(\NumberFormatter::MAX_FRACTION_DIGITS, $decimalPlaces);
$result = (string) $fmt->format((float) $rounded); // intentional float $result = (string) $fmt->format((float) $rounded); // intentional float
if (true === $coloured) { if (true === $coloured) {
if (1 === bccomp($rounded, '0')) { if (1 === bccomp($rounded, '0')) {
@@ -166,12 +166,13 @@ class Amount
return $this->getDefaultCurrencyByUserGroup($user->userGroup); return $this->getDefaultCurrencyByUserGroup($user->userGroup);
} }
} }
return $this->getSystemCurrency(); return $this->getSystemCurrency();
} }
public function getDefaultCurrencyByUserGroup(UserGroup $userGroup): TransactionCurrency public function getDefaultCurrencyByUserGroup(UserGroup $userGroup): TransactionCurrency
{ {
$cache = new CacheProperties(); $cache = new CacheProperties();
$cache->addProperty('getDefaultCurrencyByGroup'); $cache->addProperty('getDefaultCurrencyByGroup');
$cache->addProperty($userGroup->id); $cache->addProperty($userGroup->id);
if ($cache->has()) { if ($cache->has()) {
@@ -234,20 +235,20 @@ class Amount
private function getLocaleInfo(): array private function getLocaleInfo(): array
{ {
// get config from preference, not from translation: // get config from preference, not from translation:
$locale = app('steam')->getLocale(); $locale = app('steam')->getLocale();
$array = app('steam')->getLocaleArray($locale); $array = app('steam')->getLocaleArray($locale);
setlocale(LC_MONETARY, $array); setlocale(LC_MONETARY, $array);
$info = localeconv(); $info = localeconv();
// correct variables // correct variables
$info['n_cs_precedes'] = $this->getLocaleField($info, 'n_cs_precedes'); $info['n_cs_precedes'] = $this->getLocaleField($info, 'n_cs_precedes');
$info['p_cs_precedes'] = $this->getLocaleField($info, 'p_cs_precedes'); $info['p_cs_precedes'] = $this->getLocaleField($info, 'p_cs_precedes');
$info['n_sep_by_space'] = $this->getLocaleField($info, 'n_sep_by_space'); $info['n_sep_by_space'] = $this->getLocaleField($info, 'n_sep_by_space');
$info['p_sep_by_space'] = $this->getLocaleField($info, 'p_sep_by_space'); $info['p_sep_by_space'] = $this->getLocaleField($info, 'p_sep_by_space');
$fmt = new \NumberFormatter($locale, \NumberFormatter::CURRENCY); $fmt = new \NumberFormatter($locale, \NumberFormatter::CURRENCY);
$info['mon_decimal_point'] = $fmt->getSymbol(\NumberFormatter::MONETARY_SEPARATOR_SYMBOL); $info['mon_decimal_point'] = $fmt->getSymbol(\NumberFormatter::MONETARY_SEPARATOR_SYMBOL);
$info['mon_thousands_sep'] = $fmt->getSymbol(\NumberFormatter::MONETARY_GROUPING_SEPARATOR_SYMBOL); $info['mon_thousands_sep'] = $fmt->getSymbol(\NumberFormatter::MONETARY_GROUPING_SEPARATOR_SYMBOL);
@@ -270,7 +271,7 @@ class Amount
public static function getAmountJsConfig(bool $sepBySpace, int $signPosn, string $sign, bool $csPrecedes): string public static function getAmountJsConfig(bool $sepBySpace, int $signPosn, string $sign, bool $csPrecedes): string
{ {
// negative first: // negative first:
$space = ' '; $space = ' ';
// require space between symbol and amount? // require space between symbol and amount?
if (false === $sepBySpace) { if (false === $sepBySpace) {
@@ -279,11 +280,11 @@ class Amount
// there are five possible positions for the "+" or "-" sign (if it is even used) // there are five possible positions for the "+" or "-" sign (if it is even used)
// pos_a and pos_e could be the ( and ) symbol. // pos_a and pos_e could be the ( and ) symbol.
$posA = ''; // before everything $posA = ''; // before everything
$posB = ''; // before currency symbol $posB = ''; // before currency symbol
$posC = ''; // after currency symbol $posC = ''; // after currency symbol
$posD = ''; // before amount $posD = ''; // before amount
$posE = ''; // after everything $posE = ''; // after everything
// format would be (currency before amount) // format would be (currency before amount)
// AB%sC_D%vE // AB%sC_D%vE
@@ -325,11 +326,11 @@ class Amount
} }
// default is amount before currency // default is amount before currency
$format = $posA . $posD . '%v' . $space . $posB . '%s' . $posC . $posE; $format = $posA.$posD.'%v'.$space.$posB.'%s'.$posC.$posE;
if ($csPrecedes) { if ($csPrecedes) {
// alternative is currency before amount // alternative is currency before amount
$format = $posA . $posB . '%s' . $posC . $space . $posD . '%v' . $posE; $format = $posA.$posB.'%s'.$posC.$space.$posD.'%v'.$posE;
} }
return $format; return $format;

View File

@@ -507,12 +507,12 @@ class Navigation
$diff = $start->diffInMonths($end, true); $diff = $start->diffInMonths($end, true);
Log::debug(sprintf('preferredCarbonFormat(%s, %s) = %f', $start->format('Y-m-d'), $end->format('Y-m-d'), $diff)); Log::debug(sprintf('preferredCarbonFormat(%s, %s) = %f', $start->format('Y-m-d'), $end->format('Y-m-d'), $diff));
if ($diff >= 1.001) { if ($diff >= 1.001) {
// Log::debug(sprintf('Return Y-m because %s', $diff)); // Log::debug(sprintf('Return Y-m because %s', $diff));
$format = 'Y-m'; $format = 'Y-m';
} }
if ($diff >= 12.001) { if ($diff >= 12.001) {
// Log::debug(sprintf('Return Y because %s', $diff)); // Log::debug(sprintf('Return Y because %s', $diff));
$format = 'Y'; $format = 'Y';
} }

View File

@@ -1,4 +1,5 @@
<?php <?php
/* /*
* TransactionSummarizer.php * TransactionSummarizer.php
* Copyright (c) 2024 james@firefly-iii.org. * Copyright (c) 2024 james@firefly-iii.org.
@@ -52,14 +53,14 @@ class TransactionSummarizer
{ {
$array = []; $array = [];
foreach ($journals as $journal) { foreach ($journals as $journal) {
$field = 'amount'; $field = 'amount';
// grab default currency information. // grab default currency information.
$currencyId = (int) $journal['currency_id']; $currencyId = (int) $journal['currency_id'];
$currencyName = $journal['currency_name']; $currencyName = $journal['currency_name'];
$currencySymbol = $journal['currency_symbol']; $currencySymbol = $journal['currency_symbol'];
$currencyCode = $journal['currency_code']; $currencyCode = $journal['currency_code'];
$currencyDecimalPlaces = $journal['currency_decimal_places']; $currencyDecimalPlaces = $journal['currency_decimal_places'];
if ($this->convertToNative) { if ($this->convertToNative) {
// if convert to native, use the native amount yes or no? // if convert to native, use the native amount yes or no?
$useNative = $this->default->id !== (int) $journal['currency_id']; $useNative = $this->default->id !== (int) $journal['currency_id'];
@@ -83,11 +84,11 @@ class TransactionSummarizer
$currencyDecimalPlaces = $journal['foreign_currency_decimal_places']; $currencyDecimalPlaces = $journal['foreign_currency_decimal_places'];
} }
} }
if(!$this->convertToNative) { if (!$this->convertToNative) {
// default to the normal amount, but also // default to the normal amount, but also
} }
$amount = (string) ($journal[$field] ?? '0'); $amount = (string) ($journal[$field] ?? '0');
$array[$currencyId] ??= [ $array[$currencyId] ??= [
'sum' => '0', 'sum' => '0',
'currency_id' => $currencyId, 'currency_id' => $currencyId,
'currency_name' => $currencyName, 'currency_name' => $currencyName,
@@ -95,14 +96,16 @@ class TransactionSummarizer
'currency_code' => $currencyCode, 'currency_code' => $currencyCode,
'currency_decimal_places' => $currencyDecimalPlaces, 'currency_decimal_places' => $currencyDecimalPlaces,
]; ];
$array[$currencyId]['sum'] = bcadd($array[$currencyId]['sum'], app('steam')->$method($amount)); $array[$currencyId]['sum'] = bcadd($array[$currencyId]['sum'], app('steam')->{$method}($amount));
Log::debug(sprintf('Journal #%d adds amount %s %s', $journal['transaction_journal_id'], $currencyCode, $amount)); Log::debug(sprintf('Journal #%d adds amount %s %s', $journal['transaction_journal_id'], $currencyCode, $amount));
} }
Log::debug('End of sumExpenses.', $array); Log::debug('End of sumExpenses.', $array);
return $array; return $array;
} }
public function groupByDirection(array $journals, string $method, string $direction): array { public function groupByDirection(array $journals, string $method, string $direction): array
{
$array = []; $array = [];
$idKey = sprintf('%s_account_id', $direction); $idKey = sprintf('%s_account_id', $direction);
@@ -136,7 +139,7 @@ class TransactionSummarizer
if ($convertToNative && $journal['currency_id'] !== $default->id && $default->id === $journal['foreign_currency_id']) { if ($convertToNative && $journal['currency_id'] !== $default->id && $default->id === $journal['foreign_currency_id']) {
$field = 'foreign_amount'; $field = 'foreign_amount';
} }
$key = sprintf('%s-%s', $journal[$idKey], $currencyId); $key = sprintf('%s-%s', $journal[$idKey], $currencyId);
// sum it all up or create a new array. // sum it all up or create a new array.
$array[$key] ??= [ $array[$key] ??= [
'id' => $journal[$idKey], 'id' => $journal[$idKey],
@@ -150,7 +153,7 @@ class TransactionSummarizer
]; ];
// add the data from the $field to the array. // add the data from the $field to the array.
$array[$key]['sum'] = bcadd($array[$key]['sum'], app('steam')->{$method}((string) ($journal[$field] ?? '0'))); // @phpstan-ignore-line $array[$key]['sum'] = bcadd($array[$key]['sum'], app('steam')->{$method}((string) ($journal[$field] ?? '0'))); // @phpstan-ignore-line
Log::debug(sprintf('Field for transaction #%d is "%s" (%s). Sum: %s', $journal['transaction_group_id'], $currencyCode, $field, $array[$key]['sum'])); Log::debug(sprintf('Field for transaction #%d is "%s" (%s). Sum: %s', $journal['transaction_group_id'], $currencyCode, $field, $array[$key]['sum']));
// also do foreign amount, but only when convertToNative is false (otherwise we have it already) // also do foreign amount, but only when convertToNative is false (otherwise we have it already)
@@ -158,7 +161,7 @@ class TransactionSummarizer
if ((!$convertToNative || $journal['foreign_currency_id'] !== $default->id) && 0 !== (int) $journal['foreign_currency_id']) { if ((!$convertToNative || $journal['foreign_currency_id'] !== $default->id) && 0 !== (int) $journal['foreign_currency_id']) {
Log::debug(sprintf('Use foreign amount from transaction #%d: %s %s. Sum: %s', $journal['transaction_group_id'], $currencyCode, $journal['foreign_amount'], $array[$key]['sum'])); Log::debug(sprintf('Use foreign amount from transaction #%d: %s %s. Sum: %s', $journal['transaction_group_id'], $currencyCode, $journal['foreign_amount'], $array[$key]['sum']));
$key = sprintf('%s-%s', $journal[$idKey], $journal['foreign_currency_id']); $key = sprintf('%s-%s', $journal[$idKey], $journal['foreign_currency_id']);
$array[$key] ??= [ $array[$key] ??= [
'id' => $journal[$idKey], 'id' => $journal[$idKey],
'name' => $journal[$nameKey], 'name' => $journal[$nameKey],
'sum' => '0', 'sum' => '0',
@@ -174,5 +177,4 @@ class TransactionSummarizer
return $array; return $array;
} }
} }

View File

@@ -58,7 +58,7 @@ class AccountTransformer extends AbstractTransformer
// get account type: // get account type:
$fullType = $account->accountType->type; $fullType = $account->accountType->type;
$accountType = (string) config(sprintf( 'firefly.shortNamesByFullName.%s', $fullType)); $accountType = (string) config(sprintf('firefly.shortNamesByFullName.%s', $fullType));
$liabilityType = (string) config(sprintf('firefly.shortLiabilityNameByFullName.%s', $fullType)); $liabilityType = (string) config(sprintf('firefly.shortLiabilityNameByFullName.%s', $fullType));
$liabilityType = '' === $liabilityType ? null : strtolower($liabilityType); $liabilityType = '' === $liabilityType ? null : strtolower($liabilityType);
$liabilityDirection = $this->repository->getMetaValue($account, 'liability_direction'); $liabilityDirection = $this->repository->getMetaValue($account, 'liability_direction');

View File

@@ -16,9 +16,9 @@ This project adheres to [Semantic Versioning](http://semver.org/).
- [Issue 7945](https://github.com/firefly-iii/firefly-iii/issues/7945) ("Rules" that only trigger manually) reported by @SekoiaTree - [Issue 7945](https://github.com/firefly-iii/firefly-iii/issues/7945) ("Rules" that only trigger manually) reported by @SekoiaTree
- [Issue 6760](https://github.com/firefly-iii/firefly-iii/issues/6760) (Add a new trigger for automated rules) reported by @Gsyltc - [Issue 6760](https://github.com/firefly-iii/firefly-iii/issues/6760) (Add a new trigger for automated rules) reported by @Gsyltc
- [Issue 6557](https://github.com/firefly-iii/firefly-iii/issues/6557) (Piggy Banks - Draw Funds from Multiple Accounts) reported by @BugPhobic - [Issue 6557](https://github.com/firefly-iii/firefly-iii/issues/6557) (Piggy Banks - Draw Funds from Multiple Accounts) reported by @BugPhobic
- #5532 - [Issue 5532](https://github.com/firefly-iii/firefly-iii/issues/5532) (Asset prices and exchange rates) reported by @svozniuk
- #6314 - [Issue 6314](https://github.com/firefly-iii/firefly-iii/issues/6314) (Currencies and exchange rates) reported by @JC5
- #9586 - [Issue 9586](https://github.com/firefly-iii/firefly-iii/issues/9586) (Non en_US translated string in sign-up mail) reported by @benni347
### Changed ### Changed

26
composer.lock generated
View File

@@ -2614,16 +2614,16 @@
}, },
{ {
"name": "league/commonmark", "name": "league/commonmark",
"version": "2.6.0", "version": "2.6.1",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/thephpleague/commonmark.git", "url": "https://github.com/thephpleague/commonmark.git",
"reference": "d150f911e0079e90ae3c106734c93137c184f932" "reference": "d990688c91cedfb69753ffc2512727ec646df2ad"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/thephpleague/commonmark/zipball/d150f911e0079e90ae3c106734c93137c184f932", "url": "https://api.github.com/repos/thephpleague/commonmark/zipball/d990688c91cedfb69753ffc2512727ec646df2ad",
"reference": "d150f911e0079e90ae3c106734c93137c184f932", "reference": "d990688c91cedfb69753ffc2512727ec646df2ad",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -2717,7 +2717,7 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2024-12-07T15:34:16+00:00" "time": "2024-12-29T14:10:59+00:00"
}, },
{ {
"name": "league/config", "name": "league/config",
@@ -10193,20 +10193,20 @@
}, },
{ {
"name": "barryvdh/laravel-ide-helper", "name": "barryvdh/laravel-ide-helper",
"version": "v3.3.0", "version": "v3.4.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/barryvdh/laravel-ide-helper.git", "url": "https://github.com/barryvdh/laravel-ide-helper.git",
"reference": "b7675670f75914bf34afdea52a6c2fe3781f7c44" "reference": "2a41415f01bf3c409d200f6cdd940c1e7d86cfd3"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/barryvdh/laravel-ide-helper/zipball/b7675670f75914bf34afdea52a6c2fe3781f7c44", "url": "https://api.github.com/repos/barryvdh/laravel-ide-helper/zipball/2a41415f01bf3c409d200f6cdd940c1e7d86cfd3",
"reference": "b7675670f75914bf34afdea52a6c2fe3781f7c44", "reference": "2a41415f01bf3c409d200f6cdd940c1e7d86cfd3",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"barryvdh/reflection-docblock": "^2.1.2", "barryvdh/reflection-docblock": "^2.2",
"composer/class-map-generator": "^1.0", "composer/class-map-generator": "^1.0",
"ext-json": "*", "ext-json": "*",
"illuminate/console": "^11.15", "illuminate/console": "^11.15",
@@ -10239,7 +10239,7 @@
] ]
}, },
"branch-alias": { "branch-alias": {
"dev-master": "3.2-dev" "dev-master": "3.4-dev"
} }
}, },
"autoload": { "autoload": {
@@ -10271,7 +10271,7 @@
], ],
"support": { "support": {
"issues": "https://github.com/barryvdh/laravel-ide-helper/issues", "issues": "https://github.com/barryvdh/laravel-ide-helper/issues",
"source": "https://github.com/barryvdh/laravel-ide-helper/tree/v3.3.0" "source": "https://github.com/barryvdh/laravel-ide-helper/tree/v3.4.0"
}, },
"funding": [ "funding": [
{ {
@@ -10283,7 +10283,7 @@
"type": "github" "type": "github"
} }
], ],
"time": "2024-12-18T08:24:19+00:00" "time": "2024-12-29T12:10:58+00:00"
}, },
{ {
"name": "barryvdh/reflection-docblock", "name": "barryvdh/reflection-docblock",

View File

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

View File

@@ -133,7 +133,7 @@
"header_exchange_rates": "Wechselkurse", "header_exchange_rates": "Wechselkurse",
"exchange_rates_intro": "Firefly III unterst\u00fctzt das Herunterladen und Verwenden von Wechselkursen. Lesen Sie mehr dar\u00fcber in <a href=\u201ehttps:\/\/docs.firefly-iii.org\/LOL_NOT_FINISHED_YET_TODO\u201c>der Dokumentation<\/a>.", "exchange_rates_intro": "Firefly III unterst\u00fctzt das Herunterladen und Verwenden von Wechselkursen. Lesen Sie mehr dar\u00fcber in <a href=\u201ehttps:\/\/docs.firefly-iii.org\/LOL_NOT_FINISHED_YET_TODO\u201c>der Dokumentation<\/a>.",
"exchange_rates_from_to": "Zwischen {from} und {to} (und umgekehrt)", "exchange_rates_from_to": "Zwischen {from} und {to} (und umgekehrt)",
"exchange_rates_intro_rates": "Firefly III uses the following exchange rates. The inverse is automatically calculated when it is not provided. If no exchange rate exists for the date of the transaction, Firefly III will go back in time to find one. If none are present, the rate \"1\" will be used.", "exchange_rates_intro_rates": "Firefly III verwendet die folgenden Wechselkurse. Der Kehrwert wird automatisch berechnet, wenn er nicht angegeben wurde. Wenn f\u00fcr das Datum der Transaktion kein Wechselkurs vorhanden ist, sucht Firefly III in der Vergangenheit nach einem Kurs. Wenn keine vorhanden sind, wird der Kurs \u201e1\u201c verwendet.",
"header_exchange_rates_rates": "Wechselkurse", "header_exchange_rates_rates": "Wechselkurse",
"header_exchange_rates_table": "Tabelle mit Wechselkursen", "header_exchange_rates_table": "Tabelle mit Wechselkursen",
"help_rate_form": "An diesem Tag, wie viele {to} werden Sie f\u00fcr {from} bekommen?", "help_rate_form": "An diesem Tag, wie viele {to} werden Sie f\u00fcr {from} bekommen?",

View File

@@ -36,7 +36,7 @@
"is_reconciled_fields_dropped": "Omdat deze transactie al is afgestemd, kan je het bedrag noch de rekeningen wijzigen.", "is_reconciled_fields_dropped": "Omdat deze transactie al is afgestemd, kan je het bedrag noch de rekeningen wijzigen.",
"tags": "Tags", "tags": "Tags",
"no_budget": "(geen budget)", "no_budget": "(geen budget)",
"no_bill": "(no subscription)", "no_bill": "(geen abonnement)",
"category": "Categorie", "category": "Categorie",
"attachments": "Bijlagen", "attachments": "Bijlagen",
"notes": "Notities", "notes": "Notities",
@@ -52,7 +52,7 @@
"destination_account_reconciliation": "Je kan de doelrekening van een afstemming niet wijzigen.", "destination_account_reconciliation": "Je kan de doelrekening van een afstemming niet wijzigen.",
"source_account_reconciliation": "Je kan de bronrekening van een afstemming niet wijzigen.", "source_account_reconciliation": "Je kan de bronrekening van een afstemming niet wijzigen.",
"budget": "Budget", "budget": "Budget",
"bill": "Subscription", "bill": "Abonnement",
"you_create_withdrawal": "Je maakt een uitgave.", "you_create_withdrawal": "Je maakt een uitgave.",
"you_create_transfer": "Je maakt een overschrijving.", "you_create_transfer": "Je maakt een overschrijving.",
"you_create_deposit": "Je maakt inkomsten.", "you_create_deposit": "Je maakt inkomsten.",
@@ -133,7 +133,7 @@
"header_exchange_rates": "Wisselkoersen", "header_exchange_rates": "Wisselkoersen",
"exchange_rates_intro": "Firefly III kan wisselkoersen downloaden en gebruiken. Lees hier meer over in <a href=\"https:\/\/docs.firefly-iii.org\/LOL_NOT_FINISHED_YET_TODO\">de documentatie<\/a>.", "exchange_rates_intro": "Firefly III kan wisselkoersen downloaden en gebruiken. Lees hier meer over in <a href=\"https:\/\/docs.firefly-iii.org\/LOL_NOT_FINISHED_YET_TODO\">de documentatie<\/a>.",
"exchange_rates_from_to": "Tussen {from} en {to} (en andersom)", "exchange_rates_from_to": "Tussen {from} en {to} (en andersom)",
"exchange_rates_intro_rates": "Firefly III uses the following exchange rates. The inverse is automatically calculated when it is not provided. If no exchange rate exists for the date of the transaction, Firefly III will go back in time to find one. If none are present, the rate \"1\" will be used.", "exchange_rates_intro_rates": "Firefly III gebruikt de volgende wisselkoersen. De inverse berekent zichzelf als deze niet is opgegeven. Als er geen wisselkoers bestaat voor de datum van de transactie, gaat Firefly III terug in de tijd om er een te vinden. Als er geen aanwezig is, zal de koers \"1\" gebruikt worden.",
"header_exchange_rates_rates": "Wisselkoersen", "header_exchange_rates_rates": "Wisselkoersen",
"header_exchange_rates_table": "Tabel met wisselkoersen", "header_exchange_rates_table": "Tabel met wisselkoersen",
"help_rate_form": "Hoeveel {to} krijg je op deze dag voor \u00e9\u00e9n {from}?", "help_rate_form": "Hoeveel {to} krijg je op deze dag voor \u00e9\u00e9n {from}?",

View File

@@ -54,9 +54,10 @@ abstract class TestCase extends BaseTestCase
protected function createAuthenticatedUser(): User protected function createAuthenticatedUser(): User
{ {
$group = UserGroup::create(['title' => 'test@email.com']); $group = UserGroup::create(['title' => 'test@email.com']);
return User::create([ return User::create([
'email' => 'test@email.com', 'email' => 'test@email.com',
'password' => 'password', 'password' => 'password',
'user_group_id' => $group->id, 'user_group_id' => $group->id,
]); ]);
} }