Expand some multi currency things.

This commit is contained in:
James Cole
2024-12-27 16:36:01 +01:00
parent 96493425d1
commit 3d49d81856
7 changed files with 199 additions and 160 deletions

View File

@@ -36,6 +36,7 @@ use FireflyIII\Repositories\Budget\BudgetLimitRepositoryInterface;
use FireflyIII\Repositories\Budget\BudgetRepositoryInterface; use FireflyIII\Repositories\Budget\BudgetRepositoryInterface;
use FireflyIII\Repositories\Budget\OperationsRepositoryInterface; use FireflyIII\Repositories\Budget\OperationsRepositoryInterface;
use FireflyIII\Repositories\UserGroups\Currency\CurrencyRepositoryInterface; use FireflyIII\Repositories\UserGroups\Currency\CurrencyRepositoryInterface;
use FireflyIII\Support\Http\Api\ExchangeRateConverter;
use FireflyIII\Support\Http\Controllers\DateCalculation; use FireflyIII\Support\Http\Controllers\DateCalculation;
use Illuminate\Contracts\View\Factory; use Illuminate\Contracts\View\Factory;
use Illuminate\Http\JsonResponse; use Illuminate\Http\JsonResponse;
@@ -161,6 +162,7 @@ class IndexController extends Controller
private function getAllAvailableBudgets(Carbon $start, Carbon $end): array private function getAllAvailableBudgets(Carbon $start, Carbon $end): array
{ {
$converter = new ExchangeRateConverter();
// get all available budgets. // get all available budgets.
$ab = $this->abRepository->get($start, $end); $ab = $this->abRepository->get($start, $end);
$availableBudgets = []; $availableBudgets = [];
@@ -175,14 +177,17 @@ class IndexController extends Controller
// spent in period: // spent in period:
$spentArr = $this->opsRepository->sumExpenses($entry->start_date, $entry->end_date, null, null, $entry->transactionCurrency); $spentArr = $this->opsRepository->sumExpenses($entry->start_date, $entry->end_date, null, null, $entry->transactionCurrency);
$array['spent'] = $spentArr[$entry->transaction_currency_id]['sum'] ?? '0'; $array['spent'] = $spentArr[$entry->transaction_currency_id]['sum'] ?? '0';
$array['native_spent'] = $this->convertToNative && $entry->transaction_currency_id !== $this->defaultCurrency->id ? $converter->convert($entry->transactionCurrency, $this->defaultCurrency, $entry->start_date, $array['spent']) : null;
// budgeted in period: // budgeted in period:
$budgeted = $this->blRepository->budgeted($entry->start_date, $entry->end_date, $entry->transactionCurrency); $budgeted = $this->blRepository->budgeted($entry->start_date, $entry->end_date, $entry->transactionCurrency);
$array['budgeted'] = $budgeted; $array['budgeted'] = $budgeted;
$array['native_budgeted'] = $this->convertToNative && $entry->transaction_currency_id !== $this->defaultCurrency->id ? $converter->convert($entry->transactionCurrency, $this->defaultCurrency, $entry->start_date, $budgeted) : null;
// this time, because of complex sums, use the currency converter.
$availableBudgets[] = $array; $availableBudgets[] = $array;
unset($spentArr); unset($spentArr);
} }
return $availableBudgets; return $availableBudgets;
} }

View File

@@ -158,6 +158,7 @@ class BudgetController extends Controller
$cache = new CacheProperties(); $cache = new CacheProperties();
$cache->addProperty($start); $cache->addProperty($start);
$cache->addProperty($end); $cache->addProperty($end);
$cache->addProperty($this->convertToNative);
$cache->addProperty('chart.budget.budget.limit'); $cache->addProperty('chart.budget.budget.limit');
$cache->addProperty($budgetLimit->id); $cache->addProperty($budgetLimit->id);
$cache->addProperty($budget->id); $cache->addProperty($budget->id);
@@ -170,9 +171,15 @@ class BudgetController extends Controller
$amount = $budgetLimit->amount; $amount = $budgetLimit->amount;
$budgetCollection = new Collection([$budget]); $budgetCollection = new Collection([$budget]);
$currency = $budgetLimit->transactionCurrency; $currency = $budgetLimit->transactionCurrency;
if($this->convertToNative) {
$amount = $budgetLimit->native_amount;
$currency = $this->defaultCurrency;
}
while ($start <= $end) { while ($start <= $end) {
$current = clone $start; $current = clone $start;
$expenses = $this->opsRepository->sumExpenses($current, $current, null, $budgetCollection, $currency); $expenses = $this->opsRepository->sumExpenses($current, $current, null, $budgetCollection, $budgetLimit->transactionCurrency);
$spent = $expenses[$currency->id]['sum'] ?? '0'; $spent = $expenses[$currency->id]['sum'] ?? '0';
$amount = bcadd($amount, $spent); $amount = bcadd($amount, $spent);
$format = $start->isoFormat((string) trans('config.month_and_day_js', [], $locale)); $format = $start->isoFormat((string) trans('config.month_and_day_js', [], $locale));
@@ -182,8 +189,8 @@ class BudgetController extends Controller
} }
$data = $this->generator->singleSet((string) trans('firefly.left'), $entries); $data = $this->generator->singleSet((string) trans('firefly.left'), $entries);
// add currency symbol from budget limit: // add currency symbol from budget limit:
$data['datasets'][0]['currency_symbol'] = $budgetLimit->transactionCurrency->symbol; $data['datasets'][0]['currency_symbol'] = $currency->symbol;
$data['datasets'][0]['currency_code'] = $budgetLimit->transactionCurrency->code; $data['datasets'][0]['currency_code'] = $currency->code;
$cache->store($data); $cache->store($data);
return response()->json($data); return response()->json($data);

View File

@@ -49,14 +49,13 @@ class JavascriptController extends Controller
$accounts = $repository->getAccountsByType( $accounts = $repository->getAccountsByType(
[AccountType::DEFAULT, AccountType::ASSET, AccountType::DEBT, AccountType::LOAN, AccountType::MORTGAGE, AccountType::CREDITCARD] [AccountType::DEFAULT, AccountType::ASSET, AccountType::DEBT, AccountType::LOAN, AccountType::MORTGAGE, AccountType::CREDITCARD]
); );
$default = app('amount')->getDefaultCurrency();
$data = ['accounts' => []]; $data = ['accounts' => []];
/** @var Account $account */ /** @var Account $account */
foreach ($accounts as $account) { foreach ($accounts as $account) {
$accountId = $account->id; $accountId = $account->id;
$currency = (int) $repository->getMetaValue($account, 'currency_id'); $currency = (int) $repository->getMetaValue($account, 'currency_id');
$currency = 0 === $currency ? $default->id : $currency; $currency = 0 === $currency ? $this->defaultCurrency->id : $currency;
$entry = ['preferredCurrency' => $currency, 'name' => $account->name]; $entry = ['preferredCurrency' => $currency, 'name' => $account->name];
$data['accounts'][$accountId] = $entry; $data['accounts'][$accountId] = $entry;
} }
@@ -96,9 +95,9 @@ class JavascriptController extends Controller
public function variables(Request $request, AccountRepositoryInterface $repository): Response public function variables(Request $request, AccountRepositoryInterface $repository): Response
{ {
$account = $repository->find((int) $request->get('account')); $account = $repository->find((int) $request->get('account'));
$currency = app('amount')->getDefaultCurrency(); $currency = $this->defaultCurrency;
if (null !== $account) { if (null !== $account) {
$currency = $repository->getAccountCurrency($account) ?? $currency; $currency = $repository->getAccountCurrency($account) ?? $this->defaultCurrency;
} }
$locale = app('steam')->getLocale(); $locale = app('steam')->getLocale();
$accounting = app('amount')->getJsConfig(); $accounting = app('amount')->getJsConfig();

View File

@@ -179,22 +179,26 @@ trait AugumentData
$cache->addProperty($start); $cache->addProperty($start);
$cache->addProperty($end); $cache->addProperty($end);
$cache->addProperty($budget->id); $cache->addProperty($budget->id);
$cache->addProperty($this->convertToNative);
$cache->addProperty('get-limits'); $cache->addProperty('get-limits');
if ($cache->has()) { if ($cache->has()) {
return $cache->get(); // return $cache->get();
} }
$set = $blRepository->getBudgetLimits($budget, $start, $end); $set = $blRepository->getBudgetLimits($budget, $start, $end);
$limits = new Collection();
$budgetCollection = new Collection([$budget]); $budgetCollection = new Collection([$budget]);
// merge sets based on a key, in case of convert to native
$limits = new Collection();
/** @var BudgetLimit $entry */ /** @var BudgetLimit $entry */
foreach ($set as $entry) { foreach ($set as $entry) {
$currency = $entry->transactionCurrency; $currency = $entry->transactionCurrency;
if($this->convertToNative) {
if (null === $currency) { // the sumExpenses method already handles this.
$currency = app('amount')->getDefaultCurrency(); $currency = $this->defaultCurrency;
} }
// clone because these objects change each other. // clone because these objects change each other.
@@ -214,7 +218,7 @@ trait AugumentData
} }
$cache->store($limits); $cache->store($limits);
return $set; return $limits;
} }
/** /**

View File

@@ -198,36 +198,43 @@ trait PeriodOverview
/** @var array $journal */ /** @var array $journal */
foreach ($journals as $journal) { foreach ($journals as $journal) {
$currencyId = (int) $journal['currency_id']; $currencyId = (int) $journal['currency_id'];
$currencyCode = $journal['currency_code'];
$currencyName = $journal['currency_name'];
$currencySymbol = $journal['currency_symbol'];
$currencyDecimalPlaces = $journal['currency_decimal_places'];
$foreignCurrencyId = $journal['foreign_currency_id']; $foreignCurrencyId = $journal['foreign_currency_id'];
if (!array_key_exists($currencyId, $return)) { $amount = $journal['amount'];
$return[$currencyId] = [
if ($this->convertToNative && $currencyId !== $this->defaultCurrency->id && $foreignCurrencyId !== $this->defaultCurrency->id) {
$amount = $journal['native_amount'];
$currencyId = $this->defaultCurrency->id;
$currencyCode = $this->defaultCurrency->code;
$currencyName = $this->defaultCurrency->name;
$currencySymbol = $this->defaultCurrency->symbol;
$currencyDecimalPlaces = $this->defaultCurrency->decimal_places;
}
if ($this->convertToNative && $currencyId !== $this->defaultCurrency->id && $foreignCurrencyId === $this->defaultCurrency->id) {
$currencyId = (int) $foreignCurrencyId;
$currencyCode = $journal['foreign_currency_code'];
$currencyName = $journal['foreign_currency_name'];
$currencySymbol = $journal['foreign_currency_symbol'];
$currencyDecimalPlaces = $journal['foreign_currency_decimal_places'];
$amount = $journal['foreign_amount'];
}
$return[$currencyId] ??= [
'amount' => '0', 'amount' => '0',
'count' => 0, 'count' => 0,
'currency_id' => $currencyId, 'currency_id' => $currencyId,
'currency_name' => $journal['currency_name'], 'currency_name' => $currencyName,
'currency_code' => $journal['currency_code'], 'currency_code' => $currencyCode,
'currency_symbol' => $journal['currency_symbol'], 'currency_symbol' => $currencySymbol,
'currency_decimal_places' => $journal['currency_decimal_places'], 'currency_decimal_places' => $currencyDecimalPlaces,
]; ];
}
$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[$currencyId]['amount'] = bcadd($return[$currencyId]['amount'], $amount);
$return[$foreignCurrencyId] = [ ++$return[$currencyId]['count'];
'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; return $return;
@@ -322,10 +329,11 @@ trait PeriodOverview
$cache = new CacheProperties(); $cache = new CacheProperties();
$cache->addProperty($start); $cache->addProperty($start);
$cache->addProperty($end); $cache->addProperty($end);
$cache->addProperty($this->convertToNative);
$cache->addProperty('no-budget-period-entries'); $cache->addProperty('no-budget-period-entries');
if ($cache->has()) { if ($cache->has()) {
return $cache->get(); // return $cache->get();
} }
/** @var array $dates */ /** @var array $dates */

View File

@@ -116,6 +116,9 @@
<small>{{ 'budgeted'|_ }}: <small>{{ 'budgeted'|_ }}:
<span class="text-success money-positive budgeted_amount" data-id="{{ budget.id }}" data-currency="{{ budget.transaction_currency.id }}"> <span class="text-success money-positive budgeted_amount" data-id="{{ budget.id }}" data-currency="{{ budget.transaction_currency.id }}">
{{ formatAmountBySymbol(budget.budgeted, budget.transaction_currency.symbol, budget.transaction_currency.decimal_places, false) }} {{ formatAmountBySymbol(budget.budgeted, budget.transaction_currency.symbol, budget.transaction_currency.decimal_places, false) }}
{% if null != budget.native_budgeted %}
({{ formatAmountBySymbol(budget.native_budgeted, defaultCurrency.symbol, defaultCurrency.decimal_places, false) }})
{% endif %}
</span> </span>
</small> </small>
</div> </div>
@@ -125,7 +128,13 @@
data-id="{{ budget.id }}">{{ trans('firefly.available_between', {start: budget.start_date.isoFormat(monthAndDayFormat), end: budget.end_date.isoFormat(monthAndDayFormat) }) }} data-id="{{ budget.id }}">{{ trans('firefly.available_between', {start: budget.start_date.isoFormat(monthAndDayFormat), end: budget.end_date.isoFormat(monthAndDayFormat) }) }}
: :
<span class="available_amount" data-id="{{ budget.id }}" data-currency="{{ budget.transaction_currency.id }}" <span class="available_amount" data-id="{{ budget.id }}" data-currency="{{ budget.transaction_currency.id }}"
data-value="{{ budget.amount }}">{{ formatAmountBySymbol(budget.amount, budget.transaction_currency.symbol, budget.transaction_currency.decimal_places, true) }}</span> data-value="{{ budget.amount }}">
{{ formatAmountBySymbol(budget.amount, budget.transaction_currency.symbol, budget.transaction_currency.decimal_places, true) }}
{% if(convertToNative and 0 != budget.native_amount) %}
({{ formatAmountBySymbol(budget.native_amount, defaultCurrency.symbol, defaultCurrency.decimal_places, true) }})
{% endif %}
</span>
</small> </small>
</div> </div>
</div> </div>

View File

@@ -158,12 +158,19 @@
<td style="width:33%;">{{ 'amount'|_ }}</td> <td style="width:33%;">{{ 'amount'|_ }}</td>
<td> <td>
{{ formatAmountBySymbol(limit.amount, limit.transactionCurrency.symbol, limit.transactionCurrency.decimal_places) }} {{ formatAmountBySymbol(limit.amount, limit.transactionCurrency.symbol, limit.transactionCurrency.decimal_places) }}
{% if convertToNative and 0 != limit.native_amount %}
({{ formatAmountBySymbol(limit.native_amount, defaultCurrency.symbol, defaultCurrency.decimal_places) }})
{% endif %}
</td> </td>
</tr> </tr>
<tr> <tr>
<td style="width:33%;">{{ 'spent'|_ }}</td> <td style="width:33%;">{{ 'spent'|_ }}</td>
<td> <td>
{% if convertToNative %}
{{ formatAmountBySymbol(limit.spent, defaultCurrency.symbol, defaultCurrency.decimal_places) }}
{% else %}
{{ formatAmountBySymbol(limit.spent, limit.transactionCurrency.symbol, limit.transactionCurrency.decimal_places) }} {{ formatAmountBySymbol(limit.spent, limit.transactionCurrency.symbol, limit.transactionCurrency.decimal_places) }}
{% endif %}
</td> </td>
</tr> </tr>
{% if limit.spent > 0 %} {% if limit.spent > 0 %}