Merge pull request #12648 from firefly-iii/release-1787563853

🤖 Automatically merge the PR into the develop branch.
This commit is contained in:
github-actions[bot]
2026-08-24 11:31:03 +02:00
committed by GitHub
12 changed files with 94 additions and 44 deletions
@@ -158,7 +158,10 @@ final class TagController extends Controller
'currency_id' => (string) $foreignCurrencyId,
'currency_code' => $journal['foreign_currency_code'],
];
$response[$foreignKey]['difference'] = bcadd((string) $response[$foreignKey]['difference'], Steam::positive($journal['foreign_amount']));
$response[$foreignKey]['difference'] = bcadd(
(string) $response[$foreignKey]['difference'],
Steam::positive($journal['foreign_amount'])
);
$response[$foreignKey]['difference_float'] = (float) $response[$foreignKey]['difference'];
}
}
@@ -155,7 +155,10 @@ final class TagController extends Controller
'currency_id' => (string) $foreignCurrencyId,
'currency_code' => $journal['foreign_currency_code'],
];
$response[$foreignKey]['difference'] = bcadd((string) $response[$foreignKey]['difference'], Steam::positive($journal['foreign_amount']));
$response[$foreignKey]['difference'] = bcadd(
(string) $response[$foreignKey]['difference'],
Steam::positive($journal['foreign_amount'])
);
$response[$foreignKey]['difference_float'] = (float) $response[$foreignKey]['difference']; // intentional float
}
}
@@ -198,7 +198,13 @@ final class BudgetLimitController extends Controller
if ($request->expectsJson()) {
$array = $limit->toArray();
// add some extra metadata:
$spentArr = $this->opsRepository->sumExpenses($limit->start_date, $limit->end_date, null, new Collection()->push($budget), $currency);
$spentArr = $this->opsRepository->sumExpenses(
$limit->start_date,
$limit->end_date,
null,
new Collection()->push($budget),
$currency
);
$array['spent'] = $spentArr[$currency->id]['sum'] ?? '0';
$array['left_formatted'] = Amount::formatAnything($limit->transactionCurrency, bcadd($array['spent'], (string) $array['amount']));
$array['amount_formatted'] = Amount::formatAnything($limit->transactionCurrency, $limit['amount']);
@@ -284,7 +284,10 @@ final class IndexController extends Controller
if (array_key_exists($currency->id, $spentArr) && array_key_exists('sum', $spentArr[$currency->id])) {
$array['spent'][$currency->id]['spent'] = $spentArr[$currency->id]['sum'];
$array['spent'][$currency->id]['spent_outside'] = Steam::negative(bcsub($spentInLimits[$currency->id], $spentArr[$currency->id]['sum']));
$array['spent'][$currency->id]['spent_outside'] = Steam::negative(bcsub(
$spentInLimits[$currency->id],
$spentArr[$currency->id]['sum']
));
$array['spent'][$currency->id]['currency_id'] = $currency->id;
$array['spent'][$currency->id]['currency_symbol'] = $currency->symbol;
$array['spent'][$currency->id]['currency_decimal_places'] = $currency->decimal_places;
@@ -539,7 +539,13 @@ final class BudgetController extends Controller
}
// get spent amount in this period for this currency.
$sum = $this->opsRepository->sumExpenses($currentStart, $currentEnd, $accounts, new Collection()->push($budget), $currency);
$sum = $this->opsRepository->sumExpenses(
$currentStart,
$currentEnd,
$accounts,
new Collection()->push($budget),
$currency
);
$amount = Steam::positive($sum[$currency->id]['sum'] ?? '0');
$chartData[0]['entries'][$title] = Steam::bcround($amount, $currency->decimal_places);
+14 -2
View File
@@ -135,7 +135,13 @@ class CreateAutoBudgetLimits implements ShouldQueue
// if has one, calculate expenses and use that as a base.
$repository = app(OperationsRepositoryInterface::class);
$repository->setUser($autoBudget->budget->user);
$spent = $repository->sumExpenses($previousStart, $previousEnd, null, new Collection()->push($autoBudget->budget), $autoBudget->transactionCurrency);
$spent = $repository->sumExpenses(
$previousStart,
$previousEnd,
null,
new Collection()->push($autoBudget->budget),
$autoBudget->transactionCurrency
);
$currencyId = $autoBudget->transaction_currency_id;
$spentAmount = $spent[$currencyId]['sum'] ?? '0';
Log::debug(sprintf('Spent in previous budget period (%s-%s) is %s', $previousStart->format('Y-m-d'), $previousEnd->format('Y-m-d'), $spentAmount));
@@ -225,7 +231,13 @@ class CreateAutoBudgetLimits implements ShouldQueue
// if has one, calculate expenses and use that as a base.
$repository = app(OperationsRepositoryInterface::class);
$repository->setUser($autoBudget->budget->user);
$spent = $repository->sumExpenses($previousStart, $previousEnd, null, new Collection()->push($autoBudget->budget), $autoBudget->transactionCurrency);
$spent = $repository->sumExpenses(
$previousStart,
$previousEnd,
null,
new Collection()->push($autoBudget->budget),
$autoBudget->transactionCurrency
);
$currencyId = $autoBudget->transaction_currency_id;
$spentAmount = $spent[$currencyId]['sum'] ?? '0';
Log::debug(sprintf('Spent in previous budget period (%s-%s) is %s', $previousStart->format('Y-m-d'), $previousEnd->format('Y-m-d'), $spentAmount));
+2 -1
View File
@@ -186,9 +186,10 @@ class DownloadExchangeRates implements ShouldQueue
$existing = $this->repository->getExchangeRate($from, $to, $date);
if (!$existing instanceof CurrencyExchangeRate) {
Log::debug(sprintf('Saved rate from %s to %s for user #%d.', $from->code, $to->code, $user->id));
try {
$this->repository->setExchangeRate($from, $to, $date, $rate);
} catch(FireflyException $e) {
} catch (FireflyException $e) {
Log::warning(sprintf('Could not set exchange rate, but ignore this: %s', $e->getMessage()));
}
}
@@ -413,6 +413,7 @@ class CurrencyRepository implements CurrencyRepositoryInterface, UserGroupInterf
public function setExchangeRate(TransactionCurrency $fromCurrency, TransactionCurrency $toCurrency, Carbon $date, float $rate): CurrencyExchangeRate
{
$res = new CurrencyExchangeRate();
try {
$res = CurrencyExchangeRate::create([
'user_id' => $this->user->id,
@@ -423,25 +424,29 @@ class CurrencyRepository implements CurrencyRepositoryInterface, UserGroupInterf
'date_tz' => $date->format('e'),
'rate' => $rate,
]);
} catch(QueryException $e) {
} catch (QueryException $e) {
$message = $e->getMessage();
Log::error(sprintf('Could not save exchange rate: %s', $message));
if(str_contains($message,'Integrity constraint violation')) {
if (str_contains($message, 'Integrity constraint violation')) {
Log::warning(sprintf('Currency exchange rate already exists, so return existing one: %s', $message));
$res = CurrencyExchangeRate::where('user_id', $this->user->id)
->where('user_group_id', $this->userGroup->id)
->where('from_currency_id', $fromCurrency->id)
->where('to_currency_id', $toCurrency->id)
->where('date', $date)->first();
if(null === $res) {
->where('date', $date)
->first()
;
if (null === $res) {
Log::warning('Could not find currency exchange rate, throw exception.');
throw new FireflyException('Could not save new currency exchange rate, and returned null when trying to find existing one.');
}
return $res;
}
}
}
return $res;
return $res;
}
/**
@@ -222,7 +222,14 @@ trait AugumentData
$currentEnd->addMonth();
}
// primary currency amount.
$expenses = $opsRepository->sumExpenses($currentStart, $currentEnd, null, $budgetCollection, $entry->transactionCurrency, $this->convertToPrimary);
$expenses = $opsRepository->sumExpenses(
$currentStart,
$currentEnd,
null,
$budgetCollection,
$entry->transactionCurrency,
$this->convertToPrimary
);
$spent = $expenses[$currency->id]['sum'] ?? '0';
$entry->pc_spent = $spent;
@@ -354,7 +354,11 @@ class RecurringEnrichment implements EnrichmentInterface
/** @var RecurrenceRepetition $repetition */
foreach ($set as $repetition) {
$recurrence = $this->collection->filter(static fn (Recurrence $item): bool => (int) $item->id === (int) $repetition->recurrence_id)->first();
$recurrence = $this->collection->filter(
static fn (Recurrence $item): bool => (int) $item->id === (int) $repetition->recurrence_id
)
->first()
;
$fromDate = clone ($recurrence->latest_date ?? $recurrence->first_date);
$recurrenceId = (int) $repetition->recurrence_id;
$repId = (int) $repetition->id;
Generated
+27 -27
View File
@@ -1184,21 +1184,21 @@
},
{
"name": "graham-campbell/result-type",
"version": "v1.1.5",
"version": "v1.2.0",
"source": {
"type": "git",
"url": "https://github.com/GrahamCampbell/Result-Type.git",
"reference": "ef5e784ad5cf6c86fb262e3231aa11d84552fa12"
"reference": "adccca3324eece92ca35463648c12b9e6293c05b"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/GrahamCampbell/Result-Type/zipball/ef5e784ad5cf6c86fb262e3231aa11d84552fa12",
"reference": "ef5e784ad5cf6c86fb262e3231aa11d84552fa12",
"url": "https://api.github.com/repos/GrahamCampbell/Result-Type/zipball/adccca3324eece92ca35463648c12b9e6293c05b",
"reference": "adccca3324eece92ca35463648c12b9e6293c05b",
"shasum": ""
},
"require": {
"php": "^7.2.5 || ^8.0",
"phpoption/phpoption": "^1.9.6"
"phpoption/phpoption": "^1.10"
},
"require-dev": {
"phpunit/phpunit": "^8.5.52 || ^9.6.34 || ^10.5.63 || ^11.5.55 || ^12.5.14"
@@ -1230,7 +1230,7 @@
],
"support": {
"issues": "https://github.com/GrahamCampbell/Result-Type/issues",
"source": "https://github.com/GrahamCampbell/Result-Type/tree/v1.1.5"
"source": "https://github.com/GrahamCampbell/Result-Type/tree/v1.2.0"
},
"funding": [
{
@@ -1242,26 +1242,26 @@
"type": "tidelift"
}
],
"time": "2026-08-23T22:27:24+00:00"
"time": "2026-08-24T09:06:52+00:00"
},
{
"name": "guzzlehttp/guzzle",
"version": "7.15.3",
"version": "7.15.5",
"source": {
"type": "git",
"url": "https://github.com/guzzle/guzzle.git",
"reference": "ae311b8f045ea93ce7b1c9cdb7cec06c53f944bc"
"reference": "ee80339fd9177ba44c49cdb653ff02a4d1106b9a"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/guzzle/guzzle/zipball/ae311b8f045ea93ce7b1c9cdb7cec06c53f944bc",
"reference": "ae311b8f045ea93ce7b1c9cdb7cec06c53f944bc",
"url": "https://api.github.com/repos/guzzle/guzzle/zipball/ee80339fd9177ba44c49cdb653ff02a4d1106b9a",
"reference": "ee80339fd9177ba44c49cdb653ff02a4d1106b9a",
"shasum": ""
},
"require": {
"ext-json": "*",
"guzzlehttp/promises": "^2.5.2",
"guzzlehttp/psr7": "^2.13",
"guzzlehttp/promises": "^2.5.3",
"guzzlehttp/psr7": "^2.13.1",
"php": "^7.2.5 || ^8.0",
"psr/http-client": "^1.0",
"symfony/deprecation-contracts": "^2.5 || ^3.0",
@@ -1354,7 +1354,7 @@
],
"support": {
"issues": "https://github.com/guzzle/guzzle/issues",
"source": "https://github.com/guzzle/guzzle/tree/7.15.3"
"source": "https://github.com/guzzle/guzzle/tree/7.15.5"
},
"funding": [
{
@@ -1370,20 +1370,20 @@
"type": "tidelift"
}
],
"time": "2026-08-05T19:48:21+00:00"
"time": "2026-08-24T09:21:06+00:00"
},
{
"name": "guzzlehttp/promises",
"version": "2.5.2",
"version": "2.5.3",
"source": {
"type": "git",
"url": "https://github.com/guzzle/promises.git",
"reference": "2823687acff28b2dbe67b2508a6b300e2c3fa4ce"
"reference": "cde49999552d185d64715fe9c1f77a2aadd2f9f1"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/guzzle/promises/zipball/2823687acff28b2dbe67b2508a6b300e2c3fa4ce",
"reference": "2823687acff28b2dbe67b2508a6b300e2c3fa4ce",
"url": "https://api.github.com/repos/guzzle/promises/zipball/cde49999552d185d64715fe9c1f77a2aadd2f9f1",
"reference": "cde49999552d185d64715fe9c1f77a2aadd2f9f1",
"shasum": ""
},
"require": {
@@ -1438,7 +1438,7 @@
],
"support": {
"issues": "https://github.com/guzzle/promises/issues",
"source": "https://github.com/guzzle/promises/tree/2.5.2"
"source": "https://github.com/guzzle/promises/tree/2.5.3"
},
"funding": [
{
@@ -1454,20 +1454,20 @@
"type": "tidelift"
}
],
"time": "2026-08-05T19:30:54+00:00"
"time": "2026-08-24T09:11:28+00:00"
},
{
"name": "guzzlehttp/psr7",
"version": "2.13.0",
"version": "2.13.1",
"source": {
"type": "git",
"url": "https://github.com/guzzle/psr7.git",
"reference": "dad89620b7a6edb60c15858442eb2e408b45d8f4"
"reference": "95e7828100de18b4e269fb1703be530082d5166d"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/guzzle/psr7/zipball/dad89620b7a6edb60c15858442eb2e408b45d8f4",
"reference": "dad89620b7a6edb60c15858442eb2e408b45d8f4",
"url": "https://api.github.com/repos/guzzle/psr7/zipball/95e7828100de18b4e269fb1703be530082d5166d",
"reference": "95e7828100de18b4e269fb1703be530082d5166d",
"shasum": ""
},
"require": {
@@ -1557,7 +1557,7 @@
],
"support": {
"issues": "https://github.com/guzzle/psr7/issues",
"source": "https://github.com/guzzle/psr7/tree/2.13.0"
"source": "https://github.com/guzzle/psr7/tree/2.13.1"
},
"funding": [
{
@@ -1573,7 +1573,7 @@
"type": "tidelift"
}
],
"time": "2026-07-16T22:23:49+00:00"
"time": "2026-08-24T09:13:11+00:00"
},
{
"name": "guzzlehttp/uri-template",
+1 -1
View File
@@ -79,7 +79,7 @@ return [
// see cer.php for exchange rates feature flag.
],
'version' => 'develop/2026-08-24',
'build_time' => 1787562584,
'build_time' => 1787563853,
'api_version' => '2.1.0', // field is no longer used.
'db_version' => 28, // field is no longer used.