Merge branch 'develop' of github.com:firefly-iii/firefly-iii into develop

This commit is contained in:
James Cole
2025-09-07 17:30:43 +02:00
17 changed files with 253 additions and 232 deletions

View File

@@ -31,7 +31,6 @@ use FireflyIII\Enums\UserRoleEnum;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Models\Budget;
use FireflyIII\Models\BudgetLimit;
use FireflyIII\Models\TransactionCurrency;
use FireflyIII\Repositories\Budget\BudgetLimitRepositoryInterface;
use FireflyIII\Repositories\Budget\BudgetRepositoryInterface;
use FireflyIII\Repositories\Budget\OperationsRepositoryInterface;
@@ -252,7 +251,7 @@ class BudgetController extends Controller
/** @var array $journal */
foreach ($currentBudgetArray['transaction_journals'] as $journal) {
/** @var numeric-string $amount */
$amount= (string)$journal['amount'];
$amount = (string)$journal['amount'];
$return[$currencyId]['spent'] = bcadd($return[$currencyId]['spent'], $amount);
}
}

View File

@@ -55,6 +55,7 @@ class StoreByDateRequest extends FormRequest
/**
* The rules that the incoming request must be matched against.
*
* @return array<string, string>
*/
public function rules(): array
@@ -85,6 +86,7 @@ class StoreByDateRequest extends FormRequest
continue;
}
try {
$to = Amount::getTransactionCurrencyByCode((string)$key);
} catch (FireflyException) {

View File

@@ -40,9 +40,9 @@ class UpgradesCurrencyPreferences extends Command
public const string CONFIG_NAME = '610_upgrade_currency_prefs';
protected $description = 'Upgrade user currency preferences';
protected $description = 'Upgrade user currency preferences';
protected $signature = 'upgrade:610-currency-preferences {--F|force : Force the execution of this command.}';
protected $signature = 'upgrade:610-currency-preferences {--F|force : Force the execution of this command.}';
/**
* Execute the console command.
@@ -82,7 +82,7 @@ class UpgradesCurrencyPreferences extends Command
$this->upgradeGroupPreferences($group);
}
$users = User::get();
$users = User::get();
/** @var User $user */
foreach ($users as $user) {
@@ -119,6 +119,7 @@ class UpgradesCurrencyPreferences extends Command
// set the default currency for the user and for the group:
$preference = $this->getPreference($user);
try {
$primaryCurrency = Amount::getTransactionCurrencyByCode($preference);
} catch (FireflyException) {

View File

@@ -47,6 +47,7 @@ use Illuminate\Pagination\LengthAwarePaginator;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Log;
use Override;
use function Safe\json_decode;
/**
@@ -66,15 +67,15 @@ class GroupCollector implements GroupCollectorInterface
*/
public function __construct()
{
$this->sorting = [];
$this->postFilters = [];
$this->tags = [];
$this->user = null;
$this->userGroup = null;
$this->limit = null;
$this->page = null;
$this->startRow = null;
$this->endRow = null;
$this->sorting = [];
$this->postFilters = [];
$this->tags = [];
$this->user = null;
$this->userGroup = null;
$this->limit = null;
$this->page = null;
$this->startRow = null;
$this->endRow = null;
$this->hasAccountInfo = false;
$this->hasCatInformation = false;
@@ -304,7 +305,7 @@ class GroupCollector implements GroupCollectorInterface
if (is_int($param)) {
$replace = (string)$param;
}
$pos = strpos($query, '?');
$pos = strpos($query, '?');
if (false !== $pos) {
$query = substr_replace($query, $replace, $pos, 1);
}
@@ -476,15 +477,15 @@ class GroupCollector implements GroupCollectorInterface
// add to query:
$this->query->orWhereIn('transaction_journals.transaction_group_id', $groupIds);
}
$result = $this->query->get($this->fields);
$result = $this->query->get($this->fields);
// now to parse this into an array.
$collection = $this->parseArray($result);
$collection = $this->parseArray($result);
// filter the array using all available post filters:
$collection = $this->postFilterCollection($collection);
$collection = $this->postFilterCollection($collection);
// sort the collection, if sort instructions are present.
$collection = $this->sortCollection($collection);
$collection = $this->sortCollection($collection);
// count it and continue:
$this->total = $collection->count();
@@ -517,12 +518,12 @@ class GroupCollector implements GroupCollectorInterface
/** @var TransactionJournal $augumentedJournal */
foreach ($collection as $augumentedJournal) {
$groupId = (int)$augumentedJournal->transaction_group_id;
$groupId = (int)$augumentedJournal->transaction_group_id;
if (!array_key_exists($groupId, $groups)) {
// make new array
$parsedGroup = $this->parseAugmentedJournal($augumentedJournal);
$groupArray = [
$parsedGroup = $this->parseAugmentedJournal($augumentedJournal);
$groupArray = [
'id' => (int)$augumentedJournal->transaction_group_id,
'user_id' => $augumentedJournal->user_id,
'user_group_id' => $augumentedJournal->user_group_id,
@@ -593,7 +594,7 @@ class GroupCollector implements GroupCollectorInterface
}
// try to process meta date value (if present)
$dates = ['interest_date', 'payment_date', 'invoice_date', 'book_date', 'due_date', 'process_date'];
$dates = ['interest_date', 'payment_date', 'invoice_date', 'book_date', 'due_date', 'process_date'];
if (array_key_exists('meta_name', $result) && in_array($result['meta_name'], $dates, true)) {
$name = $result['meta_name'];
if (array_key_exists('meta_data', $result) && '' !== (string)$result['meta_data']) {
@@ -602,18 +603,18 @@ class GroupCollector implements GroupCollectorInterface
}
// convert values to integers:
$result = $this->convertToInteger($result);
$result = $this->convertToInteger($result);
// convert to boolean
$result = $this->convertToBoolean($result);
$result = $this->convertToBoolean($result);
// convert back to strings because SQLite is dumb like that.
$result = $this->convertToStrings($result);
$result = $this->convertToStrings($result);
$result['reconciled'] = 1 === (int)$result['reconciled'];
$result['reconciled'] = 1 === (int)$result['reconciled'];
if (array_key_exists('tag_id', $result) && null !== $result['tag_id']) { // assume the other fields are present as well.
$tagId = (int)$augumentedJournal['tag_id'];
$tagDate = null;
$tagId = (int)$augumentedJournal['tag_id'];
$tagDate = null;
try {
$tagDate = Carbon::parse($augumentedJournal['tag_date']);
@@ -686,9 +687,9 @@ class GroupCollector implements GroupCollectorInterface
{
$newArray = $newJournal->toArray();
if (array_key_exists('tag_id', $newArray)) { // assume the other fields are present as well.
$tagId = (int)$newJournal['tag_id'];
$tagId = (int)$newJournal['tag_id'];
$tagDate = null;
$tagDate = null;
try {
$tagDate = Carbon::parse($newArray['tag_date']);
@@ -711,7 +712,7 @@ class GroupCollector implements GroupCollectorInterface
{
$newArray = $newJournal->toArray();
if (array_key_exists('attachment_id', $newArray)) {
$attachmentId = (int)$newJournal['attachment_id'];
$attachmentId = (int)$newJournal['attachment_id'];
$existingJournal['attachments'][$attachmentId] = [
'id' => $attachmentId,
@@ -724,19 +725,19 @@ class GroupCollector implements GroupCollectorInterface
private function parseSums(array $groups): array
{
/**
* @var int $groudId
* @var int $groudId
* @var array $group
*/
foreach ($groups as $groudId => $group) {
/** @var array $transaction */
foreach ($group['transactions'] as $transaction) {
$currencyId = (int)$transaction['currency_id'];
$currencyId = (int)$transaction['currency_id'];
if (null === $transaction['amount']) {
throw new FireflyException(sprintf('Amount is NULL for a transaction in group #%d, please investigate.', $groudId));
}
$pcAmount = (string)('' === $transaction['pc_amount'] ? '0' : $transaction['pc_amount']);
$pcForeignAmount = (string)('' === $transaction['pc_foreign_amount'] ? '0' : $transaction['pc_foreign_amount']);
$foreignAmount = (string)('' === $transaction['foreign_amount'] ? '0' : $transaction['foreign_amount']);
$pcAmount = (string)('' === $transaction['pc_amount'] ? '0' : $transaction['pc_amount']);
$pcForeignAmount = (string)('' === $transaction['pc_foreign_amount'] ? '0' : $transaction['pc_foreign_amount']);
$foreignAmount = (string)('' === $transaction['foreign_amount'] ? '0' : $transaction['foreign_amount']);
// set default:
if (!array_key_exists($currencyId, $groups[$groudId]['sums'])) {
@@ -751,7 +752,7 @@ class GroupCollector implements GroupCollectorInterface
$groups[$groudId]['sums'][$currencyId]['pc_amount'] = bcadd((string)$groups[$groudId]['sums'][$currencyId]['pc_amount'], $pcAmount);
if (null !== $transaction['foreign_amount'] && null !== $transaction['foreign_currency_id']) {
$currencyId = (int)$transaction['foreign_currency_id'];
$currencyId = (int)$transaction['foreign_currency_id'];
// set default:
if (!array_key_exists($currencyId, $groups[$groudId]['sums'])) {
@@ -786,7 +787,7 @@ class GroupCollector implements GroupCollectorInterface
*/
foreach ($this->postFilters as $function) {
app('log')->debug('Applying filter...');
$nextCollection = new Collection();
$nextCollection = new Collection();
// loop everything in the current collection
// and save it (or not) in the new collection.
@@ -850,7 +851,7 @@ class GroupCollector implements GroupCollectorInterface
*/
public function getPaginatedGroups(): LengthAwarePaginator
{
$set = $this->getGroups();
$set = $this->getGroups();
if (0 === $this->limit) {
$this->setLimit(50);
}
@@ -1074,7 +1075,8 @@ class GroupCollector implements GroupCollectorInterface
'transactions as source',
static function (JoinClause $join): void {
$join->on('source.transaction_journal_id', '=', 'transaction_journals.id')
->where('source.amount', '<', 0);
->where('source.amount', '<', 0)
;
}
)
// join destination transaction
@@ -1082,7 +1084,8 @@ class GroupCollector implements GroupCollectorInterface
'transactions as destination',
static function (JoinClause $join): void {
$join->on('destination.transaction_journal_id', '=', 'transaction_journals.id')
->where('destination.amount', '>', 0);
->where('destination.amount', '>', 0)
;
}
)
// left join transaction type.
@@ -1101,7 +1104,8 @@ class GroupCollector implements GroupCollectorInterface
->orderBy('transaction_journals.order', 'ASC')
->orderBy('transaction_journals.id', 'DESC')
->orderBy('transaction_journals.description', 'DESC')
->orderBy('source.amount', 'DESC');
->orderBy('source.amount', 'DESC')
;
}
/**
@@ -1132,7 +1136,8 @@ class GroupCollector implements GroupCollectorInterface
'transactions as source',
static function (JoinClause $join): void {
$join->on('source.transaction_journal_id', '=', 'transaction_journals.id')
->where('source.amount', '<', 0);
->where('source.amount', '<', 0)
;
}
)
// join destination transaction
@@ -1140,7 +1145,8 @@ class GroupCollector implements GroupCollectorInterface
'transactions as destination',
static function (JoinClause $join): void {
$join->on('destination.transaction_journal_id', '=', 'transaction_journals.id')
->where('destination.amount', '>', 0);
->where('destination.amount', '>', 0)
;
}
)
// left join transaction type.
@@ -1155,7 +1161,8 @@ class GroupCollector implements GroupCollectorInterface
->orderBy('transaction_journals.order', 'ASC')
->orderBy('transaction_journals.id', 'DESC')
->orderBy('transaction_journals.description', 'DESC')
->orderBy('source.amount', 'DESC');
->orderBy('source.amount', 'DESC')
;
}
/**
@@ -1166,13 +1173,12 @@ class GroupCollector implements GroupCollectorInterface
// include source + destination account name and type.
$this->withAccountInformation()
// include category ID + name (if any)
->withCategoryInformation()
->withCategoryInformation()
// include budget ID + name (if any)
->withBudgetInformation()
->withBudgetInformation()
// include bill ID + name (if any)
->withBillInformation();
->withBillInformation();
return $this;
}
}

View File

@@ -104,20 +104,20 @@ class InterestingMessage
// send message about newly created transaction group.
/** @var null|TransactionGroup $group */
$group = auth()->user()->transactionGroups()->with(['transactionJournals', 'transactionJournals.transactionType'])->find((int)$transactionGroupId);
$group = auth()->user()->transactionGroups()->with(['transactionJournals', 'transactionJournals.transactionType'])->find((int)$transactionGroupId);
if (null === $group) {
return;
}
$count = $group->transactionJournals->count();
$count = $group->transactionJournals->count();
/** @var null|TransactionJournal $journal */
$journal = $group->transactionJournals->first();
$journal = $group->transactionJournals->first();
if (null === $journal) {
return;
}
$title = $count > 1 ? $group->title : $journal->description;
$title = $count > 1 ? $group->title : $journal->description;
if ('created' === $message) {
session()->flash('success_url', route('transactions.show', [$transactionGroupId]));
session()->flash('success', (string)trans('firefly.stored_journal', ['description' => $title]));
@@ -150,7 +150,7 @@ class InterestingMessage
$message = $request->get('message');
/** @var User $user */
$user = auth()->user();
$user = auth()->user();
/** @var null|UserGroup $userGroup */
$userGroup = UserGroup::find($userGroupId);
@@ -197,10 +197,10 @@ class InterestingMessage
$message = $request->get('message');
/** @var User $user */
$user = auth()->user();
$user = auth()->user();
/** @var null|Account $account */
$account = $user->accounts()->withTrashed()->find($accountId);
$account = $user->accounts()->withTrashed()->find($accountId);
if (null === $account) {
return;
@@ -232,7 +232,7 @@ class InterestingMessage
$message = $request->get('message');
/** @var null|Bill $bill */
$bill = auth()->user()->bills()->withTrashed()->find($billId);
$bill = auth()->user()->bills()->withTrashed()->find($billId);
if (null === $bill) {
return;
@@ -261,7 +261,7 @@ class InterestingMessage
$message = $request->get('message');
/** @var null|Webhook $webhook */
$webhook = auth()->user()->webhooks()->withTrashed()->find($webhookId);
$webhook = auth()->user()->webhooks()->withTrashed()->find($webhookId);
if (null === $webhook) {
return;
@@ -290,8 +290,9 @@ class InterestingMessage
{
// params:
// get parameters from request.
$code = (string) $request->get('code');
$message = (string) $request->get('message');
$code = (string) $request->get('code');
$message = (string) $request->get('message');
try {
$currency = Amount::getTransactionCurrencyByCode($code);
} catch (FireflyException) {

View File

@@ -107,7 +107,7 @@ class PiggyBankStoreRequest extends FormRequest
if ($accountCurrency->id !== $currency->id && 'true' !== $isMultiCurrency) {
$validator->errors()->add('accounts', trans('validation.invalid_account_currency'));
}
$type = $account->accountType->type;
$type = $account->accountType->type;
if (!in_array($type, $types, true)) {
$validator->errors()->add('accounts', trans('validation.invalid_account_type'));
}
@@ -125,6 +125,7 @@ class PiggyBankStoreRequest extends FormRequest
private function getCurrencyFromData(array $data): TransactionCurrency
{
$currencyId = (int)($data['transaction_currency_id'] ?? 0);
try {
$currency = Amount::getTransactionCurrencyById($currencyId);
} catch (FireflyException) {

View File

@@ -130,6 +130,7 @@ class PiggyBankUpdateRequest extends FormRequest
private function getCurrencyFromData(array $data): TransactionCurrency
{
$currencyId = (int) ($data['transaction_currency_id'] ?? 0);
try {
$currency = Amount::getTransactionCurrencyById($currencyId);
} catch (FireflyException) {

View File

@@ -71,9 +71,9 @@ trait ModifiesPiggyBanks
$pivot->native_current_amount = null;
// also update native_current_amount.
$userCurrency = app('amount')->getPrimaryCurrencyByUserGroup($this->user->userGroup);
$userCurrency = app('amount')->getPrimaryCurrencyByUserGroup($this->user->userGroup);
if ($userCurrency->id !== $piggyBank->transaction_currency_id) {
$converter = new ExchangeRateConverter();
$converter = new ExchangeRateConverter();
$converter->setIgnoreSettings(true);
$pivot->native_current_amount = $converter->convert($piggyBank->transactionCurrency, $userCurrency, today(), $pivot->current_amount);
}
@@ -94,9 +94,9 @@ trait ModifiesPiggyBanks
$pivot->native_current_amount = null;
// also update native_current_amount.
$userCurrency = app('amount')->getPrimaryCurrencyByUserGroup($this->user->userGroup);
$userCurrency = app('amount')->getPrimaryCurrencyByUserGroup($this->user->userGroup);
if ($userCurrency->id !== $piggyBank->transaction_currency_id) {
$converter = new ExchangeRateConverter();
$converter = new ExchangeRateConverter();
$converter->setIgnoreSettings(true);
$pivot->native_current_amount = $converter->convert($piggyBank->transactionCurrency, $userCurrency, today(), $pivot->current_amount);
}
@@ -128,8 +128,8 @@ trait ModifiesPiggyBanks
Log::debug(sprintf('Maximum amount: %s', $maxAmount));
}
$compare = bccomp($amount, $maxAmount);
$result = $compare <= 0;
$compare = bccomp($amount, $maxAmount);
$result = $compare <= 0;
Log::debug(sprintf('Compare <= 0? %d, so canAddAmount is %s', $compare, var_export($result, true)));
@@ -163,11 +163,11 @@ trait ModifiesPiggyBanks
public function setCurrentAmount(PiggyBank $piggyBank, string $amount): PiggyBank
{
$repetition = $this->getRepetition($piggyBank);
$repetition = $this->getRepetition($piggyBank);
if (null === $repetition) {
return $piggyBank;
}
$max = $piggyBank->target_amount;
$max = $piggyBank->target_amount;
if (1 === bccomp($amount, $max) && 0 !== bccomp($piggyBank->target_amount, '0')) {
$amount = $max;
}
@@ -210,14 +210,14 @@ trait ModifiesPiggyBanks
public function update(PiggyBank $piggyBank, array $data): PiggyBank
{
$piggyBank = $this->updateProperties($piggyBank, $data);
$piggyBank = $this->updateProperties($piggyBank, $data);
if (array_key_exists('notes', $data)) {
$this->updateNote($piggyBank, (string)$data['notes']);
}
// update the order of the piggy bank:
$oldOrder = $piggyBank->order;
$newOrder = (int)($data['order'] ?? $oldOrder);
$oldOrder = $piggyBank->order;
$newOrder = (int)($data['order'] ?? $oldOrder);
if ($oldOrder !== $newOrder) {
$this->setOrder($piggyBank, $newOrder);
}
@@ -318,7 +318,7 @@ trait ModifiesPiggyBanks
return;
}
$dbNote = $piggyBank->notes()->first();
$dbNote = $piggyBank->notes()->first();
if (null === $dbNote) {
$dbNote = new Note();
$dbNote->noteable()->associate($piggyBank);
@@ -329,15 +329,16 @@ trait ModifiesPiggyBanks
public function setOrder(PiggyBank $piggyBank, int $newOrder): bool
{
$oldOrder = $piggyBank->order;
$oldOrder = $piggyBank->order;
// Log::debug(sprintf('Will move piggy bank #%d ("%s") from %d to %d', $piggyBank->id, $piggyBank->name, $oldOrder, $newOrder));
if ($newOrder > $oldOrder) {
PiggyBank::leftJoin('account_piggy_bank', 'account_piggy_bank.piggy_bank_id', '=', 'piggy_banks.id')
->leftJoin('accounts', 'accounts.id', '=', 'account_piggy_bank.account_id')
->where('accounts.user_id', $this->user->id)
->where('piggy_banks.order', '<=', $newOrder)->where('piggy_banks.order', '>', $oldOrder)
->where('piggy_banks.id', '!=', $piggyBank->id)
->distinct()->decrement('piggy_banks.order');
->leftJoin('accounts', 'accounts.id', '=', 'account_piggy_bank.account_id')
->where('accounts.user_id', $this->user->id)
->where('piggy_banks.order', '<=', $newOrder)->where('piggy_banks.order', '>', $oldOrder)
->where('piggy_banks.id', '!=', $piggyBank->id)
->distinct()->decrement('piggy_banks.order')
;
$piggyBank->order = $newOrder;
Log::debug(sprintf('[1] Order of piggy #%d ("%s") from %d to %d', $piggyBank->id, $piggyBank->name, $oldOrder, $newOrder));
@@ -346,11 +347,12 @@ trait ModifiesPiggyBanks
return true;
}
PiggyBank::leftJoin('account_piggy_bank', 'account_piggy_bank.piggy_bank_id', '=', 'piggy_banks.id')
->leftJoin('accounts', 'accounts.id', '=', 'account_piggy_bank.account_id')
->where('accounts.user_id', $this->user->id)
->where('piggy_banks.order', '>=', $newOrder)->where('piggy_banks.order', '<', $oldOrder)
->where('piggy_banks.id', '!=', $piggyBank->id)
->distinct()->increment('piggy_banks.order');
->leftJoin('accounts', 'accounts.id', '=', 'account_piggy_bank.account_id')
->where('accounts.user_id', $this->user->id)
->where('piggy_banks.order', '>=', $newOrder)->where('piggy_banks.order', '<', $oldOrder)
->where('piggy_banks.id', '!=', $piggyBank->id)
->distinct()->increment('piggy_banks.order')
;
$piggyBank->order = $newOrder;
Log::debug(sprintf('[2] Order of piggy #%d ("%s") from %d to %d', $piggyBank->id, $piggyBank->name, $oldOrder, $newOrder));
@@ -371,7 +373,7 @@ trait ModifiesPiggyBanks
}
// if this account contains less than the amount, remove the current amount, update the amount and continue.
$this->removeAmount($piggyBank, $account, $current);
$amount = bcsub($amount, (string)$current);
$amount = bcsub($amount, (string)$current);
}
}
}

View File

@@ -36,7 +36,6 @@ use FireflyIII\Models\Location;
use FireflyIII\Models\Note;
use FireflyIII\Models\PiggyBankEvent;
use FireflyIII\Models\Transaction;
use FireflyIII\Models\TransactionCurrency;
use FireflyIII\Models\TransactionGroup;
use FireflyIII\Models\TransactionJournal;
use FireflyIII\Models\TransactionJournalLink;

View File

@@ -60,15 +60,15 @@ class Amount
*/
public function formatFlat(string $symbol, int $decimalPlaces, string $amount, ?bool $coloured = null): string
{
$locale = Steam::getLocale();
$rounded = Steam::bcround($amount, $decimalPlaces);
$locale = Steam::getLocale();
$rounded = Steam::bcround($amount, $decimalPlaces);
$coloured ??= true;
$fmt = new NumberFormatter($locale, NumberFormatter::CURRENCY);
$fmt = new NumberFormatter($locale, NumberFormatter::CURRENCY);
$fmt->setSymbol(NumberFormatter::CURRENCY_SYMBOL, $symbol);
$fmt->setAttribute(NumberFormatter::MIN_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 (1 === bccomp($rounded, '0')) {
@@ -120,8 +120,9 @@ class Amount
{
$instance = PreferencesSingleton::getInstance();
$key = sprintf('transaction_currency_%d', $currencyId);
/** @var TransactionCurrency|null $pref */
$pref = $instance->getPreference($key);
/** @var null|TransactionCurrency $pref */
$pref = $instance->getPreference($key);
if (null !== $pref) {
return $pref;
}
@@ -129,9 +130,11 @@ class Amount
if (null === $currency) {
$message = sprintf('Could not find a transaction currency with ID #%d', $currencyId);
Log::error($message);
throw new FireflyException($message);
}
$instance->setPreference($key, $currency);
return $currency;
}
@@ -139,8 +142,9 @@ class Amount
{
$instance = PreferencesSingleton::getInstance();
$key = sprintf('transaction_currency_%s', $code);
/** @var TransactionCurrency|null $pref */
$pref = $instance->getPreference($key);
/** @var null|TransactionCurrency $pref */
$pref = $instance->getPreference($key);
if (null !== $pref) {
return $pref;
}
@@ -148,9 +152,11 @@ class Amount
if (null === $currency) {
$message = sprintf('Could not find a transaction currency with code "%s"', $code);
Log::error($message);
throw new FireflyException($message);
}
$instance->setPreference($key, $currency);
return $currency;
}
@@ -168,8 +174,8 @@ class Amount
return $pref;
}
$key = sprintf('convert_to_primary_%d', $user->id);
$pref = $instance->getPreference($key);
$key = sprintf('convert_to_primary_%d', $user->id);
$pref = $instance->getPreference($key);
if (null === $pref) {
$res = true === Preferences::getForUser($user, 'convert_to_primary', false)->data && true === config('cer.enabled');
$instance->setPreference($key, $res);
@@ -195,7 +201,7 @@ class Amount
public function getPrimaryCurrencyByUserGroup(UserGroup $userGroup): TransactionCurrency
{
$cache = new CacheProperties();
$cache = new CacheProperties();
$cache->addProperty('getPrimaryCurrencyByGroup');
$cache->addProperty($userGroup->id);
if ($cache->has()) {
@@ -225,16 +231,16 @@ class Amount
*/
public function getAmountFromJournalObject(TransactionJournal $journal): string
{
$convertToPrimary = $this->convertToPrimary();
$currency = $this->getPrimaryCurrency();
$field = $convertToPrimary && $currency->id !== $journal->transaction_currency_id ? 'pc_amount' : 'amount';
$convertToPrimary = $this->convertToPrimary();
$currency = $this->getPrimaryCurrency();
$field = $convertToPrimary && $currency->id !== $journal->transaction_currency_id ? 'pc_amount' : 'amount';
/** @var null|Transaction $sourceTransaction */
$sourceTransaction = $journal->transactions()->where('amount', '<', 0)->first();
if (null === $sourceTransaction) {
return '0';
}
$amount = $sourceTransaction->{$field} ?? '0';
$amount = $sourceTransaction->{$field} ?? '0';
if ((int)$sourceTransaction->foreign_currency_id === $currency->id) {
// use foreign amount instead!
$amount = (string)$sourceTransaction->foreign_amount; // hard coded to be foreign amount.
@@ -282,20 +288,20 @@ class Amount
private function getLocaleInfo(): array
{
// get config from preference, not from translation:
$locale = Steam::getLocale();
$array = Steam::getLocaleArray($locale);
$locale = Steam::getLocale();
$array = Steam::getLocaleArray($locale);
setlocale(LC_MONETARY, $array);
$info = localeconv();
$info = localeconv();
// correct variables
$info['n_cs_precedes'] = $this->getLocaleField($info, 'n_cs_precedes');
$info['p_cs_precedes'] = $this->getLocaleField($info, 'p_cs_precedes');
$info['n_cs_precedes'] = $this->getLocaleField($info, 'n_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['p_sep_by_space'] = $this->getLocaleField($info, 'p_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');
$fmt = new NumberFormatter($locale, NumberFormatter::CURRENCY);
$fmt = new NumberFormatter($locale, NumberFormatter::CURRENCY);
$info['mon_decimal_point'] = $fmt->getSymbol(NumberFormatter::MONETARY_SEPARATOR_SYMBOL);
$info['mon_thousands_sep'] = $fmt->getSymbol(NumberFormatter::MONETARY_GROUPING_SEPARATOR_SYMBOL);
@@ -327,11 +333,11 @@ class Amount
// there are five possible positions for the "+" or "-" sign (if it is even used)
// pos_a and pos_e could be the ( and ) symbol.
$posA = ''; // before everything
$posB = ''; // before currency symbol
$posC = ''; // after currency symbol
$posD = ''; // before amount
$posE = ''; // after everything
$posA = ''; // before everything
$posB = ''; // before currency symbol
$posC = ''; // after currency symbol
$posD = ''; // before amount
$posE = ''; // after everything
// format would be (currency before amount)
// AB%sC_D%vE
@@ -373,9 +379,9 @@ class Amount
}
if ($csPrecedes) {
return $posA . $posB . '%s' . $posC . $space . $posD . '%v' . $posE;
return $posA.$posB.'%s'.$posC.$space.$posD.'%v'.$posE;
}
return $posA . $posD . '%v' . $space . $posB . '%s' . $posC . $posE;
return $posA.$posD.'%v'.$space.$posB.'%s'.$posC.$posE;
}
}

View File

@@ -42,9 +42,10 @@ class CurrencyCode implements BinderInterface
if (auth()->check()) {
try {
$currency = Amount::getTransactionCurrencyByCode(trim($value));
} catch(FireflyException) {
} catch (FireflyException) {
throw new NotFoundHttpException();
}
return $currency;
}

View File

@@ -72,14 +72,15 @@ class AccountBalanceCalculator
$balances = [];
$count = 0;
$query = Transaction::leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id')
->whereNull('transactions.deleted_at')
->whereNull('transaction_journals.deleted_at')
->whereNull('transactions.deleted_at')
->whereNull('transaction_journals.deleted_at')
// this order is the same as GroupCollector, but in the exact reverse.
->orderBy('transaction_journals.date', 'asc')
->orderBy('transaction_journals.order', 'desc')
->orderBy('transaction_journals.id', 'asc')
->orderBy('transaction_journals.description', 'asc')
->orderBy('transactions.amount', 'asc');
->orderBy('transaction_journals.date', 'asc')
->orderBy('transaction_journals.order', 'desc')
->orderBy('transaction_journals.id', 'asc')
->orderBy('transaction_journals.description', 'asc')
->orderBy('transactions.amount', 'asc')
;
if ($accounts->count() > 0) {
$query->whereIn('transactions.account_id', $accounts->pluck('id')->toArray());
}
@@ -88,7 +89,7 @@ class AccountBalanceCalculator
$query->where('transaction_journals.date', '>=', $notBefore);
}
$set = $query->get(['transactions.id', 'transactions.balance_dirty', 'transactions.transaction_currency_id', 'transaction_journals.date', 'transactions.account_id', 'transactions.amount']);
$set = $query->get(['transactions.id', 'transactions.balance_dirty', 'transactions.transaction_currency_id', 'transaction_journals.date', 'transactions.account_id', 'transactions.amount']);
Log::debug(sprintf('Counted %d transaction(s)', $set->count()));
// the balance value is an array.
@@ -101,8 +102,8 @@ class AccountBalanceCalculator
$balances[$entry->account_id][$entry->transaction_currency_id] ??= [$this->getLatestBalance($entry->account_id, $entry->transaction_currency_id, $notBefore), null];
// before and after are easy:
$before = $balances[$entry->account_id][$entry->transaction_currency_id][0];
$after = bcadd($before, (string)$entry->amount);
$before = $balances[$entry->account_id][$entry->transaction_currency_id][0];
$after = bcadd($before, (string)$entry->amount);
if (true === $entry->balance_dirty || $accounts->count() > 0) {
// update the transaction:
$entry->balance_before = $before;
@@ -128,17 +129,18 @@ class AccountBalanceCalculator
return '0';
}
Log::debug(sprintf('getLatestBalance: notBefore date is "%s", calculating', $notBefore->format('Y-m-d')));
$query = Transaction::leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id')
->whereNull('transactions.deleted_at')
->where('transaction_journals.transaction_currency_id', $currencyId)
->whereNull('transaction_journals.deleted_at')
$query = Transaction::leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id')
->whereNull('transactions.deleted_at')
->where('transaction_journals.transaction_currency_id', $currencyId)
->whereNull('transaction_journals.deleted_at')
// this order is the same as GroupCollector
->orderBy('transaction_journals.date', 'DESC')
->orderBy('transaction_journals.order', 'ASC')
->orderBy('transaction_journals.id', 'DESC')
->orderBy('transaction_journals.description', 'DESC')
->orderBy('transactions.amount', 'DESC')
->where('transactions.account_id', $accountId);
->orderBy('transaction_journals.date', 'DESC')
->orderBy('transaction_journals.order', 'ASC')
->orderBy('transaction_journals.id', 'DESC')
->orderBy('transaction_journals.description', 'DESC')
->orderBy('transactions.amount', 'DESC')
->where('transactions.account_id', $accountId)
;
$notBefore->startOfDay();
$query->where('transaction_journals.date', '<', $notBefore);
@@ -152,7 +154,7 @@ class AccountBalanceCalculator
private function storeAccountBalances(array $balances): void
{
/**
* @var int $accountId
* @var int $accountId
* @var array $currencies
*/
foreach ($balances as $accountId => $currencies) {
@@ -165,7 +167,7 @@ class AccountBalanceCalculator
}
/**
* @var int $currencyId
* @var int $currencyId
* @var array $balance
*/
foreach ($currencies as $currencyId => $balance) {
@@ -198,9 +200,9 @@ class AccountBalanceCalculator
public static function recalculateForJournal(TransactionJournal $transactionJournal): void
{
Log::debug(__METHOD__);
$object = new self();
$object = new self();
$set = [];
$set = [];
foreach ($transactionJournal->transactions as $transaction) {
$set[$transaction->account_id] = $transaction->account;
}

View File

@@ -524,6 +524,7 @@ class Steam
$singleton = PreferencesSingleton::getInstance();
foreach ($others as $key => $amount) {
$preference = $singleton->getPreference($key);
try {
$currency = $preference ?? Amount::getTransactionCurrencyByCode($key);
} catch (FireflyException) {

View File

@@ -164,7 +164,7 @@ class AmountFormat extends AbstractExtension
try {
$currency = Amount::getTransactionCurrencyByCode($code);
} catch(FireflyException) {
} catch (FireflyException) {
Log::error(sprintf('Could not find currency with code "%s". Fallback to primary currency.', $code));
$currency = Amount::getPrimaryCurrency();
Log::error(sprintf('Fallback currency is "%s".', $currency->code));

View File

@@ -25,7 +25,6 @@ namespace FireflyIII\Support\Twig;
use Carbon\Carbon;
use FireflyIII\Models\Account;
use FireflyIII\Models\TransactionCurrency;
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use FireflyIII\Repositories\User\UserRepositoryInterface;
use FireflyIII\Support\Facades\Amount;