PHPStorm can order methods by alphabet, who knew.

This commit is contained in:
James Cole
2024-02-22 20:11:09 +01:00
parent f9d4a43e05
commit 68c9c4ec3c
221 changed files with 5840 additions and 5843 deletions

View File

@@ -58,11 +58,11 @@ class AccountBalanceGrouped
// income and expense array prepped:
$income = [
'label' => 'earned',
'currency_id' => (string) $currency['currency_id'],
'currency_id' => (string)$currency['currency_id'],
'currency_symbol' => $currency['currency_symbol'],
'currency_code' => $currency['currency_code'],
'currency_decimal_places' => $currency['currency_decimal_places'],
'native_currency_id' => (string) $currency['native_currency_id'],
'native_currency_id' => (string)$currency['native_currency_id'],
'native_currency_symbol' => $currency['native_currency_symbol'],
'native_currency_code' => $currency['native_currency_code'],
'native_currency_decimal_places' => $currency['native_currency_decimal_places'],
@@ -74,11 +74,11 @@ class AccountBalanceGrouped
];
$expense = [
'label' => 'spent',
'currency_id' => (string) $currency['currency_id'],
'currency_id' => (string)$currency['currency_id'],
'currency_symbol' => $currency['currency_symbol'],
'currency_code' => $currency['currency_code'],
'currency_decimal_places' => $currency['currency_decimal_places'],
'native_currency_id' => (string) $currency['native_currency_id'],
'native_currency_id' => (string)$currency['native_currency_id'],
'native_currency_symbol' => $currency['native_currency_symbol'],
'native_currency_code' => $currency['native_currency_code'],
'native_currency_decimal_places' => $currency['native_currency_decimal_places'],
@@ -126,19 +126,19 @@ class AccountBalanceGrouped
foreach ($this->journals as $journal) {
// format the date according to the period
$period = $journal['date']->format($this->carbonFormat);
$currencyId = (int) $journal['currency_id'];
$currencyId = (int)$journal['currency_id'];
$currency = $this->currencies[$currencyId] ?? TransactionCurrency::find($currencyId);
$this->currencies[$currencyId] = $currency; // may just re-assign itself, don't mind.
// set the array with monetary info, if it does not exist.
$this->data[$currencyId] ??= [
'currency_id' => (string) $currencyId,
'currency_id' => (string)$currencyId,
'currency_symbol' => $journal['currency_symbol'],
'currency_code' => $journal['currency_code'],
'currency_name' => $journal['currency_name'],
'currency_decimal_places' => $journal['currency_decimal_places'],
// native currency info (could be the same)
'native_currency_id' => (string) $this->default->id,
'native_currency_id' => (string)$this->default->id,
'native_currency_code' => $this->default->code,
'native_currency_symbol' => $this->default->symbol,
'native_currency_decimal_places' => $this->default->decimal_places,
@@ -183,7 +183,7 @@ class AccountBalanceGrouped
$amountConverted = bcmul($amount, $rate);
// perhaps transaction already has the foreign amount in the native currency.
if ((int) $journal['foreign_currency_id'] === $this->default->id) {
if ((int)$journal['foreign_currency_id'] === $this->default->id) {
$amountConverted = $journal['foreign_amount'] ?? '0';
$amountConverted = 'earned' === $key ? app('steam')->positive($amountConverted) : app('steam')->negative($amountConverted);
}
@@ -209,12 +209,12 @@ class AccountBalanceGrouped
$defaultCurrencyId = $default->id;
$this->currencies = [$default->id => $default]; // currency cache
$this->data[$defaultCurrencyId] = [
'currency_id' => (string) $defaultCurrencyId,
'currency_id' => (string)$defaultCurrencyId,
'currency_symbol' => $default->symbol,
'currency_code' => $default->code,
'currency_name' => $default->name,
'currency_decimal_places' => $default->decimal_places,
'native_currency_id' => (string) $defaultCurrencyId,
'native_currency_id' => (string)$defaultCurrencyId,
'native_currency_symbol' => $default->symbol,
'native_currency_code' => $default->code,
'native_currency_name' => $default->name,

View File

@@ -76,6 +76,27 @@ trait ConvertsExchangeRates
return $set;
}
/**
* @deprecated
*/
private function getPreference(): void
{
$this->enabled = config('cer.currency_conversion');
}
/**
* @deprecated
*/
private function getCurrency(int $currencyId): TransactionCurrency
{
$result = TransactionCurrency::find($currencyId);
if (null === $result) {
return app('amount')->getDefaultCurrency();
}
return $result;
}
/**
* For a sum of entries, get the exchange rate to the native currency of
* the user.
@@ -133,27 +154,6 @@ trait ConvertsExchangeRates
return $return;
}
/**
* @deprecated
*/
private function getPreference(): void
{
$this->enabled = config('cer.currency_conversion');
}
/**
* @deprecated
*/
private function getCurrency(int $currencyId): TransactionCurrency
{
$result = TransactionCurrency::find($currencyId);
if (null === $result) {
return app('amount')->getDefaultCurrency();
}
return $result;
}
/**
* @deprecated
*/

View File

@@ -37,11 +37,11 @@ use Illuminate\Support\Facades\Log;
class ExchangeRateConverter
{
// use ConvertsExchangeRates;
private int $queryCount = 0;
private array $prepared = [];
private array $fallback = [];
private bool $isPrepared = false;
private bool $noPreparedRates = false;
private array $prepared = [];
private int $queryCount = 0;
/**
* @throws FireflyException
@@ -54,61 +54,6 @@ class ExchangeRateConverter
return bcmul($amount, $rate);
}
/**
* @throws FireflyException
*/
public function prepare(TransactionCurrency $from, TransactionCurrency $to, Carbon $start, Carbon $end): void
{
Log::debug('prepare()');
$start->startOfDay();
$end->endOfDay();
Log::debug(sprintf('Preparing for %s to %s between %s and %s', $from->code, $to->code, $start->format('Y-m-d'), $end->format('Y-m-d')));
$set = auth()->user()
->currencyExchangeRates()
->where('from_currency_id', $from->id)
->where('to_currency_id', $to->id)
->where('date', '<=', $end->format('Y-m-d'))
->where('date', '>=', $start->format('Y-m-d'))
->orderBy('date', 'DESC')->get()
;
++$this->queryCount;
if (0 === $set->count()) {
Log::debug('No prepared rates found in this period, use the fallback');
$this->fallback($from, $to, $start);
$this->noPreparedRates = true;
$this->isPrepared = true;
Log::debug('prepare DONE()');
return;
}
$this->isPrepared = true;
// so there is a fallback just in case. Now loop the set of rates we DO have.
$temp = [];
$count = 0;
foreach ($set as $rate) {
$date = $rate->date->format('Y-m-d');
$temp[$date] ??= [
$from->id => [
$to->id => $rate->rate,
],
];
++$count;
}
Log::debug(sprintf('Found %d rates in this period.', $count));
$currentStart = clone $start;
while ($currentStart->lte($end)) {
$currentDate = $currentStart->format('Y-m-d');
$this->prepared[$currentDate] ??= [];
$fallback = $temp[$currentDate][$from->id][$to->id] ?? $this->fallback[$from->id][$to->id] ?? '0';
if (0 === count($this->prepared[$currentDate]) && 0 !== bccomp('0', $fallback)) {
// fill from temp or fallback or from temp (see before)
$this->prepared[$currentDate][$from->id][$to->id] = $fallback;
}
$currentStart->addDay();
}
}
/**
* @throws FireflyException
*/
@@ -120,11 +65,6 @@ class ExchangeRateConverter
return '0' === $rate ? '1' : $rate;
}
public function summarize(): void
{
Log::debug(sprintf('ExchangeRateConverter ran %d queries.', $this->queryCount));
}
/**
* @throws FireflyException
*/
@@ -202,7 +142,7 @@ class ExchangeRateConverter
->first()
;
++$this->queryCount;
$rate = (string) $result?->rate;
$rate = (string)$result?->rate;
if ('' === $rate) {
app('log')->debug(sprintf('Found no rate for #%d->#%d (%s) in the DB.', $from, $to, $date));
@@ -258,7 +198,7 @@ class ExchangeRateConverter
// grab backup values from config file:
$backup = config(sprintf('cer.rates.%s', $currency->code));
if (null !== $backup) {
return bcdiv('1', (string) $backup);
return bcdiv('1', (string)$backup);
// app('log')->debug(sprintf('Backup rate for %s to EUR is %s.', $currency->code, $backup));
// return $backup;
}
@@ -276,7 +216,7 @@ class ExchangeRateConverter
$cache = new CacheProperties();
$cache->addProperty('cer-euro-id');
if ($cache->has()) {
return (int) $cache->get();
return (int)$cache->get();
}
$euro = TransactionCurrency::whereCode('EUR')->first();
++$this->queryCount;
@@ -288,6 +228,61 @@ class ExchangeRateConverter
return $euro->id;
}
/**
* @throws FireflyException
*/
public function prepare(TransactionCurrency $from, TransactionCurrency $to, Carbon $start, Carbon $end): void
{
Log::debug('prepare()');
$start->startOfDay();
$end->endOfDay();
Log::debug(sprintf('Preparing for %s to %s between %s and %s', $from->code, $to->code, $start->format('Y-m-d'), $end->format('Y-m-d')));
$set = auth()->user()
->currencyExchangeRates()
->where('from_currency_id', $from->id)
->where('to_currency_id', $to->id)
->where('date', '<=', $end->format('Y-m-d'))
->where('date', '>=', $start->format('Y-m-d'))
->orderBy('date', 'DESC')->get()
;
++$this->queryCount;
if (0 === $set->count()) {
Log::debug('No prepared rates found in this period, use the fallback');
$this->fallback($from, $to, $start);
$this->noPreparedRates = true;
$this->isPrepared = true;
Log::debug('prepare DONE()');
return;
}
$this->isPrepared = true;
// so there is a fallback just in case. Now loop the set of rates we DO have.
$temp = [];
$count = 0;
foreach ($set as $rate) {
$date = $rate->date->format('Y-m-d');
$temp[$date] ??= [
$from->id => [
$to->id => $rate->rate,
],
];
++$count;
}
Log::debug(sprintf('Found %d rates in this period.', $count));
$currentStart = clone $start;
while ($currentStart->lte($end)) {
$currentDate = $currentStart->format('Y-m-d');
$this->prepared[$currentDate] ??= [];
$fallback = $temp[$currentDate][$from->id][$to->id] ?? $this->fallback[$from->id][$to->id] ?? '0';
if (0 === count($this->prepared[$currentDate]) && 0 !== bccomp('0', $fallback)) {
// fill from temp or fallback or from temp (see before)
$this->prepared[$currentDate][$from->id][$to->id] = $fallback;
}
$currentStart->addDay();
}
}
/**
* If there are no exchange rate in the "prepare" array, future searches for any exchange rate
* will result in nothing: otherwise the preparation had been unnecessary. So, to fix this Firefly III
@@ -307,4 +302,9 @@ class ExchangeRateConverter
Log::debug(sprintf('Fallback rate %s > %s = %s', $from->code, $to->code, $fallback));
Log::debug(sprintf('Fallback rate %s > %s = %s', $to->code, $from->code, bcdiv('1', $fallback)));
}
public function summarize(): void
{
Log::debug(sprintf('ExchangeRateConverter ran %d queries.', $this->queryCount));
}
}

View File

@@ -29,12 +29,12 @@ use Illuminate\Support\Facades\Log;
class SummaryBalanceGrouped
{
private const string SUM = 'sum';
private TransactionCurrency $default;
private array $amounts = [];
private array $keys;
private array $currencies;
private const string SUM = 'sum';
private array $amounts = [];
private array $currencies;
private CurrencyRepositoryInterface $currencyRepository;
private TransactionCurrency $default;
private array $keys;
public function __construct()
{
@@ -43,42 +43,6 @@ class SummaryBalanceGrouped
$this->currencyRepository = app(CurrencyRepositoryInterface::class);
}
public function groupTransactions(string $key, array $journals): void
{
Log::debug(sprintf('Created new ExchangeRateConverter in %s', __METHOD__));
Log::debug(sprintf('Now in groupTransactions with key "%s" and %d journal(s)', $key, count($journals)));
$converter = new ExchangeRateConverter();
$this->keys[] = $key;
$multiplier = 'income' === $key ? '-1' : '1';
/** @var array $journal */
foreach ($journals as $journal) {
// transaction info:
$currencyId = (int)$journal['currency_id'];
$amount = bcmul($journal['amount'], $multiplier);
$currency = $this->currencies[$currencyId] ?? TransactionCurrency::find($currencyId);
$this->currencies[$currencyId] = $currency;
$nativeAmount = $converter->convert($currency, $this->default, $journal['date'], $amount);
if ((int)$journal['foreign_currency_id'] === $this->default->id) {
// use foreign amount instead
$nativeAmount = $journal['foreign_amount'];
}
// prep the arrays
$this->amounts[$key] ??= [];
$this->amounts[$key][$currencyId] ??= '0';
$this->amounts[$key]['native'] ??= '0';
$this->amounts[self::SUM][$currencyId] ??= '0';
$this->amounts[self::SUM]['native'] ??= '0';
// add values:
$this->amounts[$key][$currencyId] = bcadd($this->amounts[$key][$currencyId], $amount);
$this->amounts[self::SUM][$currencyId] = bcadd($this->amounts[self::SUM][$currencyId], $amount);
$this->amounts[$key]['native'] = bcadd($this->amounts[$key]['native'], $nativeAmount);
$this->amounts[self::SUM]['native'] = bcadd($this->amounts[self::SUM]['native'], $nativeAmount);
}
$converter->summarize();
}
public function groupData(): array
{
Log::debug('Now going to group data.');
@@ -132,6 +96,42 @@ class SummaryBalanceGrouped
return $return;
}
public function groupTransactions(string $key, array $journals): void
{
Log::debug(sprintf('Created new ExchangeRateConverter in %s', __METHOD__));
Log::debug(sprintf('Now in groupTransactions with key "%s" and %d journal(s)', $key, count($journals)));
$converter = new ExchangeRateConverter();
$this->keys[] = $key;
$multiplier = 'income' === $key ? '-1' : '1';
/** @var array $journal */
foreach ($journals as $journal) {
// transaction info:
$currencyId = (int)$journal['currency_id'];
$amount = bcmul($journal['amount'], $multiplier);
$currency = $this->currencies[$currencyId] ?? TransactionCurrency::find($currencyId);
$this->currencies[$currencyId] = $currency;
$nativeAmount = $converter->convert($currency, $this->default, $journal['date'], $amount);
if ((int)$journal['foreign_currency_id'] === $this->default->id) {
// use foreign amount instead
$nativeAmount = $journal['foreign_amount'];
}
// prep the arrays
$this->amounts[$key] ??= [];
$this->amounts[$key][$currencyId] ??= '0';
$this->amounts[$key]['native'] ??= '0';
$this->amounts[self::SUM][$currencyId] ??= '0';
$this->amounts[self::SUM]['native'] ??= '0';
// add values:
$this->amounts[$key][$currencyId] = bcadd($this->amounts[$key][$currencyId], $amount);
$this->amounts[self::SUM][$currencyId] = bcadd($this->amounts[self::SUM][$currencyId], $amount);
$this->amounts[$key]['native'] = bcadd($this->amounts[$key]['native'], $nativeAmount);
$this->amounts[self::SUM]['native'] = bcadd($this->amounts[self::SUM]['native'], $nativeAmount);
}
$converter->summarize();
}
public function setDefault(TransactionCurrency $default): void
{
$this->default = $default;

View File

@@ -84,9 +84,9 @@ trait ModelInformation
/** @var AccountType $mortgage */
$mortgage = $repository->getAccountTypeByType(AccountType::MORTGAGE);
$liabilityTypes = [
$debt->id => (string) trans(sprintf('firefly.account_type_%s', AccountType::DEBT)),
$loan->id => (string) trans(sprintf('firefly.account_type_%s', AccountType::LOAN)),
$mortgage->id => (string) trans(sprintf('firefly.account_type_%s', AccountType::MORTGAGE)),
$debt->id => (string)trans(sprintf('firefly.account_type_%s', AccountType::DEBT)),
$loan->id => (string)trans(sprintf('firefly.account_type_%s', AccountType::LOAN)),
$mortgage->id => (string)trans(sprintf('firefly.account_type_%s', AccountType::MORTGAGE)),
];
asort($liabilityTypes);
@@ -97,7 +97,7 @@ trait ModelInformation
{
$roles = [];
foreach (config('firefly.accountRoles') as $role) {
$roles[$role] = (string) trans(sprintf('firefly.account_role_%s', $role));
$roles[$role] = (string)trans(sprintf('firefly.account_role_%s', $role));
}
return $roles;
@@ -115,7 +115,7 @@ trait ModelInformation
$triggers = [];
foreach ($operators as $key => $operator) {
if ('user_action' !== $key && false === $operator['alias']) {
$triggers[$key] = (string) trans(sprintf('firefly.rule_trigger_%s_choice', $key));
$triggers[$key] = (string)trans(sprintf('firefly.rule_trigger_%s_choice', $key));
}
}
asort($triggers);
@@ -166,7 +166,7 @@ trait ModelInformation
$triggers = [];
foreach ($operators as $key => $operator) {
if ('user_action' !== $key && false === $operator['alias']) {
$triggers[$key] = (string) trans(sprintf('firefly.rule_trigger_%s_choice', $key));
$triggers[$key] = (string)trans(sprintf('firefly.rule_trigger_%s_choice', $key));
}
}
asort($triggers);

View File

@@ -139,6 +139,99 @@ trait PeriodOverview
return $entries;
}
/**
* Filter a list of journals by a set of dates, and then group them by currency.
*/
private function filterJournalsByDate(array $array, Carbon $start, Carbon $end): array
{
$result = [];
/** @var array $journal */
foreach ($array as $journal) {
if ($journal['date'] <= $end && $journal['date'] >= $start) {
$result[] = $journal;
}
}
return $result;
}
/**
* Return only transactions where $account is the source.
*/
private function filterTransferredAway(Account $account, array $journals): array
{
$return = [];
/** @var array $journal */
foreach ($journals as $journal) {
if ($account->id === (int)$journal['source_account_id']) {
$return[] = $journal;
}
}
return $return;
}
/**
* Return only transactions where $account is the source.
*/
private function filterTransferredIn(Account $account, array $journals): array
{
$return = [];
/** @var array $journal */
foreach ($journals as $journal) {
if ($account->id === (int)$journal['destination_account_id']) {
$return[] = $journal;
}
}
return $return;
}
private function groupByCurrency(array $journals): array
{
$return = [];
/** @var array $journal */
foreach ($journals as $journal) {
$currencyId = (int)$journal['currency_id'];
$foreignCurrencyId = $journal['foreign_currency_id'];
if (!array_key_exists($currencyId, $return)) {
$return[$currencyId] = [
'amount' => '0',
'count' => 0,
'currency_id' => $currencyId,
'currency_name' => $journal['currency_name'],
'currency_code' => $journal['currency_code'],
'currency_symbol' => $journal['currency_symbol'],
'currency_decimal_places' => $journal['currency_decimal_places'],
];
}
$return[$currencyId]['amount'] = bcadd($return[$currencyId]['amount'], $journal['amount'] ?? '0');
++$return[$currencyId]['count'];
if (null !== $foreignCurrencyId && null !== $journal['foreign_amount']) {
if (!array_key_exists($foreignCurrencyId, $return)) {
$return[$foreignCurrencyId] = [
'amount' => '0',
'count' => 0,
'currency_id' => (int)$foreignCurrencyId,
'currency_name' => $journal['foreign_currency_name'],
'currency_code' => $journal['foreign_currency_code'],
'currency_symbol' => $journal['foreign_currency_symbol'],
'currency_decimal_places' => $journal['foreign_currency_decimal_places'],
];
}
++$return[$foreignCurrencyId]['count'];
$return[$foreignCurrencyId]['amount'] = bcadd($return[$foreignCurrencyId]['amount'], $journal['foreign_amount']);
}
}
return $return;
}
/**
* Overview for single category. Has been refactored recently.
*
@@ -406,6 +499,27 @@ trait PeriodOverview
return $entries;
}
private function filterJournalsByTag(array $set, Tag $tag): array
{
$return = [];
foreach ($set as $entry) {
$found = false;
/** @var array $localTag */
foreach ($entry['tags'] as $localTag) {
if ($localTag['id'] === $tag->id) {
$found = true;
}
}
if (false === $found) {
continue;
}
$return[] = $entry;
}
return $return;
}
/**
* @throws FireflyException
*/
@@ -452,129 +566,15 @@ trait PeriodOverview
}
$entries[]
= [
'title' => $title,
'route' => route('transactions.index', [$transactionType, $currentDate['start']->format('Y-m-d'), $currentDate['end']->format('Y-m-d')]),
'total_transactions' => count($spent) + count($earned) + count($transferred),
'spent' => $this->groupByCurrency($spent),
'earned' => $this->groupByCurrency($earned),
'transferred' => $this->groupByCurrency($transferred),
];
'title' => $title,
'route' => route('transactions.index', [$transactionType, $currentDate['start']->format('Y-m-d'), $currentDate['end']->format('Y-m-d')]),
'total_transactions' => count($spent) + count($earned) + count($transferred),
'spent' => $this->groupByCurrency($spent),
'earned' => $this->groupByCurrency($earned),
'transferred' => $this->groupByCurrency($transferred),
];
}
return $entries;
}
/**
* Filter a list of journals by a set of dates, and then group them by currency.
*/
private function filterJournalsByDate(array $array, Carbon $start, Carbon $end): array
{
$result = [];
/** @var array $journal */
foreach ($array as $journal) {
if ($journal['date'] <= $end && $journal['date'] >= $start) {
$result[] = $journal;
}
}
return $result;
}
/**
* Return only transactions where $account is the source.
*/
private function filterTransferredAway(Account $account, array $journals): array
{
$return = [];
/** @var array $journal */
foreach ($journals as $journal) {
if ($account->id === (int) $journal['source_account_id']) {
$return[] = $journal;
}
}
return $return;
}
/**
* Return only transactions where $account is the source.
*/
private function filterTransferredIn(Account $account, array $journals): array
{
$return = [];
/** @var array $journal */
foreach ($journals as $journal) {
if ($account->id === (int) $journal['destination_account_id']) {
$return[] = $journal;
}
}
return $return;
}
private function groupByCurrency(array $journals): array
{
$return = [];
/** @var array $journal */
foreach ($journals as $journal) {
$currencyId = (int) $journal['currency_id'];
$foreignCurrencyId = $journal['foreign_currency_id'];
if (!array_key_exists($currencyId, $return)) {
$return[$currencyId] = [
'amount' => '0',
'count' => 0,
'currency_id' => $currencyId,
'currency_name' => $journal['currency_name'],
'currency_code' => $journal['currency_code'],
'currency_symbol' => $journal['currency_symbol'],
'currency_decimal_places' => $journal['currency_decimal_places'],
];
}
$return[$currencyId]['amount'] = bcadd($return[$currencyId]['amount'], $journal['amount'] ?? '0');
++$return[$currencyId]['count'];
if (null !== $foreignCurrencyId && null !== $journal['foreign_amount']) {
if (!array_key_exists($foreignCurrencyId, $return)) {
$return[$foreignCurrencyId] = [
'amount' => '0',
'count' => 0,
'currency_id' => (int) $foreignCurrencyId,
'currency_name' => $journal['foreign_currency_name'],
'currency_code' => $journal['foreign_currency_code'],
'currency_symbol' => $journal['foreign_currency_symbol'],
'currency_decimal_places' => $journal['foreign_currency_decimal_places'],
];
}
++$return[$foreignCurrencyId]['count'];
$return[$foreignCurrencyId]['amount'] = bcadd($return[$foreignCurrencyId]['amount'], $journal['foreign_amount']);
}
}
return $return;
}
private function filterJournalsByTag(array $set, Tag $tag): array
{
$return = [];
foreach ($set as $entry) {
$found = false;
/** @var array $localTag */
foreach ($entry['tags'] as $localTag) {
if ($localTag['id'] === $tag->id) {
$found = true;
}
}
if (false === $found) {
continue;
}
$return[] = $entry;
}
return $return;
}
}