mirror of
https://github.com/firefly-iii/firefly-iii.git
synced 2025-02-25 18:45:27 -06:00
Make reports slightly more multi currency.
This commit is contained in:
parent
1903292202
commit
d5773ab5d0
@ -24,6 +24,7 @@ namespace FireflyIII\Helpers\Collection;
|
|||||||
|
|
||||||
use Carbon\Carbon;
|
use Carbon\Carbon;
|
||||||
use FireflyIII\Models\Bill as BillModel;
|
use FireflyIII\Models\Bill as BillModel;
|
||||||
|
use FireflyIII\Models\TransactionCurrency;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class BillLine.
|
* Class BillLine.
|
||||||
@ -42,6 +43,8 @@ class BillLine
|
|||||||
protected $max;
|
protected $max;
|
||||||
/** @var string What was the min amount. */
|
/** @var string What was the min amount. */
|
||||||
protected $min;
|
protected $min;
|
||||||
|
/** @var TransactionCurrency The transaction currency */
|
||||||
|
private $currency;
|
||||||
/** @var Carbon Latest date that payment is expected. */
|
/** @var Carbon Latest date that payment is expected. */
|
||||||
private $endOfPayDate;
|
private $endOfPayDate;
|
||||||
/** @var Carbon Date of last hit */
|
/** @var Carbon Date of last hit */
|
||||||
@ -99,6 +102,22 @@ class BillLine
|
|||||||
$this->bill = $bill;
|
$this->bill = $bill;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return TransactionCurrency
|
||||||
|
*/
|
||||||
|
public function getCurrency(): TransactionCurrency
|
||||||
|
{
|
||||||
|
return $this->currency;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param TransactionCurrency $currency
|
||||||
|
*/
|
||||||
|
public function setCurrency(TransactionCurrency $currency): void
|
||||||
|
{
|
||||||
|
$this->currency = $currency;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* End of pay date getter.
|
* End of pay date getter.
|
||||||
*
|
*
|
||||||
|
@ -98,6 +98,7 @@ class ReportHelper implements ReportHelperInterface
|
|||||||
|
|
||||||
$billLine = new BillLine;
|
$billLine = new BillLine;
|
||||||
$billLine->setBill($bill);
|
$billLine->setBill($bill);
|
||||||
|
$billLine->setCurrency($bill->transactionCurrency);
|
||||||
$billLine->setPayDate($payDate);
|
$billLine->setPayDate($payDate);
|
||||||
$billLine->setEndOfPayDate($endOfPayPeriod);
|
$billLine->setEndOfPayDate($endOfPayPeriod);
|
||||||
$billLine->setMin((string)$bill->amount_min);
|
$billLine->setMin((string)$bill->amount_min);
|
||||||
|
@ -24,8 +24,10 @@ namespace FireflyIII\Repositories\Account;
|
|||||||
|
|
||||||
use Carbon\Carbon;
|
use Carbon\Carbon;
|
||||||
use FireflyIII\Helpers\Collector\TransactionCollectorInterface;
|
use FireflyIII\Helpers\Collector\TransactionCollectorInterface;
|
||||||
|
use FireflyIII\Models\Account;
|
||||||
use FireflyIII\Models\Transaction;
|
use FireflyIII\Models\Transaction;
|
||||||
use FireflyIII\Models\TransactionType;
|
use FireflyIII\Models\TransactionType;
|
||||||
|
use FireflyIII\Repositories\Currency\CurrencyRepositoryInterface;
|
||||||
use FireflyIII\User;
|
use FireflyIII\User;
|
||||||
use Illuminate\Support\Collection;
|
use Illuminate\Support\Collection;
|
||||||
use Log;
|
use Log;
|
||||||
@ -68,18 +70,28 @@ class AccountTasker implements AccountTaskerInterface
|
|||||||
/** @var AccountRepositoryInterface $repository */
|
/** @var AccountRepositoryInterface $repository */
|
||||||
$repository = app(AccountRepositoryInterface::class);
|
$repository = app(AccountRepositoryInterface::class);
|
||||||
|
|
||||||
|
/** @var CurrencyRepositoryInterface $currencyRepository */
|
||||||
|
$currencyRepository = app(CurrencyRepositoryInterface::class);
|
||||||
|
$defaultCurrency = app('amount')->getDefaultCurrencyByUser($this->user);
|
||||||
|
|
||||||
$return = [
|
$return = [
|
||||||
|
'currencies' => [],
|
||||||
'start' => '0',
|
'start' => '0',
|
||||||
'end' => '0',
|
'end' => '0',
|
||||||
'difference' => '0',
|
'difference' => '0',
|
||||||
'accounts' => [],
|
'accounts' => [],
|
||||||
];
|
];
|
||||||
|
|
||||||
|
/** @var Account $account */
|
||||||
foreach ($accounts as $account) {
|
foreach ($accounts as $account) {
|
||||||
$id = $account->id;
|
$id = $account->id;
|
||||||
|
$currencyId = (int)$repository->getMetaValue($account, 'currency_id');
|
||||||
|
$currency = $currencyRepository->findNull($currencyId);
|
||||||
|
$return['currencies'][] = $currencyId;
|
||||||
$entry = [
|
$entry = [
|
||||||
'name' => $account->name,
|
'name' => $account->name,
|
||||||
'id' => $account->id,
|
'id' => $account->id,
|
||||||
|
'currency' => $currency ?? $defaultCurrency,
|
||||||
'start_balance' => '0',
|
'start_balance' => '0',
|
||||||
'end_balance' => '0',
|
'end_balance' => '0',
|
||||||
];
|
];
|
||||||
@ -100,7 +112,7 @@ class AccountTasker implements AccountTaskerInterface
|
|||||||
|
|
||||||
$return['accounts'][$id] = $entry;
|
$return['accounts'][$id] = $entry;
|
||||||
}
|
}
|
||||||
|
$return['currencies'] = count(array_unique($return['currencies']));
|
||||||
$return['difference'] = bcsub($return['end'], $return['start']);
|
$return['difference'] = bcsub($return['end'], $return['start']);
|
||||||
|
|
||||||
return $return;
|
return $return;
|
||||||
@ -206,29 +218,51 @@ class AccountTasker implements AccountTaskerInterface
|
|||||||
*/
|
*/
|
||||||
private function groupByOpposing(Collection $transactions): array
|
private function groupByOpposing(Collection $transactions): array
|
||||||
{
|
{
|
||||||
|
$defaultCurrency = app('amount')->getDefaultCurrencyByUser($this->user);
|
||||||
|
/** @var CurrencyRepositoryInterface $currencyRepos */
|
||||||
|
$currencyRepos = app(CurrencyRepositoryInterface::class);
|
||||||
|
$currencies = [$defaultCurrency->id => $defaultCurrency,];
|
||||||
$expenses = [];
|
$expenses = [];
|
||||||
// join the result together:
|
$countAccounts = []; // if count remains 0 use original name, not the name with the currency.
|
||||||
|
|
||||||
|
|
||||||
|
/** @var Transaction $transaction */
|
||||||
foreach ($transactions as $transaction) {
|
foreach ($transactions as $transaction) {
|
||||||
$opposingId = $transaction->opposing_account_id;
|
$opposingId = (int)$transaction->opposing_account_id;
|
||||||
$name = $transaction->opposing_account_name;
|
$currencyId = (int)$transaction->transaction_currency_id;
|
||||||
if (!isset($expenses[$opposingId])) {
|
$key = sprintf('%s-%s', $opposingId, $currencyId);
|
||||||
$expenses[$opposingId] = [
|
$name = sprintf('%s (%s)', $transaction->opposing_account_name, $transaction->transaction_currency_code);
|
||||||
|
$countAccounts[$opposingId] = isset($countAccounts[$opposingId]) ? $countAccounts[$opposingId] + 1 : 1;
|
||||||
|
if (!isset($expenses[$key])) {
|
||||||
|
$currencies[$currencyId] = $currencies[$currencyId] ?? $currencyRepos->findNull($currencyId);
|
||||||
|
$expenses[$key] = [
|
||||||
'id' => $opposingId,
|
'id' => $opposingId,
|
||||||
'name' => $name,
|
'name' => $name,
|
||||||
|
'original' => $transaction->opposing_account_name,
|
||||||
'sum' => '0',
|
'sum' => '0',
|
||||||
'average' => '0',
|
'average' => '0',
|
||||||
|
'currencies' => [],
|
||||||
|
'single_currency' => $currencies[$currencyId],
|
||||||
'count' => 0,
|
'count' => 0,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
$expenses[$opposingId]['sum'] = bcadd($expenses[$opposingId]['sum'], $transaction->transaction_amount);
|
$expenses[$key]['currencies'][] = (int)$transaction->transaction_currency_id;
|
||||||
++$expenses[$opposingId]['count'];
|
$expenses[$key]['sum'] = bcadd($expenses[$key]['sum'], $transaction->transaction_amount);
|
||||||
|
++$expenses[$key]['count'];
|
||||||
}
|
}
|
||||||
// do averages:
|
// do averages:
|
||||||
$keys = array_keys($expenses);
|
$keys = array_keys($expenses);
|
||||||
foreach ($keys as $key) {
|
foreach ($keys as $key) {
|
||||||
|
$opposingId = $expenses[$key]['id'];
|
||||||
|
if(1===$countAccounts[$opposingId]) {
|
||||||
|
$expenses[$key]['name'] = $expenses[$key]['original'];
|
||||||
|
}
|
||||||
|
|
||||||
if ($expenses[$key]['count'] > 1) {
|
if ($expenses[$key]['count'] > 1) {
|
||||||
$expenses[$key]['average'] = bcdiv($expenses[$key]['sum'], (string)$expenses[$key]['count']);
|
$expenses[$key]['average'] = bcdiv($expenses[$key]['sum'], (string)$expenses[$key]['count']);
|
||||||
}
|
}
|
||||||
|
$expenses[$key]['currencies'] = \count(array_unique($expenses[$key]['currencies']));
|
||||||
|
$expenses[$key]['all_currencies'] = \count($currencies);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $expenses;
|
return $expenses;
|
||||||
|
@ -148,7 +148,7 @@ class BillRepository implements BillRepositoryInterface
|
|||||||
public function getBillsForAccounts(Collection $accounts): Collection
|
public function getBillsForAccounts(Collection $accounts): Collection
|
||||||
{
|
{
|
||||||
$fields = ['bills.id', 'bills.created_at', 'bills.updated_at', 'bills.deleted_at', 'bills.user_id', 'bills.name', 'bills.match', 'bills.amount_min',
|
$fields = ['bills.id', 'bills.created_at', 'bills.updated_at', 'bills.deleted_at', 'bills.user_id', 'bills.name', 'bills.match', 'bills.amount_min',
|
||||||
'bills.amount_max', 'bills.date', 'bills.repeat_freq', 'bills.skip', 'bills.automatch', 'bills.active', 'bills.name_encrypted',
|
'bills.amount_max', 'bills.date','bills.transaction_currency_id', 'bills.repeat_freq', 'bills.skip', 'bills.automatch', 'bills.active', 'bills.name_encrypted',
|
||||||
'bills.match_encrypted',];
|
'bills.match_encrypted',];
|
||||||
$ids = $accounts->pluck('id')->toArray();
|
$ids = $accounts->pluck('id')->toArray();
|
||||||
$set = $this->user->bills()
|
$set = $this->user->bills()
|
||||||
|
@ -27,6 +27,7 @@ namespace FireflyIII\Support\Http\Controllers;
|
|||||||
use FireflyIII\Helpers\Collection\BalanceLine;
|
use FireflyIII\Helpers\Collection\BalanceLine;
|
||||||
use FireflyIII\Helpers\Report\PopupReportInterface;
|
use FireflyIII\Helpers\Report\PopupReportInterface;
|
||||||
use FireflyIII\Models\AccountType;
|
use FireflyIII\Models\AccountType;
|
||||||
|
use FireflyIII\Models\Budget;
|
||||||
use FireflyIII\Models\Tag;
|
use FireflyIII\Models\Tag;
|
||||||
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
|
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
|
||||||
use FireflyIII\Repositories\Budget\BudgetRepositoryInterface;
|
use FireflyIII\Repositories\Budget\BudgetRepositoryInterface;
|
||||||
@ -102,6 +103,7 @@ trait RenderPartialViews
|
|||||||
break;
|
break;
|
||||||
case BalanceLine::ROLE_DEFAULTROLE === $role && null === $budget && null !== $account:
|
case BalanceLine::ROLE_DEFAULTROLE === $role && null === $budget && null !== $account:
|
||||||
// normal row without a budget:
|
// normal row without a budget:
|
||||||
|
$budget = new Budget;
|
||||||
$journals = $popupHelper->balanceForNoBudget($account, $attributes);
|
$journals = $popupHelper->balanceForNoBudget($account, $attributes);
|
||||||
$budget->name = (string)trans('firefly.no_budget');
|
$budget->name = (string)trans('firefly.no_budget');
|
||||||
break;
|
break;
|
||||||
@ -156,7 +158,7 @@ trait RenderPartialViews
|
|||||||
|
|
||||||
$budget = $budgetRepository->findNull((int)$attributes['budgetId']);
|
$budget = $budgetRepository->findNull((int)$attributes['budgetId']);
|
||||||
if (null === $budget) {
|
if (null === $budget) {
|
||||||
return 'This is an unknown budget. Apologies.';
|
$budget = new Budget;
|
||||||
}
|
}
|
||||||
$journals = $popupHelper->byBudget($budget, $attributes);
|
$journals = $popupHelper->byBudget($budget, $attributes);
|
||||||
try {
|
try {
|
||||||
|
@ -1013,6 +1013,8 @@ return [
|
|||||||
'in_out_per_category' => 'Earned and spent per category',
|
'in_out_per_category' => 'Earned and spent per category',
|
||||||
'out_per_budget' => 'Spent per budget',
|
'out_per_budget' => 'Spent per budget',
|
||||||
'select_expense_revenue' => 'Select expense/revenue account',
|
'select_expense_revenue' => 'Select expense/revenue account',
|
||||||
|
'multi_currency_report_sum' => 'Because this list contains accounts with multiple currencies, the sum(s) you see may not make sense. The report will always fall back to your default currency.',
|
||||||
|
'sum_in_default_currency' => 'The sum will always be in your default currency.',
|
||||||
|
|
||||||
// charts:
|
// charts:
|
||||||
'chart' => 'Chart',
|
'chart' => 'Chart',
|
||||||
|
@ -9,6 +9,11 @@
|
|||||||
<div class="modal-body">
|
<div class="modal-body">
|
||||||
{% set hideBudget = true %}
|
{% set hideBudget = true %}
|
||||||
{% include 'popup/list/journals' %}
|
{% include 'popup/list/journals' %}
|
||||||
|
<p>
|
||||||
|
<small class="text-warning">
|
||||||
|
{{ 'sum_in_default_currency'|_ }}
|
||||||
|
</small>
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-footer">
|
<div class="modal-footer">
|
||||||
<button type="button" class="btn btn-default" data-dismiss="modal">{{ 'close'|_ }}</button>
|
<button type="button" class="btn btn-default" data-dismiss="modal">{{ 'close'|_ }}</button>
|
||||||
|
@ -13,10 +13,15 @@
|
|||||||
<td data-value="{{ account.name }}">
|
<td data-value="{{ account.name }}">
|
||||||
<a href="{{ route('accounts.show',account.id) }}" title="{{ account.name }}">{{ account.name }}</a>
|
<a href="{{ route('accounts.show',account.id) }}" title="{{ account.name }}">{{ account.name }}</a>
|
||||||
</td>
|
</td>
|
||||||
<td class="hidden-xs" data-value="{{ account.start_balance }}" style="text-align: right;">{{ account.start_balance|formatAmount }}</td>
|
<td class="hidden-xs" data-value="{{ account.start_balance }}" style="text-align: right;">
|
||||||
<td class="hidden-xs" data-value="{{ account.end_balance }}" style="text-align: right;">{{ account.end_balance|formatAmount }}</td>
|
{{ formatAmountByCurrency(account.currency, account.start_balance) }}
|
||||||
|
</td>
|
||||||
|
<td class="hidden-xs" data-value="{{ account.end_balance }}" style="text-align: right;">
|
||||||
|
{{ formatAmountByCurrency(account.currency, account.end_balance) }}</td>
|
||||||
<td style="text-align: right;"
|
<td style="text-align: right;"
|
||||||
data-value="{{ (account.end_balance - account.start_balance) }}">{{ (account.end_balance - account.start_balance)|formatAmount }}</td>
|
data-value="{{ (account.end_balance - account.start_balance) }}">
|
||||||
|
{{ formatAmountByCurrency(account.currency, (account.end_balance - account.start_balance)) }}
|
||||||
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</tbody>
|
</tbody>
|
||||||
@ -27,5 +32,10 @@
|
|||||||
<td class="hidden-xs" style="text-align: right;">{{ accountReport.end|formatAmount }}</td>
|
<td class="hidden-xs" style="text-align: right;">{{ accountReport.end|formatAmount }}</td>
|
||||||
<td style="text-align: right;">{{ accountReport.difference|formatAmount }}</td>
|
<td style="text-align: right;">{{ accountReport.difference|formatAmount }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
{% if accountReport.currencies > 1 %}
|
||||||
|
<tr>
|
||||||
|
<td colspan="4"><small class="text-warning">{{ 'multi_currency_report_sum'|_ }}</small></td>
|
||||||
|
</tr>
|
||||||
|
{% endif %}
|
||||||
</tfoot>
|
</tfoot>
|
||||||
</table>
|
</table>
|
||||||
|
@ -22,14 +22,14 @@
|
|||||||
{{ trans('firefly.bill_expected_between', {start: line.getPayDate.formatLocalized(monthAndDayFormat), end: line.getEndOfPayDate.formatLocalized(monthAndDayFormat) }) }}
|
{{ trans('firefly.bill_expected_between', {start: line.getPayDate.formatLocalized(monthAndDayFormat), end: line.getEndOfPayDate.formatLocalized(monthAndDayFormat) }) }}
|
||||||
</small>
|
</small>
|
||||||
</td>
|
</td>
|
||||||
<td class="hidden-xs" data-value="{{ line.getMin }}" style="text-align: right;">{{ line.getMin|formatAmount }}</td>
|
<td class="hidden-xs" data-value="{{ line.getMin }}" style="text-align: right;">{{ formatAmountByCurrency(line.getCurrency, line.getMin) }}</td>
|
||||||
<td class="hidden-xs" data-value="{{ line.getMax }}" style="text-align: right;">{{ line.getMax|formatAmount }}</td>
|
<td class="hidden-xs" data-value="{{ line.getMax }}" style="text-align: right;">{{ formatAmountByCurrency(line.getCurrency, line.getMax) }}</td>
|
||||||
|
|
||||||
{# if bill is hit, show hit amount #}
|
{# if bill is hit, show hit amount #}
|
||||||
{% if line.isHit %}
|
{% if line.isHit %}
|
||||||
<td data-value="{{ line.getAmount }}" style="text-align: right;">
|
<td data-value="{{ line.getAmount }}" style="text-align: right;">
|
||||||
<a href="{{ route('transactions.show', line.getTransactionJournalId) }}">
|
<a href="{{ route('transactions.show', line.getTransactionJournalId) }}">
|
||||||
{{ line.getAmount|formatAmount }}
|
{{ formatAmountByCurrency(line.getCurrency, line.getAmount) }}
|
||||||
</a>
|
</a>
|
||||||
</td>
|
</td>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
@ -42,7 +42,7 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
<td data-value="{{ (line.getMax - line.getAmount) }}" style="text-align: right;" class="hidden-xs">
|
<td data-value="{{ (line.getMax - line.getAmount) }}" style="text-align: right;" class="hidden-xs">
|
||||||
{% if line.isHit %}
|
{% if line.isHit %}
|
||||||
{{ (line.getMax + line.getAmount)|formatAmount }}
|
{{ formatAmountByCurrency(line.getCurrency, (line.getMax + line.getAmount)) }}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
@ -26,7 +26,11 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
</td>
|
</td>
|
||||||
<td data-value="{{ entry.sum }}" style="text-align: right;">
|
<td data-value="{{ entry.sum }}" style="text-align: right;">
|
||||||
|
{% if entry.currencies == 1 %}
|
||||||
|
{{ formatAmountByCurrency(entry.single_currency, entry.sum) }}
|
||||||
|
{% else %}
|
||||||
{{ (entry.sum)|formatAmount }}
|
{{ (entry.sum)|formatAmount }}
|
||||||
|
{% endif %}
|
||||||
</td>
|
</td>
|
||||||
<td class="hidden-xs" data-value="{{ entry.average }}" style="text-align: right;">
|
<td class="hidden-xs" data-value="{{ entry.average }}" style="text-align: right;">
|
||||||
{% if entry.count > 1 %}
|
{% if entry.count > 1 %}
|
||||||
@ -54,5 +58,8 @@
|
|||||||
<td><em>{{ 'sum'|_ }}</em></td>
|
<td><em>{{ 'sum'|_ }}</em></td>
|
||||||
<td style="text-align: right;">{{ (sum)|formatAmount }}</td>
|
<td style="text-align: right;">{{ (sum)|formatAmount }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td colspan="4"><small class="text-warning">{{ 'sum_in_default_currency'|_ }}</small></td>
|
||||||
|
</tr>
|
||||||
</tfoot>
|
</tfoot>
|
||||||
</table>
|
</table>
|
||||||
|
@ -11,4 +11,9 @@
|
|||||||
<td>{{ 'difference'|_ }}</td>
|
<td>{{ 'difference'|_ }}</td>
|
||||||
<td style="text-align: right;">{{ (incomeSum + expensesSum)|formatAmount }}</td>
|
<td style="text-align: right;">{{ (incomeSum + expensesSum)|formatAmount }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td colspan="2">
|
||||||
|
<small class="text-warning">{{ 'sum_in_default_currency'|_ }}</small>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
|
Loading…
Reference in New Issue
Block a user