mirror of
https://github.com/firefly-iii/firefly-iii.git
synced 2025-09-16 09:51:16 +00:00
Merge pull request #10875 from firefly-iii/release-1757313349
🤖 Automatically merge the PR into the develop branch.
This commit is contained in:
@@ -46,7 +46,7 @@ class TransactionCurrencyFactory
|
||||
$data['decimal_places'] = (int)$data['decimal_places'];
|
||||
// if the code already exists (deleted)
|
||||
// force delete it and then create the transaction:
|
||||
$count = TransactionCurrency::withTrashed()->whereCode($data['code'])->count();
|
||||
$count = TransactionCurrency::withTrashed()->whereCode($data['code'])->count();
|
||||
if (1 === $count) {
|
||||
$old = TransactionCurrency::withTrashed()->whereCode($data['code'])->first();
|
||||
$old->forceDelete();
|
||||
@@ -104,6 +104,7 @@ class TransactionCurrencyFactory
|
||||
}
|
||||
}
|
||||
Log::info(sprintf('Found currency #%d based on ID %d and code "%s".', $currency->id, $currencyId, $currencyCode));
|
||||
|
||||
return $currency;
|
||||
}
|
||||
}
|
||||
|
@@ -1177,7 +1177,8 @@ class GroupCollector implements GroupCollectorInterface
|
||||
// include budget ID + name (if any)
|
||||
->withBudgetInformation()
|
||||
// include bill ID + name (if any)
|
||||
->withBillInformation();
|
||||
->withBillInformation()
|
||||
;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
@@ -62,7 +62,7 @@ class SubscriptionsOverdueReminder extends Notification
|
||||
'bill' => $item['bill'],
|
||||
];
|
||||
$current['pay_dates'] = array_map(
|
||||
static fn(string $date): string => new Carbon($date)->isoFormat((string)trans('config.month_and_day_moment_js')),
|
||||
static fn (string $date): string => new Carbon($date)->isoFormat((string)trans('config.month_and_day_moment_js')),
|
||||
$item['dates']['pay_dates']
|
||||
);
|
||||
$info[] = $current;
|
||||
|
@@ -294,7 +294,7 @@ class OperationsRepository implements OperationsRepositoryInterface, UserGroupIn
|
||||
$summarizer->setConvertToPrimary($convertToPrimary);
|
||||
|
||||
// filter $journals by range AND currency if it is present.
|
||||
$expenses = array_filter($expenses, static fn(array $expense): bool => $expense['date']->between($start, $end) && $expense['currency_id'] === $transactionCurrency->id);
|
||||
$expenses = array_filter($expenses, static fn (array $expense): bool => $expense['date']->between($start, $end) && $expense['currency_id'] === $transactionCurrency->id);
|
||||
|
||||
return $summarizer->groupByCurrencyId($expenses, 'negative', false);
|
||||
}
|
||||
@@ -306,7 +306,7 @@ class OperationsRepository implements OperationsRepositoryInterface, UserGroupIn
|
||||
$summarizer->setConvertToPrimary($convertToPrimary);
|
||||
|
||||
// filter $journals by range AND currency if it is present.
|
||||
$expenses = array_filter($expenses, static fn(array $expense): bool => $expense['budget_id'] === $budget->id);
|
||||
$expenses = array_filter($expenses, static fn (array $expense): bool => $expense['budget_id'] === $budget->id);
|
||||
|
||||
return $summarizer->groupByCurrencyId($expenses, 'negative', false);
|
||||
}
|
||||
|
@@ -44,6 +44,7 @@ use FireflyIII\Support\Repositories\UserGroup\UserGroupTrait;
|
||||
use Illuminate\Support\Collection;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Override;
|
||||
|
||||
use function Safe\json_encode;
|
||||
|
||||
/**
|
||||
@@ -69,7 +70,7 @@ class CurrencyRepository implements CurrencyRepositoryInterface, UserGroupInterf
|
||||
public function currencyInUseAt(TransactionCurrency $currency): ?string
|
||||
{
|
||||
Log::debug(sprintf('Now in currencyInUse() for #%d ("%s")', $currency->id, $currency->code));
|
||||
$countJournals = $this->countJournals($currency);
|
||||
$countJournals = $this->countJournals($currency);
|
||||
if ($countJournals > 0) {
|
||||
Log::info(sprintf('Count journals is %d, return true.', $countJournals));
|
||||
|
||||
@@ -84,7 +85,7 @@ class CurrencyRepository implements CurrencyRepositoryInterface, UserGroupInterf
|
||||
}
|
||||
|
||||
// is being used in accounts:
|
||||
$meta = AccountMeta::where('name', 'currency_id')->where('data', json_encode((string)$currency->id))->count();
|
||||
$meta = AccountMeta::where('name', 'currency_id')->where('data', json_encode((string)$currency->id))->count();
|
||||
if ($meta > 0) {
|
||||
Log::info(sprintf('Used in %d accounts as currency_id, return true. ', $meta));
|
||||
|
||||
@@ -92,7 +93,7 @@ class CurrencyRepository implements CurrencyRepositoryInterface, UserGroupInterf
|
||||
}
|
||||
|
||||
// second search using integer check.
|
||||
$meta = AccountMeta::where('name', 'currency_id')->where('data', json_encode((int)$currency->id))->count();
|
||||
$meta = AccountMeta::where('name', 'currency_id')->where('data', json_encode((int)$currency->id))->count();
|
||||
if ($meta > 0) {
|
||||
Log::info(sprintf('Used in %d accounts as currency_id, return true. ', $meta));
|
||||
|
||||
@@ -100,7 +101,7 @@ class CurrencyRepository implements CurrencyRepositoryInterface, UserGroupInterf
|
||||
}
|
||||
|
||||
// is being used in bills:
|
||||
$bills = Bill::where('transaction_currency_id', $currency->id)->count();
|
||||
$bills = Bill::where('transaction_currency_id', $currency->id)->count();
|
||||
if ($bills > 0) {
|
||||
Log::info(sprintf('Used in %d bills as currency, return true. ', $bills));
|
||||
|
||||
@@ -118,9 +119,10 @@ class CurrencyRepository implements CurrencyRepositoryInterface, UserGroupInterf
|
||||
}
|
||||
|
||||
// is being used in accounts (as integer)
|
||||
$meta = AccountMeta::leftJoin('accounts', 'accounts.id', '=', 'account_meta.account_id')
|
||||
->whereNull('accounts.deleted_at')
|
||||
->where('account_meta.name', 'currency_id')->where('account_meta.data', json_encode($currency->id))->count();
|
||||
$meta = AccountMeta::leftJoin('accounts', 'accounts.id', '=', 'account_meta.account_id')
|
||||
->whereNull('accounts.deleted_at')
|
||||
->where('account_meta.name', 'currency_id')->where('account_meta.data', json_encode($currency->id))->count()
|
||||
;
|
||||
if ($meta > 0) {
|
||||
Log::info(sprintf('Used in %d accounts as currency_id, return true. ', $meta));
|
||||
|
||||
@@ -136,7 +138,7 @@ class CurrencyRepository implements CurrencyRepositoryInterface, UserGroupInterf
|
||||
}
|
||||
|
||||
// is being used in budget limits
|
||||
$budgetLimit = BudgetLimit::where('transaction_currency_id', $currency->id)->count();
|
||||
$budgetLimit = BudgetLimit::where('transaction_currency_id', $currency->id)->count();
|
||||
if ($budgetLimit > 0) {
|
||||
Log::info(sprintf('Used in %d budget limits as currency, return true. ', $budgetLimit));
|
||||
|
||||
@@ -144,7 +146,7 @@ class CurrencyRepository implements CurrencyRepositoryInterface, UserGroupInterf
|
||||
}
|
||||
|
||||
// is the default currency for the user or the system
|
||||
$count = $this->userGroup->currencies()->where('transaction_currencies.id', $currency->id)->wherePivot('group_default', 1)->count();
|
||||
$count = $this->userGroup->currencies()->where('transaction_currencies.id', $currency->id)->wherePivot('group_default', 1)->count();
|
||||
if ($count > 0) {
|
||||
Log::info('Is the default currency of the user, return true.');
|
||||
|
||||
@@ -152,7 +154,7 @@ class CurrencyRepository implements CurrencyRepositoryInterface, UserGroupInterf
|
||||
}
|
||||
|
||||
// is the default currency for the user or the system
|
||||
$count = $this->userGroup->currencies()->where('transaction_currencies.id', $currency->id)->wherePivot('group_default', 1)->count();
|
||||
$count = $this->userGroup->currencies()->where('transaction_currencies.id', $currency->id)->wherePivot('group_default', 1)->count();
|
||||
if ($count > 0) {
|
||||
Log::info('Is the default currency of the user group, return true.');
|
||||
|
||||
@@ -181,8 +183,8 @@ class CurrencyRepository implements CurrencyRepositoryInterface, UserGroupInterf
|
||||
$local = $this->get();
|
||||
|
||||
return $all->map(static function (TransactionCurrency $current) use ($local) {
|
||||
$hasId = $local->contains(static fn(TransactionCurrency $entry) => $entry->id === $current->id);
|
||||
$isPrimary = $local->contains(static fn(TransactionCurrency $entry) => 1 === (int)$entry->pivot->group_default && $entry->id === $current->id);
|
||||
$hasId = $local->contains(static fn (TransactionCurrency $entry) => $entry->id === $current->id);
|
||||
$isPrimary = $local->contains(static fn (TransactionCurrency $entry) => 1 === (int)$entry->pivot->group_default && $entry->id === $current->id);
|
||||
$current->userGroupEnabled = $hasId;
|
||||
$current->userGroupNative = $isPrimary;
|
||||
|
||||
@@ -286,6 +288,7 @@ class CurrencyRepository implements CurrencyRepositoryInterface, UserGroupInterf
|
||||
} catch (FireflyException) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
@@ -299,6 +302,7 @@ class CurrencyRepository implements CurrencyRepositoryInterface, UserGroupInterf
|
||||
} catch (FireflyException) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
@@ -333,9 +337,10 @@ class CurrencyRepository implements CurrencyRepositoryInterface, UserGroupInterf
|
||||
|
||||
/** @var null|CurrencyExchangeRate $rate */
|
||||
$rate = $this->user->currencyExchangeRates()
|
||||
->where('from_currency_id', $fromCurrency->id)
|
||||
->where('to_currency_id', $toCurrency->id)
|
||||
->where('date', $date->format('Y-m-d'))->first();
|
||||
->where('from_currency_id', $fromCurrency->id)
|
||||
->where('to_currency_id', $toCurrency->id)
|
||||
->where('date', $date->format('Y-m-d'))->first()
|
||||
;
|
||||
if (null !== $rate) {
|
||||
Log::debug(sprintf('Found cached exchange rate in database for %s to %s on %s', $fromCurrency->code, $toCurrency->code, $date->format('Y-m-d')));
|
||||
|
||||
|
@@ -28,9 +28,7 @@ use Illuminate\Contracts\Validation\ValidationRule;
|
||||
|
||||
class IsValidSortInstruction implements ValidationRule
|
||||
{
|
||||
public function __construct(private readonly string $class)
|
||||
{
|
||||
}
|
||||
public function __construct(private readonly string $class) {}
|
||||
|
||||
public function validate(string $attribute, mixed $value, Closure $fail): void
|
||||
{
|
||||
|
@@ -221,7 +221,7 @@ class JournalUpdateService
|
||||
|
||||
private function hasFields(array $fields): bool
|
||||
{
|
||||
return array_any($fields, fn($field) => array_key_exists($field, $this->data));
|
||||
return array_any($fields, fn ($field) => array_key_exists($field, $this->data));
|
||||
}
|
||||
|
||||
private function getOriginalSourceAccount(): Account
|
||||
|
@@ -458,7 +458,7 @@ class AccountEnrichment implements EnrichmentInterface
|
||||
|
||||
case 'current_balance':
|
||||
case 'pc_current_balance':
|
||||
$this->collection = $this->collection->sortBy(static fn(Account $account) => $account->meta['balances'][$parameter[0]] ?? '0', SORT_NUMERIC, 'desc' === $parameter[1]);
|
||||
$this->collection = $this->collection->sortBy(static fn (Account $account) => $account->meta['balances'][$parameter[0]] ?? '0', SORT_NUMERIC, 'desc' === $parameter[1]);
|
||||
|
||||
break;
|
||||
}
|
||||
|
@@ -181,13 +181,13 @@ class BudgetLimitEnrichment implements EnrichmentInterface
|
||||
|
||||
private function stringifyIds(): void
|
||||
{
|
||||
$this->expenses = array_map(fn($first) => array_map(function ($second) {
|
||||
$this->expenses = array_map(fn ($first) => array_map(function ($second) {
|
||||
$second['currency_id'] = (string)($second['currency_id'] ?? 0);
|
||||
|
||||
return $second;
|
||||
}, $first), $this->expenses);
|
||||
|
||||
$this->pcExpenses = array_map(fn($first) => array_map(function ($second) {
|
||||
$this->pcExpenses = array_map(fn ($first) => array_map(function ($second) {
|
||||
$second['currency_id'] = (string)($second['currency_id'] ?? 0);
|
||||
|
||||
return $second;
|
||||
@@ -196,6 +196,6 @@ class BudgetLimitEnrichment implements EnrichmentInterface
|
||||
|
||||
private function filterToBudget(array $expenses, int $budget): array
|
||||
{
|
||||
return array_filter($expenses, fn(array $item) => (int)$item['budget_id'] === $budget);
|
||||
return array_filter($expenses, fn (array $item) => (int)$item['budget_id'] === $budget);
|
||||
}
|
||||
}
|
||||
|
@@ -274,7 +274,7 @@ class SubscriptionEnrichment implements EnrichmentInterface
|
||||
|
||||
// At this point the "next match" is exactly after the last time the bill was paid.
|
||||
$result = [];
|
||||
$filtered = $set->filter(fn(TransactionJournal $journal) => (int)$journal->bill_id === (int)$subscription->id);
|
||||
$filtered = $set->filter(fn (TransactionJournal $journal) => (int)$journal->bill_id === (int)$subscription->id);
|
||||
foreach ($filtered as $entry) {
|
||||
$array = [
|
||||
'transaction_group_id' => (string)$entry->transaction_group_id,
|
||||
@@ -344,7 +344,7 @@ class SubscriptionEnrichment implements EnrichmentInterface
|
||||
*/
|
||||
protected function lastPaidDate(Bill $subscription, Collection $dates, Carbon $default): Carbon
|
||||
{
|
||||
$filtered = $dates->filter(fn(TransactionJournal $journal) => (int)$journal->bill_id === (int)$subscription->id);
|
||||
$filtered = $dates->filter(fn (TransactionJournal $journal) => (int)$journal->bill_id === (int)$subscription->id);
|
||||
Log::debug(sprintf('Filtered down from %d to %d entries for bill #%d.', $dates->count(), $filtered->count(), $subscription->id));
|
||||
if (0 === $filtered->count()) {
|
||||
return $default;
|
||||
|
@@ -348,7 +348,7 @@ class Steam
|
||||
$currency = $currencies[$account->id];
|
||||
|
||||
// second array
|
||||
$accountSum = array_filter($arrayOfSums, fn($entry) => $entry['account_id'] === $account->id);
|
||||
$accountSum = array_filter($arrayOfSums, fn ($entry) => $entry['account_id'] === $account->id);
|
||||
if (0 === count($accountSum)) {
|
||||
$result[$account->id] = $return;
|
||||
|
||||
|
@@ -78,8 +78,8 @@ return [
|
||||
'running_balance_column' => env('USE_RUNNING_BALANCE', false),
|
||||
// see cer.php for exchange rates feature flag.
|
||||
],
|
||||
'version' => 'develop/2025-09-07',
|
||||
'build_time' => 1757249809,
|
||||
'version' => 'develop/2025-09-08',
|
||||
'build_time' => 1757313229,
|
||||
'api_version' => '2.1.0', // field is no longer used.
|
||||
'db_version' => 26,
|
||||
|
||||
|
@@ -116,9 +116,9 @@
|
||||
"webhook_trigger_DESTROY_BUDGET": "After budget delete",
|
||||
"webhook_trigger_STORE_UPDATE_BUDGET_LIMIT": "After budgeted amount change",
|
||||
"webhook_response_TRANSACTIONS": "\u039b\u03b5\u03c0\u03c4\u03bf\u03bc\u03ad\u03c1\u03b5\u03b9\u03b5\u03c2 \u03c3\u03c5\u03bd\u03b1\u03bb\u03bb\u03b1\u03b3\u03ae\u03c2",
|
||||
"webhook_response_RELEVANT": "Relevant details",
|
||||
"webhook_response_RELEVANT": "\u03a3\u03c7\u03b5\u03c4\u03b9\u03ba\u03ad\u03c2 \u03bb\u03b5\u03c0\u03c4\u03bf\u03bc\u03ad\u03c1\u03b5\u03b9\u03b5\u03c2",
|
||||
"webhook_response_ACCOUNTS": "\u03a0\u03bb\u03b7\u03c1\u03bf\u03c6\u03bf\u03c1\u03af\u03b5\u03c2 \u03bb\u03bf\u03b3\u03b1\u03c1\u03b9\u03b1\u03c3\u03bc\u03bf\u03cd",
|
||||
"webhook_response_NONE": "No details",
|
||||
"webhook_response_NONE": "\u0394\u03b5\u03bd \u03c5\u03c0\u03ac\u03c1\u03c7\u03bf\u03c5\u03bd \u03bb\u03b5\u03c0\u03c4\u03bf\u03bc\u03ad\u03c1\u03b5\u03b9\u03b5\u03c2",
|
||||
"webhook_delivery_JSON": "JSON",
|
||||
"actions": "\u0395\u03bd\u03ad\u03c1\u03b3\u03b5\u03b9\u03b5\u03c2",
|
||||
"meta_data": "\u039c\u03b5\u03c4\u03b1-\u03b4\u03b5\u03b4\u03bf\u03bc\u03ad\u03bd\u03b1",
|
||||
|
Reference in New Issue
Block a user