Expand currency view in accounts.

This commit is contained in:
James Cole
2024-12-25 07:10:02 +01:00
parent 98b579c042
commit e73fe06f7e
5 changed files with 105 additions and 37 deletions

View File

@@ -27,6 +27,7 @@ use Carbon\Carbon;
use FireflyIII\Exceptions\FireflyException; use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Http\Controllers\Controller; use FireflyIII\Http\Controllers\Controller;
use FireflyIII\Models\Account; use FireflyIII\Models\Account;
use FireflyIII\Models\TransactionCurrency;
use FireflyIII\Repositories\Account\AccountRepositoryInterface; use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use FireflyIII\Support\Http\Controllers\BasicDataSupport; use FireflyIII\Support\Http\Controllers\BasicDataSupport;
use Illuminate\Contracts\View\Factory; use Illuminate\Contracts\View\Factory;
@@ -70,22 +71,22 @@ class IndexController extends Controller
* */ * */
public function inactive(Request $request, string $objectType) public function inactive(Request $request, string $objectType)
{ {
$inactivePage = true; $inactivePage = true;
$subTitle = (string) trans(sprintf('firefly.%s_accounts_inactive', $objectType)); $subTitle = (string) trans(sprintf('firefly.%s_accounts_inactive', $objectType));
$subTitleIcon = config(sprintf('firefly.subIconsByIdentifier.%s', $objectType)); $subTitleIcon = config(sprintf('firefly.subIconsByIdentifier.%s', $objectType));
$types = config(sprintf('firefly.accountTypesByIdentifier.%s', $objectType)); $types = config(sprintf('firefly.accountTypesByIdentifier.%s', $objectType));
$collection = $this->repository->getInactiveAccountsByType($types); $collection = $this->repository->getInactiveAccountsByType($types);
$total = $collection->count(); $total = $collection->count();
$page = 0 === (int) $request->get('page') ? 1 : (int) $request->get('page'); $page = 0 === (int) $request->get('page') ? 1 : (int) $request->get('page');
$pageSize = (int) app('preferences')->get('listPageSize', 50)->data; $pageSize = (int) app('preferences')->get('listPageSize', 50)->data;
$accounts = $collection->slice(($page - 1) * $pageSize, $pageSize); $accounts = $collection->slice(($page - 1) * $pageSize, $pageSize);
unset($collection); unset($collection);
/** @var Carbon $start */ /** @var Carbon $start */
$start = clone session('start', today(config('app.timezone'))->startOfMonth()); $start = clone session('start', today(config('app.timezone'))->startOfMonth());
/** @var Carbon $end */ /** @var Carbon $end */
$end = clone session('end', today(config('app.timezone'))->endOfMonth()); $end = clone session('end', today(config('app.timezone'))->endOfMonth());
$start->subDay(); $start->subDay();
$ids = $accounts->pluck('id')->toArray(); $ids = $accounts->pluck('id')->toArray();
@@ -94,13 +95,13 @@ class IndexController extends Controller
$activities = app('steam')->getLastActivities($ids); $activities = app('steam')->getLastActivities($ids);
$accounts->each( $accounts->each(
function (Account $account) use ($activities, $startBalances, $endBalances): void { function (Account $account) use ($activities, $startBalances, $endBalances): void {
$currency = $this->repository->getAccountCurrency($account);
$account->lastActivityDate = $this->isInArrayDate($activities, $account->id); $account->lastActivityDate = $this->isInArrayDate($activities, $account->id);
$account->startBalance = $this->isInArray($startBalances, $account->id); $account->startBalances = $this->getBalance($account, $currency, $startBalances);
$account->endBalance = $this->isInArray($endBalances, $account->id); $account->endBalances = $this->getBalance($account, $currency, $endBalances);
$account->difference = bcsub($account->endBalance, $account->startBalance); $account->differences = $this->subtract($account->startBalances, $account->endBalances);
$account->interest = app('steam')->bcround($this->repository->getMetaValue($account, 'interest'), 4); $account->interest = app('steam')->bcround($this->repository->getMetaValue($account, 'interest'), 4);
$account->interestPeriod = (string) trans(sprintf('firefly.interest_calc_%s', $this->repository->getMetaValue($account, 'interest_period'))); $account->interestPeriod = (string) trans(sprintf('firefly.interest_calc_%s', $this->repository->getMetaValue($account, 'interest_period')));
$account->accountTypeString = (string) trans(sprintf('firefly.account_type_%s', $account->accountType->type)); $account->accountTypeString = (string) trans(sprintf('firefly.account_type_%s', $account->accountType->type));
@@ -110,7 +111,7 @@ class IndexController extends Controller
); );
// make paginator: // make paginator:
$accounts = new LengthAwarePaginator($accounts, $total, $pageSize, $page); $accounts = new LengthAwarePaginator($accounts, $total, $pageSize, $page);
$accounts->setPath(route('accounts.inactive.index', [$objectType])); $accounts->setPath(route('accounts.inactive.index', [$objectType]));
return view('accounts.index', compact('objectType', 'inactivePage', 'subTitleIcon', 'subTitle', 'page', 'accounts')); return view('accounts.index', compact('objectType', 'inactivePage', 'subTitleIcon', 'subTitle', 'page', 'accounts'));
@@ -126,9 +127,9 @@ class IndexController extends Controller
public function index(Request $request, string $objectType) public function index(Request $request, string $objectType)
{ {
app('log')->debug(sprintf('Now at %s', __METHOD__)); app('log')->debug(sprintf('Now at %s', __METHOD__));
$subTitle = (string) trans(sprintf('firefly.%s_accounts', $objectType)); $subTitle = (string) trans(sprintf('firefly.%s_accounts', $objectType));
$subTitleIcon = config(sprintf('firefly.subIconsByIdentifier.%s', $objectType)); $subTitleIcon = config(sprintf('firefly.subIconsByIdentifier.%s', $objectType));
$types = config(sprintf('firefly.accountTypesByIdentifier.%s', $objectType)); $types = config(sprintf('firefly.accountTypesByIdentifier.%s', $objectType));
$this->repository->resetAccountOrder(); $this->repository->resetAccountOrder();
@@ -144,10 +145,10 @@ class IndexController extends Controller
unset($collection); unset($collection);
/** @var Carbon $start */ /** @var Carbon $start */
$start = clone session('start', today(config('app.timezone'))->startOfMonth()); $start = clone session('start', today(config('app.timezone'))->startOfMonth());
/** @var Carbon $end */ /** @var Carbon $end */
$end = clone session('end', today(config('app.timezone'))->endOfMonth()); $end = clone session('end', today(config('app.timezone'))->endOfMonth());
$start->subDay(); $start->subDay();
$ids = $accounts->pluck('id')->toArray(); $ids = $accounts->pluck('id')->toArray();
@@ -155,16 +156,17 @@ class IndexController extends Controller
$endBalances = app('steam')->finalAccountsBalance($accounts, $end); $endBalances = app('steam')->finalAccountsBalance($accounts, $end);
$activities = app('steam')->getLastActivities($ids); $activities = app('steam')->getLastActivities($ids);
$accounts->each( $accounts->each(
function (Account $account) use ($activities, $startBalances, $endBalances): void { function (Account $account) use ($activities, $startBalances, $endBalances): void {
$interest = (string) $this->repository->getMetaValue($account, 'interest'); $interest = (string) $this->repository->getMetaValue($account, 'interest');
$interest = '' === $interest ? '0' : $interest; $interest = '' === $interest ? '0' : $interest;
$currency = $this->repository->getAccountCurrency($account);
// See reference nr. 68 $account->startBalances = $this->getBalance($account, $currency, $startBalances);
$account->endBalances = $this->getBalance($account, $currency, $endBalances);
$account->differences = $this->subtract($account->startBalances, $account->endBalances);
$account->lastActivityDate = $this->isInArrayDate($activities, $account->id); $account->lastActivityDate = $this->isInArrayDate($activities, $account->id);
$account->startBalance = $this->isInArray($startBalances, $account->id);
$account->endBalance = $this->isInArray($endBalances, $account->id);
$account->difference = bcsub($account->endBalance, $account->startBalance);
$account->interest = app('steam')->bcround($interest, 4); $account->interest = app('steam')->bcround($interest, 4);
$account->interestPeriod = (string) trans( $account->interestPeriod = (string) trans(
sprintf('firefly.interest_calc_%s', $this->repository->getMetaValue($account, 'interest_period')) sprintf('firefly.interest_calc_%s', $this->repository->getMetaValue($account, 'interest_period'))
@@ -173,14 +175,17 @@ class IndexController extends Controller
$account->location = $this->repository->getLocation($account); $account->location = $this->repository->getLocation($account);
$account->liability_direction = $this->repository->getMetaValue($account, 'liability_direction'); $account->liability_direction = $this->repository->getMetaValue($account, 'liability_direction');
$account->current_debt = $this->repository->getMetaValue($account, 'current_debt') ?? '-'; $account->current_debt = $this->repository->getMetaValue($account, 'current_debt') ?? '-';
$account->currency = $currency;
$account->iban = implode(' ', str_split((string) $account->iban, 4)); $account->iban = implode(' ', str_split((string) $account->iban, 4));
} }
); );
// make paginator: // make paginator:
app('log')->debug(sprintf('Count of accounts before LAP: %d', $accounts->count())); app('log')->debug(sprintf('Count of accounts before LAP: %d', $accounts->count()));
/** @var LengthAwarePaginator $accounts */ /** @var LengthAwarePaginator $accounts */
$accounts = new LengthAwarePaginator($accounts, $total, $pageSize, $page); $accounts = new LengthAwarePaginator($accounts, $total, $pageSize, $page);
$accounts->setPath(route('accounts.index', [$objectType])); $accounts->setPath(route('accounts.index', [$objectType]));
app('log')->debug(sprintf('Count of accounts after LAP (1): %d', $accounts->count())); app('log')->debug(sprintf('Count of accounts after LAP (1): %d', $accounts->count()));
@@ -188,4 +193,30 @@ class IndexController extends Controller
return view('accounts.index', compact('objectType', 'inactiveCount', 'subTitleIcon', 'subTitle', 'page', 'accounts')); return view('accounts.index', compact('objectType', 'inactiveCount', 'subTitleIcon', 'subTitle', 'page', 'accounts'));
} }
private function getBalance(Account $account, ?TransactionCurrency $currency = null, array $balances): array
{
if (!array_key_exists($account->id, $balances)) {
return [];
}
$set = $balances[$account->id];
if ($this->convertToNative && $this->defaultCurrency->id === $currency?->id) {
unset($set['native_balance'], $set[$this->defaultCurrency->code]);
}
if ($this->convertToNative && null !== $currency && $this->defaultCurrency->id !== $currency->id) {
unset($set['balance']);
}
return $set;
}
private function subtract(array $startBalances, array $endBalances)
{
$result = [];
foreach ($endBalances as $key => $value) {
$result[$key] = bcsub($value, $startBalances[$key] ?? '0');
}
return $result;
}
} }

View File

@@ -23,6 +23,7 @@ declare(strict_types=1);
namespace FireflyIII\Http\Controllers; namespace FireflyIII\Http\Controllers;
use FireflyIII\Models\TransactionCurrency;
use FireflyIII\Support\Facades\Steam; use FireflyIII\Support\Facades\Steam;
use FireflyIII\Support\Http\Controllers\RequestInformation; use FireflyIII\Support\Http\Controllers\RequestInformation;
use FireflyIII\Support\Http\Controllers\UserNavigation; use FireflyIII\Support\Http\Controllers\UserNavigation;
@@ -53,6 +54,7 @@ abstract class Controller extends BaseController
protected string $dateTimeFormat; protected string $dateTimeFormat;
protected string $monthAndDayFormat; protected string $monthAndDayFormat;
protected bool $convertToNative = false; protected bool $convertToNative = false;
protected TransactionCurrency $defaultCurrency;
protected string $monthFormat; protected string $monthFormat;
protected string $redirectUrl = '/'; protected string $redirectUrl = '/';
@@ -111,6 +113,7 @@ abstract class Controller extends BaseController
$this->monthFormat = (string) trans('config.month_js', [], $locale); $this->monthFormat = (string) trans('config.month_js', [], $locale);
$this->monthAndDayFormat = (string) trans('config.month_and_day_js', [], $locale); $this->monthAndDayFormat = (string) trans('config.month_and_day_js', [], $locale);
$this->dateTimeFormat = (string) trans('config.date_time_js', [], $locale); $this->dateTimeFormat = (string) trans('config.date_time_js', [], $locale);
$this->defaultCurrency = app('amount')->getDefaultCurrency();
$darkMode = 'browser'; $darkMode = 'browser';
// get shown-intro-preference: // get shown-intro-preference:
if (auth()->check()) { if (auth()->check()) {

View File

@@ -336,11 +336,11 @@ class Steam
} }
// if the currency is the same as the native currency, set the native_balance to the balance for consistency. // if the currency is the same as the native currency, set the native_balance to the balance for consistency.
if($currency->id === $native->id) { // if($currency->id === $native->id) {
$return['native_balance'] = $return['balance']; // $return['native_balance'] = $return['balance'];
} // }
if (!$hasCurrency) { if (!$hasCurrency && array_key_exists('balance', $return) && array_key_exists('native_balance', $return)) {
Log::debug('Account has no currency preference, dropping balance in favor of native balance.'); Log::debug('Account has no currency preference, dropping balance in favor of native balance.');
$sum = bcadd($return['balance'], $return['native_balance']); $sum = bcadd($return['balance'], $return['native_balance']);
Log::debug(sprintf('%s + %s = %s', $return['balance'], $return['native_balance'], $sum)); Log::debug(sprintf('%s + %s = %s', $return['balance'], $return['native_balance'], $sum));

View File

@@ -75,6 +75,7 @@ class AmountFormat extends AbstractExtension
$this->formatAmountByAccount(), $this->formatAmountByAccount(),
$this->formatAmountBySymbol(), $this->formatAmountBySymbol(),
$this->formatAmountByCurrency(), $this->formatAmountByCurrency(),
$this->formatAmountByCode()
]; ];
} }
@@ -100,6 +101,25 @@ class AmountFormat extends AbstractExtension
); );
} }
/**
* Use the code to format a currency.
*/
protected function formatAmountByCode(): TwigFunction
{
// formatAmountByCode
return new TwigFunction(
'formatAmountByCode',
static function (string $amount, string $code, ?bool $coloured = null): string {
$coloured ??= true;
/** @var TransactionCurrency $currency */
$currency = TransactionCurrency::whereCode($code)->first();
return app('amount')->formatAnything($currency, $amount, $coloured);
},
['is_safe' => ['html']]
);
}
/** /**
* Will format the amount by the currency related to the given account. * Will format the amount by the currency related to the given account.
*/ */
@@ -108,8 +128,8 @@ class AmountFormat extends AbstractExtension
return new TwigFunction( return new TwigFunction(
'formatAmountBySymbol', 'formatAmountBySymbol',
static function (string $amount, string $symbol, ?int $decimalPlaces = null, ?bool $coloured = null): string { static function (string $amount, string $symbol, ?int $decimalPlaces = null, ?bool $coloured = null): string {
$decimalPlaces ??= 2; $decimalPlaces ??= 2;
$coloured ??= true; $coloured ??= true;
$currency = new TransactionCurrency(); $currency = new TransactionCurrency();
$currency->symbol = $symbol; $currency->symbol = $symbol;
$currency->decimal_places = $decimalPlaces; $currency->decimal_places = $decimalPlaces;

View File

@@ -66,14 +66,22 @@
{% if objectType != 'liabilities' %} {% if objectType != 'liabilities' %}
<td style="text-align: right;"> <td style="text-align: right;">
<span style="margin-right:5px;"> <span style="margin-right:5px;">
{{ formatAmountByAccount(account, account.endBalance) }} {% for key, balance in account.endBalances %}
{% if 'balance' == key or 'native_balance' == key %}
{{ formatAmountBySymbol(balance, defaultCurrency.symbol, defaultCurrency.currency.decimal_places) }}
{% else %}
({{ formatAmountByCode(balance, key) }})
{% endif %}
{% endfor %}
</span> </span>
</td> </td>
{% endif %} {% endif %}
{% if objectType == 'liabilities' %} {% if objectType == 'liabilities' %}
<td style="text-align: right;"> <td style="text-align: right;">
{% if '-' != account.current_debt %} {% if '-' != account.current_debt %}
<span class="text-info money-transfer">{{ formatAmountByAccount(account, account.current_debt, false) }}</span> <span class="text-info money-transfer">
{{ formatAmountBySymbol(account.current_debt, account.currency.symbol, account.currency.decimal_places, false) }}
</span>
{% endif %} {% endif %}
</td> </td>
{% endif %} {% endif %}
@@ -99,7 +107,13 @@
{% endif %} {% endif %}
<td class="hidden-sm hidden-xs hidden-md" style="text-align: right;"> <td class="hidden-sm hidden-xs hidden-md" style="text-align: right;">
<span style="margin-right:5px;"> <span style="margin-right:5px;">
{{ formatAmountByAccount(account, account.difference) }} {% for key, balance in account.differences %}
{% if 'balance' == key or 'native_balance' == key %}
{{ formatAmountBySymbol(balance, defaultCurrency.symbol, defaultCurrency.currency.decimal_places) }}
{% else %}
({{ formatAmountByCode(balance, key) }})
{% endif %}
{% endfor %}
</span> </span>
</td> </td>
<td class="hidden-sm hidden-xs"> <td class="hidden-sm hidden-xs">