mirror of
https://github.com/firefly-iii/firefly-iii.git
synced 2025-02-25 18:45:27 -06:00
This makes the expense chart on the frontpage multi-currency.
This commit is contained in:
parent
3764499714
commit
4fc13037d2
@ -39,6 +39,8 @@ class ChartJsGenerator implements GeneratorInterface
|
||||
* 'type' => bar or line, optional
|
||||
* 'yAxisID' => ID of yAxis, optional, will not be included when unused.
|
||||
* 'fill' => if to fill a line? optional, will not be included when unused.
|
||||
* 'currency_symbol' => 'x',
|
||||
* 'backgroundColor' => 'x',
|
||||
* 'entries' =>
|
||||
* [
|
||||
* 'label-of-entry' => 'value'
|
||||
|
@ -65,7 +65,7 @@ class AccountController extends Controller
|
||||
|
||||
|
||||
/**
|
||||
* Shows the balances for all the user's expense accounts.
|
||||
* Shows the balances for all the user's expense accounts (on the front page).
|
||||
*
|
||||
* @param AccountRepositoryInterface $repository
|
||||
*
|
||||
@ -86,23 +86,50 @@ class AccountController extends Controller
|
||||
}
|
||||
$start->subDay();
|
||||
|
||||
/** @var CurrencyRepositoryInterface $currencyRepos */
|
||||
$currencyRepos = app(CurrencyRepositoryInterface::class);
|
||||
$currencies = [];
|
||||
$chartData = [
|
||||
[
|
||||
'label' => (string)trans('firefly.spent'),
|
||||
'type' => 'bar',
|
||||
'currency_symbol' => '¤',
|
||||
'backgroundColor' => 'rgba(219, 68, 55, 0.5)', // red
|
||||
'entries' => [],
|
||||
],
|
||||
];
|
||||
$accounts = $repository->getAccountsByType([AccountType::EXPENSE, AccountType::BENEFICIARY]);
|
||||
$startBalances = app('steam')->balancesByAccounts($accounts, $start);
|
||||
$endBalances = app('steam')->balancesByAccounts($accounts, $end);
|
||||
$chartData = [];
|
||||
$accountNames = $this->extractNames($accounts);
|
||||
$startBalances = app('steam')->balancesPerCurrencyByAccounts($accounts, $start);
|
||||
$endBalances = app('steam')->balancesPerCurrencyByAccounts($accounts, $end);
|
||||
$tempData = [];
|
||||
|
||||
foreach ($accounts as $account) {
|
||||
$id = $account->id;
|
||||
$startBalance = $startBalances[$id] ?? '0';
|
||||
$endBalance = $endBalances[$id] ?? '0';
|
||||
$diff = bcsub($endBalance, $startBalance);
|
||||
if (0 !== bccomp($diff, '0')) {
|
||||
$chartData[$account->name] = $diff;
|
||||
|
||||
foreach ($endBalances as $accountId => $expenses) {
|
||||
$accountId = (int)$accountId;
|
||||
foreach ($expenses as $currencyId => $endAmount) {
|
||||
$currencyId = (int)$currencyId;
|
||||
$startAmount = $startBalances[$accountId][$currencyId] ?? '0';
|
||||
$diff = bcsub($endAmount, $startAmount);
|
||||
$currencies[$currencyId] = $currencies[$currencyId] ?? $currencyRepos->findNull($currencyId);
|
||||
$title = (string)trans(
|
||||
'firefly.account_in_currency', ['account' => $accountNames[$accountId], 'currency' => $currencies[$currencyId]->name]
|
||||
);
|
||||
$tempData[$title] = $diff;
|
||||
}
|
||||
}
|
||||
arsort($tempData, SORT_NUMERIC);
|
||||
|
||||
arsort($chartData);
|
||||
$data = $this->generator->singleSet((string)trans('firefly.spent'), $chartData);
|
||||
foreach ($tempData as $label => $entry) {
|
||||
if (0 !== bccomp($entry, '0')) {
|
||||
$chartData[0]['entries'][$label] = $entry;
|
||||
}
|
||||
}
|
||||
if (1 === \count($currencies)) {
|
||||
$first = array_first($currencies);
|
||||
$chartData[0]['currency_symbol'] = $first->symbol;
|
||||
}
|
||||
$data = $this->generator->multiSet($chartData);
|
||||
$cache->store($data);
|
||||
|
||||
return response()->json($data);
|
||||
@ -507,4 +534,51 @@ class AccountController extends Controller
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Collection $accounts
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function extractNames(Collection $accounts): array
|
||||
{
|
||||
$return = [];
|
||||
/** @var Account $account */
|
||||
foreach ($accounts as $account) {
|
||||
$return[$account->id] = $account->name;
|
||||
}
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method extracts the unique currency ID's from an array of balances.
|
||||
*
|
||||
* The given array is expected to be in this format:
|
||||
*
|
||||
* accountID1:
|
||||
* currencyID1: balance
|
||||
* currencyID2: balance
|
||||
* accountID2:
|
||||
* currencyID1: balance
|
||||
* currencyID2: balance
|
||||
*
|
||||
*
|
||||
* @param array $balances
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function getCurrencyIDs(array $balances): array
|
||||
{
|
||||
$currencies = [];
|
||||
/**
|
||||
* @var int $accountId
|
||||
* @var array $info
|
||||
*/
|
||||
foreach ($balances as $accountId => $info) {
|
||||
$currencies = array_merge(array_keys($info));
|
||||
}
|
||||
|
||||
return array_unique($currencies);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -31,6 +31,7 @@ use FireflyIII\Repositories\Account\AccountRepositoryInterface;
|
||||
use Illuminate\Contracts\Encryption\DecryptException;
|
||||
use Illuminate\Support\Collection;
|
||||
use Log;
|
||||
use stdClass;
|
||||
|
||||
/**
|
||||
* Class Steam.
|
||||
@ -211,6 +212,38 @@ class Steam
|
||||
return $balances;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \FireflyIII\Models\Account $account
|
||||
* @param \Carbon\Carbon $date
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function balancePerCurrency(Account $account, Carbon $date): array
|
||||
{
|
||||
|
||||
// abuse chart properties:
|
||||
$cache = new CacheProperties;
|
||||
$cache->addProperty($account->id);
|
||||
$cache->addProperty('balance-per-currency');
|
||||
$cache->addProperty($date);
|
||||
if ($cache->has()) {
|
||||
return $cache->get(); // @codeCoverageIgnore
|
||||
}
|
||||
$query = $account->transactions()
|
||||
->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id')
|
||||
->where('transaction_journals.date', '<=', $date->format('Y-m-d 23:59:59'))
|
||||
->groupBy('transactions.transaction_currency_id');
|
||||
$balances = $query->get(['transactions.transaction_currency_id', DB::raw('SUM(transactions.amount) as sum_for_currency')]);
|
||||
$return = [];
|
||||
/** @var stdClass $entry */
|
||||
foreach ($balances as $entry) {
|
||||
$return[(int)$entry->transaction_currency_id] = $entry->sum_for_currency;
|
||||
}
|
||||
$cache->store($return);
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method always ignores the virtual balance.
|
||||
*
|
||||
@ -243,6 +276,38 @@ class Steam
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Same as above, but also groups per currency.
|
||||
*
|
||||
* @param \Illuminate\Support\Collection $accounts
|
||||
* @param \Carbon\Carbon $date
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function balancesPerCurrencyByAccounts(Collection $accounts, Carbon $date): array
|
||||
{
|
||||
$ids = $accounts->pluck('id')->toArray();
|
||||
// cache this property.
|
||||
$cache = new CacheProperties;
|
||||
$cache->addProperty($ids);
|
||||
$cache->addProperty('balances-per-currency');
|
||||
$cache->addProperty($date);
|
||||
if ($cache->has()) {
|
||||
return $cache->get(); // @codeCoverageIgnore
|
||||
}
|
||||
|
||||
// need to do this per account.
|
||||
$result = [];
|
||||
/** @var Account $account */
|
||||
foreach ($accounts as $account) {
|
||||
$result[$account->id] = $this->balancePerCurrency($account, $date);
|
||||
}
|
||||
|
||||
$cache->store($result);
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $isEncrypted
|
||||
* @param $value
|
||||
|
@ -183,6 +183,7 @@ return [
|
||||
'scopes_will_be_able' => 'This application will be able to:',
|
||||
'button_authorize' => 'Authorize',
|
||||
'none_in_select_list' => '(none)',
|
||||
'account_in_currency' => ':account in :currency',
|
||||
|
||||
// check for updates:
|
||||
'update_check_title' => 'Check for updates',
|
||||
|
Loading…
Reference in New Issue
Block a user