diff --git a/app/Api/V1/Controllers/Summary/BasicController.php b/app/Api/V1/Controllers/Summary/BasicController.php
index 74a71fd4c2..89217caf55 100644
--- a/app/Api/V1/Controllers/Summary/BasicController.php
+++ b/app/Api/V1/Controllers/Summary/BasicController.php
@@ -27,6 +27,7 @@ namespace FireflyIII\Api\V1\Controllers\Summary;
use Carbon\Carbon;
use FireflyIII\Api\V1\Controllers\Controller;
use FireflyIII\Api\V1\Requests\Data\DateRequest;
+use FireflyIII\Enums\AccountTypeEnum;
use FireflyIII\Enums\TransactionTypeEnum;
use FireflyIII\Helpers\Collector\GroupCollectorInterface;
use FireflyIII\Helpers\Report\NetWorthInterface;
@@ -38,6 +39,7 @@ use FireflyIII\Repositories\Budget\AvailableBudgetRepositoryInterface;
use FireflyIII\Repositories\Budget\BudgetRepositoryInterface;
use FireflyIII\Repositories\Budget\OperationsRepositoryInterface;
use FireflyIII\Repositories\UserGroups\Currency\CurrencyRepositoryInterface;
+use FireflyIII\Support\Facades\Amount;
use FireflyIII\User;
use Illuminate\Http\JsonResponse;
use Illuminate\Support\Facades\Log;
@@ -102,10 +104,10 @@ class BasicController extends Controller
$billData = $this->getBillInformation($start, $end);
$spentData = $this->getLeftToSpendInfo($start, $end);
$netWorthData = $this->getNetWorthInfo($start, $end);
- $balanceData = [];
- $billData = [];
-// $spentData = [];
- $netWorthData = [];
+// $balanceData = [];
+// $billData = [];
+// $spentData = [];
+// $netWorthData = [];
$total = array_merge($balanceData, $billData, $spentData, $netWorthData);
// give new keys
@@ -121,6 +123,9 @@ class BasicController extends Controller
private function getBalanceInformation(Carbon $start, Carbon $end): array
{
+ // some config settings
+ $convertToNative = app('preferences')->get('convert_to_native', false)->data;
+ $default = app('amount')->getDefaultCurrency();
// prep some arrays:
$incomes = [];
$expenses = [];
@@ -134,16 +139,17 @@ class BasicController extends Controller
$set = $collector->getExtractedJournals();
- /** @var array $transactionJournal */
- foreach ($set as $transactionJournal) {
- $currencyId = (int) $transactionJournal['currency_id'];
+ /** @var array $journal */
+ foreach ($set as $journal) {
+ $currencyId = $convertToNative ? $default->id : (int) $journal['currency_id'];
+ $amount = Amount::getAmountFromJournal($journal);
$incomes[$currencyId] ??= '0';
$incomes[$currencyId] = bcadd(
$incomes[$currencyId],
- bcmul($transactionJournal['amount'], '-1')
+ bcmul($amount, '-1')
);
$sums[$currencyId] ??= '0';
- $sums[$currencyId] = bcadd($sums[$currencyId], bcmul($transactionJournal['amount'], '-1'));
+ $sums[$currencyId] = bcadd($sums[$currencyId], bcmul($amount, '-1'));
}
// collect expenses of user using the new group collector.
@@ -152,13 +158,14 @@ class BasicController extends Controller
$collector->setRange($start, $end)->setPage($this->parameters->get('page'))->setTypes([TransactionTypeEnum::WITHDRAWAL->value]);
$set = $collector->getExtractedJournals();
- /** @var array $transactionJournal */
- foreach ($set as $transactionJournal) {
- $currencyId = (int) $transactionJournal['currency_id'];
+ /** @var array $journal */
+ foreach ($set as $journal) {
+ $currencyId = $convertToNative ? $default->id : (int) $journal['currency_id'];
+ $amount = Amount::getAmountFromJournal($journal);
$expenses[$currencyId] ??= '0';
- $expenses[$currencyId] = bcadd($expenses[$currencyId], $transactionJournal['amount']);
+ $expenses[$currencyId] = bcadd($expenses[$currencyId], $amount);
$sums[$currencyId] ??= '0';
- $sums[$currencyId] = bcadd($sums[$currencyId], $transactionJournal['amount']);
+ $sums[$currencyId] = bcadd($sums[$currencyId], $amount);
}
// format amounts:
@@ -317,7 +324,7 @@ class BasicController extends Controller
{
/** @var User $user */
$user = auth()->user();
- $date = today(config('app.timezone'))->startOfDay();
+ $date = now(config('app.timezone'));
// start and end in the future? use $end
if ($this->notInDateRange($date, $start, $end)) {
/** @var Carbon $date */
@@ -327,9 +334,7 @@ class BasicController extends Controller
/** @var NetWorthInterface $netWorthHelper */
$netWorthHelper = app(NetWorthInterface::class);
$netWorthHelper->setUser($user);
- $allAccounts = $this->accountRepository->getActiveAccountsByType(
- [AccountType::ASSET, AccountType::DEFAULT, AccountType::LOAN, AccountType::MORTGAGE, AccountType::DEBT]
- );
+ $allAccounts = $this->accountRepository->getActiveAccountsByType([AccountTypeEnum::ASSET->value, AccountTypeEnum::DEFAULT->value, AccountTypeEnum::LOAN->value, AccountTypeEnum::MORTGAGE->value, AccountTypeEnum::DEBT->value]);
// filter list on preference of being included.
$filtered = $allAccounts->filter(
diff --git a/app/Helpers/Report/NetWorth.php b/app/Helpers/Report/NetWorth.php
index dbffefd0e3..1a8a9d5a9f 100644
--- a/app/Helpers/Report/NetWorth.php
+++ b/app/Helpers/Report/NetWorth.php
@@ -33,7 +33,8 @@ use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use FireflyIII\Repositories\UserGroups\Account\AccountRepositoryInterface as AdminAccountRepositoryInterface;
use FireflyIII\Repositories\UserGroups\Currency\CurrencyRepositoryInterface;
use FireflyIII\Support\CacheProperties;
-use FireflyIII\Support\Http\Api\ExchangeRateConverter;
+use FireflyIII\Support\Facades\Amount;
+use FireflyIII\Support\Facades\Steam;
use FireflyIII\User;
use Illuminate\Contracts\Auth\Authenticatable;
use Illuminate\Support\Collection;
@@ -65,87 +66,58 @@ class NetWorth implements NetWorthInterface
public function byAccounts(Collection $accounts, Carbon $date): array
{
// start in the past, end in the future? use $date
- $ids = implode(',', $accounts->pluck('id')->toArray());
- $cache = new CacheProperties();
+ $convertToNative = app('preferences')->get('convert_to_native', false)->data;
+ $ids = implode(',', $accounts->pluck('id')->toArray());
+ $cache = new CacheProperties();
$cache->addProperty($date);
+ $cache->addProperty($convertToNative);
$cache->addProperty('net-worth-by-accounts');
$cache->addProperty($ids);
if ($cache->has()) {
- return $cache->get();
+ // return $cache->get();
}
- app('log')->debug(sprintf('Now in byAccounts("%s", "%s")', $ids, $date->format('Y-m-d')));
- Log::debug(sprintf('Created new ExchangeRateConverter in %s', __METHOD__));
- $default = app('amount')->getDefaultCurrency();
- $converter = new ExchangeRateConverter();
-
- // default "native" currency has everything twice, for consistency.
- $netWorth = [
- 'native' => [
- 'balance' => '0',
- 'native_balance' => '0',
- 'currency_id' => $default->id,
- 'currency_code' => $default->code,
- 'currency_name' => $default->name,
- 'currency_symbol' => $default->symbol,
- 'currency_decimal_places' => $default->decimal_places,
- 'native_currency_id' => $default->id,
- 'native_currency_code' => $default->code,
- 'native_currency_name' => $default->name,
- 'native_currency_symbol' => $default->symbol,
- 'native_currency_decimal_places' => $default->decimal_places,
- ],
- ];
- $balances = app('steam')->finalAccountsBalance($accounts, $date);
+ Log::debug(sprintf('Now in byAccounts("%s", "%s")', $ids, $date->format('Y-m-d H:i:s')));
+ $default = Amount::getDefaultCurrency();
+ $netWorth = [];
+ $balances = Steam::finalAccountsBalance($accounts, $date);
/** @var Account $account */
foreach ($accounts as $account) {
- app('log')->debug(sprintf('Now at account #%d ("%s")', $account->id, $account->name));
- $currency = $this->getRepository()->getAccountCurrency($account);
- if (null === $currency) {
- $currency = app('amount')->getDefaultCurrency();
- }
- $currencyCode = $currency->code;
- $balance = '0';
- $nativeBalance = '0';
+ Log::debug(sprintf('Now at account #%d ("%s")', $account->id, $account->name));
+ $currency = $this->getRepository()->getAccountCurrency($account) ?? $default;
+ $useNative = $convertToNative && $default->id !== $currency->id;
+ $currency = $useNative ? $default : $currency;
+ $currencyCode = $currency->code;
+ $balance = '0';
+ $nativeBalance = '0';
if (array_key_exists($account->id, $balances)) {
$balance = $balances[$account->id]['balance'] ?? '0';
$nativeBalance = $balances[$account->id]['native_balance'] ?? '0';
}
- app('log')->debug(sprintf('Balance is %s, native balance is %s', $balance, $nativeBalance));
- // always subtract virtual balance
- $virtualBalance = $account->virtual_balance;
- if ('' !== $virtualBalance) {
- $balance = bcsub($balance, $virtualBalance);
- $nativeVirtualBalance = $converter->convert($default, $currency, $account->created_at, $virtualBalance);
- $nativeBalance = bcsub($nativeBalance, $nativeVirtualBalance);
- }
+ Log::debug(sprintf('Balance is %s, native balance is %s', $balance, $nativeBalance));
+ // always subtract virtual balance again.
+ $balance = '' !== (string) $account->virtual_balance ? bcsub($balance, $account->virtual_balance) : $balance;
+ $nativeBalance = '' !== (string) $account->native_virtual_balance ? bcsub($nativeBalance, $account->native_virtual_balance) : $nativeBalance;
+ $amountToUse = $useNative ? $nativeBalance : $balance;
+ Log::debug(sprintf('Will use %s %s', $currencyCode, $amountToUse));
+
$netWorth[$currencyCode] ??= [
- 'balance' => '0',
- 'native_balance' => '0',
- 'currency_id' => (string) $currency->id,
- 'currency_code' => $currency->code,
- 'currency_name' => $currency->name,
- 'currency_symbol' => $currency->symbol,
- 'currency_decimal_places' => $currency->decimal_places,
- 'native_currency_id' => (string) $default->id,
- 'native_currency_code' => $default->code,
- 'native_currency_name' => $default->name,
- 'native_currency_symbol' => $default->symbol,
- 'native_currency_decimal_places' => $default->decimal_places,
+ 'balance' => '0',
+ 'currency_id' => (string) $currency->id,
+ 'currency_code' => $currency->code,
+ 'currency_name' => $currency->name,
+ 'currency_symbol' => $currency->symbol,
+ 'currency_decimal_places' => $currency->decimal_places,
];
- $netWorth[$currencyCode]['balance'] = bcadd($balance, $netWorth[$currencyCode]['balance']);
- $netWorth[$currencyCode]['native_balance'] = bcadd($nativeBalance, $netWorth[$currencyCode]['native_balance']);
- $netWorth['native']['balance'] = bcadd($nativeBalance, $netWorth['native']['balance']);
- $netWorth['native']['native_balance'] = bcadd($nativeBalance, $netWorth['native']['native_balance']);
+ $netWorth[$currencyCode]['balance'] = bcadd($amountToUse, $netWorth[$currencyCode]['balance']);
}
$cache->store($netWorth);
- $converter->summarize();
return $netWorth;
}
- private function getRepository(): AccountRepositoryInterface|AdminAccountRepositoryInterface
+ private function getRepository(): AccountRepositoryInterface | AdminAccountRepositoryInterface
{
if (null === $this->userGroup) {
return $this->accountRepository;
@@ -154,19 +126,19 @@ class NetWorth implements NetWorthInterface
return $this->adminAccountRepository;
}
- public function setUser(null|Authenticatable|User $user): void
+ public function setUser(null | Authenticatable | User $user): void
{
if (!$user instanceof User) {
return;
}
- $this->user = $user;
- $this->userGroup = null;
+ $this->user = $user;
+ $this->userGroup = null;
// make repository:
$this->accountRepository = app(AccountRepositoryInterface::class);
$this->accountRepository->setUser($this->user);
- $this->currencyRepos = app(CurrencyRepositoryInterface::class);
+ $this->currencyRepos = app(CurrencyRepositoryInterface::class);
$this->currencyRepos->setUser($this->user);
}
@@ -187,18 +159,18 @@ class NetWorth implements NetWorthInterface
*/
$accounts = $this->getAccounts();
$return = [];
- $balances = app('steam')->finalAccountsBalance($accounts, $date);
+ $balances = Steam::finalAccountsBalance($accounts, $date);
foreach ($accounts as $account) {
- $currency = $this->getRepository()->getAccountCurrency($account);
- $balance = $balances[$account->id]['balance'] ?? '0';
+ $currency = $this->getRepository()->getAccountCurrency($account);
+ $balance = $balances[$account->id]['balance'] ?? '0';
// always subtract virtual balance.
- $virtualBalance = $account->virtual_balance;
+ $virtualBalance = $account->virtual_balance;
if ('' !== $virtualBalance) {
$balance = bcsub($balance, $virtualBalance);
}
- $return[$currency->id] ??= [
+ $return[$currency->id] ??= [
'id' => (string) $currency->id,
'name' => $currency->name,
'symbol' => $currency->symbol,
diff --git a/app/Http/Controllers/Json/BoxController.php b/app/Http/Controllers/Json/BoxController.php
index 154160a8bc..58f91c3060 100644
--- a/app/Http/Controllers/Json/BoxController.php
+++ b/app/Http/Controllers/Json/BoxController.php
@@ -29,13 +29,11 @@ use FireflyIII\Helpers\Report\NetWorthInterface;
use FireflyIII\Http\Controllers\Controller;
use FireflyIII\Models\Account;
use FireflyIII\Models\AccountType;
-use FireflyIII\Models\AvailableBudget;
use FireflyIII\Models\TransactionType;
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
-use FireflyIII\Repositories\Budget\AvailableBudgetRepositoryInterface;
-use FireflyIII\Repositories\Budget\OperationsRepositoryInterface;
use FireflyIII\Repositories\UserGroups\Currency\CurrencyRepositoryInterface;
use FireflyIII\Support\CacheProperties;
+use FireflyIII\Support\Facades\Amount;
use FireflyIII\Support\Http\Controllers\DateCalculation;
use Illuminate\Http\JsonResponse;
@@ -48,6 +46,7 @@ class BoxController extends Controller
/**
* Deprecated method, no longer in use.
+ *
* @deprecated
*/
public function available(): JsonResponse
@@ -73,7 +72,7 @@ class BoxController extends Controller
$cache->addProperty($convertToNative);
$cache->addProperty('box-balance');
if ($cache->has()) {
- return response()->json($cache->get());
+ // return response()->json($cache->get());
}
// prep some arrays:
$incomes = [];
@@ -91,9 +90,8 @@ class BoxController extends Controller
/** @var array $journal */
foreach ($set as $journal) {
- $field = $convertToNative && $currency->id !== $journal['currency_id'] ? 'native_amount' : 'amount';
$currencyId = $convertToNative ? $currency->id : (int) $journal['currency_id'];
- $amount = $journal[$field] ?? '0';
+ $amount = Amount::getAmountFromJournal($journal);
$incomes[$currencyId] ??= '0';
$incomes[$currencyId] = bcadd($incomes[$currencyId], app('steam')->positive($amount));
$sums[$currencyId] ??= '0';
@@ -109,9 +107,8 @@ class BoxController extends Controller
/** @var array $journal */
foreach ($set as $journal) {
- $field = $convertToNative && $currency->id !== $journal['currency_id'] ? 'native_amount' : 'amount';
$currencyId = $convertToNative ? $currency->id : (int) $journal['currency_id'];
- $amount = $journal[$field] ?? '0';
+ $amount = Amount::getAmountFromJournal($journal);
$expenses[$currencyId] ??= '0';
$expenses[$currencyId] = bcadd($expenses[$currencyId], $amount);
$sums[$currencyId] ??= '0';
diff --git a/app/Models/Account.php b/app/Models/Account.php
index fcb43a5878..c56940e2ee 100644
--- a/app/Models/Account.php
+++ b/app/Models/Account.php
@@ -61,7 +61,7 @@ class Account extends Model
'virtual_balance' => 'string',
];
- protected $fillable = ['user_id', 'user_group_id', 'account_type_id', 'name', 'active', 'virtual_balance', 'iban'];
+ protected $fillable = ['user_id', 'user_group_id', 'account_type_id', 'name', 'active', 'virtual_balance', 'iban','native_virtual_balance'];
protected $hidden = ['encrypted'];
private bool $joinedAccountTypes = false;
diff --git a/app/Repositories/Bill/BillRepository.php b/app/Repositories/Bill/BillRepository.php
index 0edeb437cf..fb8c0a087e 100644
--- a/app/Repositories/Bill/BillRepository.php
+++ b/app/Repositories/Bill/BillRepository.php
@@ -37,6 +37,7 @@ use FireflyIII\Repositories\ObjectGroup\CreatesObjectGroups;
use FireflyIII\Services\Internal\Destroy\BillDestroyService;
use FireflyIII\Services\Internal\Update\BillUpdateService;
use FireflyIII\Support\CacheProperties;
+use FireflyIII\Support\Facades\Amount;
use FireflyIII\User;
use Illuminate\Contracts\Auth\Authenticatable;
use Illuminate\Database\Query\JoinClause;
@@ -501,6 +502,7 @@ class BillRepository implements BillRepositoryInterface
public function sumPaidInRange(Carbon $start, Carbon $end): array
{
+ Log::debug(sprintf('sumPaidInRange from %s to %s', $start->toW3cString(), $end->toW3cString()));
$bills = $this->getActiveBills();
$return = [];
$convertToNative = app('preferences')->getForUser($this->user, 'convert_to_native', false)->data;
@@ -508,12 +510,11 @@ class BillRepository implements BillRepositoryInterface
/** @var Bill $bill */
foreach ($bills as $bill) {
+
/** @var Collection $set */
- $set = $bill->transactionJournals()->after($start)->before($end)->get(['transaction_journals.*']);
- $currency = $convertToNative && $bill->transactionCurrency->id !== $default->id ? $default : $bill->transactionCurrency;
- $field = $convertToNative && $bill->transactionCurrency->id !== $default->id ? 'native_amount' : 'amount';
- $foreignField = $convertToNative && $bill->transactionCurrency->id !== $default->id ? 'native_foreign_amount' : 'foreign_amount';
- $return[$currency->id] ??= [
+ $set = $bill->transactionJournals()->after($start)->before($end)->get(['transaction_journals.*']);
+ $currency = $convertToNative && $bill->transactionCurrency->id !== $default->id ? $default : $bill->transactionCurrency;
+ $return[(int) $currency->id] ??= [
'id' => (string) $currency->id,
'name' => $currency->name,
'symbol' => $currency->symbol,
@@ -521,20 +522,14 @@ class BillRepository implements BillRepositoryInterface
'decimal_places' => $currency->decimal_places,
'sum' => '0',
];
-
+ $setAmount = '0';
/** @var TransactionJournal $transactionJournal */
foreach ($set as $transactionJournal) {
- /** @var null|Transaction $sourceTransaction */
- $sourceTransaction = $transactionJournal->transactions()->where('amount', '<', 0)->first();
- if (null !== $sourceTransaction) {
- $amount = $sourceTransaction->$field;
- if ((int) $sourceTransaction->foreign_currency_id === $currency->id) {
- // use foreign amount instead!
- $amount = (string) $sourceTransaction->$foreignField;
- }
- $return[$currency->id]['sum'] = bcadd($return[$currency->id]['sum'], $amount);
- }
+ $setAmount = bcadd($setAmount, Amount::getAmountFromJournalObject($transactionJournal));
}
+ Log::debug(sprintf('Bill #%d ("%s") with %d transaction(s) and sum %s %s', $bill->id, $bill->name, $set->count(), $currency->code, $setAmount));
+ $return[$currency->id]['sum'] = bcadd($return[$currency->id]['sum'], $setAmount);
+ Log::debug(sprintf('Total sum is now %s', $return[$currency->id]['sum']));
}
return $return;
@@ -568,6 +563,7 @@ class BillRepository implements BillRepositoryInterface
$minField = $convertToNative && $bill->transactionCurrency->id !== $default->id ? 'native_amount_min' : 'amount_min';
$maxField = $convertToNative && $bill->transactionCurrency->id !== $default->id ? 'native_amount_max' : 'amount_max';
+ Log::debug(sprintf('min field is %s, max field is %s', $minField, $maxField));
if ($total > 0) {
$currency = $convertToNative && $bill->transactionCurrency->id !== $default->id ? $default : $bill->transactionCurrency;
diff --git a/app/Repositories/Budget/OperationsRepository.php b/app/Repositories/Budget/OperationsRepository.php
index 43f5a12d76..e3c49d4b03 100644
--- a/app/Repositories/Budget/OperationsRepository.php
+++ b/app/Repositories/Budget/OperationsRepository.php
@@ -31,9 +31,11 @@ use FireflyIII\Models\Budget;
use FireflyIII\Models\TransactionCurrency;
use FireflyIII\Models\TransactionType;
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
+use FireflyIII\Support\Facades\Amount;
use FireflyIII\User;
use Illuminate\Contracts\Auth\Authenticatable;
use Illuminate\Support\Collection;
+use Illuminate\Support\Facades\Log;
/**
* Class OperationsRepository
@@ -209,11 +211,12 @@ class OperationsRepository implements OperationsRepositoryInterface
?TransactionCurrency $currency = null
): array
{
- // this collector excludes all transfers TO
- // liabilities (which are also withdrawals)
- // because those expenses only become expenses
- // once they move from the liability to the friend.
+ // this collector excludes all transfers TO liabilities (which are also withdrawals)
+ // because those expenses only become expenses once they move from the liability to the friend.
// TODO this filter must be somewhere in AccountRepositoryInterface because I suspect its needed more often (A113)
+
+ // 2024-12-24 disable the exclusion for now.
+
$repository = app(AccountRepositoryInterface::class);
$repository->setUser($this->user);
$subset = $repository->getAccountsByType(config('firefly.valid_liabilities'));
@@ -234,7 +237,7 @@ class OperationsRepository implements OperationsRepositoryInterface
$collector = app(GroupCollectorInterface::class);
$collector->setUser($this->user)
->setRange($start, $end)
- ->excludeDestinationAccounts($selection)
+ // ->excludeDestinationAccounts($selection)
->setTypes([TransactionType::WITHDRAWAL]);
if (null !== $accounts) {
@@ -249,13 +252,12 @@ class OperationsRepository implements OperationsRepositoryInterface
$collector->setBudgets($budgets);
$journals = $collector->getExtractedJournals();
- // same but for foreign currencies:
+ // same but for transactions in the foreign currency:
if (null !== $currency) {
// app('log')->debug(sprintf('Currency is "%s".', $currency->name));
/** @var GroupCollectorInterface $collector */
$collector = app(GroupCollectorInterface::class);
- $collector->setUser($this->user)->setRange($start, $end)->setTypes([TransactionType::WITHDRAWAL])
- ->setForeignCurrency($currency)->setBudgets($budgets);
+ $collector->setUser($this->user)->setRange($start, $end)->setTypes([TransactionType::WITHDRAWAL])->setForeignCurrency($currency)->setBudgets($budgets);
if (null !== $accounts) {
$collector->setAccounts($accounts);
@@ -273,9 +275,9 @@ class OperationsRepository implements OperationsRepositoryInterface
$currencySymbol = $journal['currency_symbol'];
$currencyCode = $journal['currency_code'];
$currencyDecimalPlaces = $journal['currency_decimal_places'];
- $field = 'amount';
- $foreignField = 'foreign_amount';
+
// if the user wants everything in native currency, use it.
+ // if the foreign amount is in this currency it's OK because Amount::getAmountFromJournal catches that.
if ($convertToNative && $default->id !== (int) $journal['currency_id']) {
// use default currency info
$currencyId = $default->id;
@@ -283,8 +285,6 @@ class OperationsRepository implements OperationsRepositoryInterface
$currencySymbol = $default->symbol;
$currencyCode = $default->code;
$currencyDecimalPlaces = $default->decimal_places;
- $field = 'native_amount';
- $foreignField = 'native_foreign_amount';
}
$array[$currencyId] ??= [
'sum' => '0',
@@ -294,21 +294,9 @@ class OperationsRepository implements OperationsRepositoryInterface
'currency_code' => $currencyCode,
'currency_decimal_places' => $currencyDecimalPlaces,
];
- $array[$currencyId]['sum'] = bcadd($array[$currencyId]['sum'], app('steam')->negative($journal[$field]));
-
- // also do foreign amount:
- $foreignId = (int) $journal['foreign_currency_id'];
- if (0 !== $foreignId && $foreignId !== $currencyId) {
- $array[$foreignId] ??= [
- 'sum' => '0',
- 'currency_id' => $foreignId,
- 'currency_name' => $journal['foreign_currency_name'],
- 'currency_symbol' => $journal['foreign_currency_symbol'],
- 'currency_code' => $journal['foreign_currency_code'],
- 'currency_decimal_places' => $journal['foreign_currency_decimal_places'],
- ];
- $array[$foreignId]['sum'] = bcadd($array[$foreignId]['sum'], app('steam')->negative($journal['foreign_amount']));
- }
+ $amount = Amount::getAmountFromJournal($journal);
+ $array[$currencyId]['sum'] = bcadd($array[$currencyId]['sum'], app('steam')->negative($amount));
+ Log::debug(sprintf('Journal #%d adds amount %s %s', $journal['transaction_journal_id'], $currencyCode, $amount));
}
return $array;
diff --git a/app/Support/Amount.php b/app/Support/Amount.php
index cff9e3989d..a185a6c891 100644
--- a/app/Support/Amount.php
+++ b/app/Support/Amount.php
@@ -24,7 +24,9 @@ declare(strict_types=1);
namespace FireflyIII\Support;
use FireflyIII\Exceptions\FireflyException;
+use FireflyIII\Models\Transaction;
use FireflyIII\Models\TransactionCurrency;
+use FireflyIII\Models\TransactionJournal;
use FireflyIII\Models\UserGroup;
use FireflyIII\User;
use Illuminate\Support\Collection;
@@ -45,6 +47,46 @@ class Amount
return $this->formatFlat($format->symbol, $format->decimal_places, $amount, $coloured);
}
+ /**
+ * Experimental function to see if we can quickly and quietly get the amount from a journal.
+ * This depends on the user's default currency and the wish to have it converted.
+ */
+ public function getAmountFromJournal(array $journal): string
+ {
+ $convertToNative = app('preferences')->get('convert_to_native', false)->data;
+ $currency = app('amount')->getDefaultCurrency();
+ $field = $convertToNative && $currency->id !== $journal['currency_id'] ? 'native_amount' : 'amount';
+ $amount = $journal[$field] ?? '0';
+ // fallback, the transaction has a foreign amount in $currency.
+ if ($convertToNative && null !== $journal['foreign_amount'] && $currency->id === $journal['foreign_currency_id']) {
+ $amount = $journal['foreign_amount'];
+ }
+ return $amount;
+ }
+
+ /**
+ * Experimental function to see if we can quickly and quietly get the amount from a journal.
+ * This depends on the user's default currency and the wish to have it converted.
+ */
+ public function getAmountFromJournalObject(TransactionJournal $journal): string
+ {
+ $convertToNative = app('preferences')->get('convert_to_native', false)->data;
+ $currency = app('amount')->getDefaultCurrency();
+ $field = $convertToNative && $currency->id !== $journal->transaction_currency_id ? 'native_amount' : 'amount';
+ /** @var null|Transaction $sourceTransaction */
+ $sourceTransaction = $journal->transactions()->where('amount', '<', 0)->first();
+ if (null === $sourceTransaction) {
+ return '0';
+ }
+ $amount = $sourceTransaction->$field;
+ if ((int) $sourceTransaction->foreign_currency_id === $currency->id) {
+ // use foreign amount instead!
+ $amount = (string) $sourceTransaction->foreign_amount; // hard coded to be foreign amount.
+ }
+ return $amount;
+ }
+
+
/**
* This method will properly format the given number, in color or "black and white",
* as a currency, given two things: the currency required and the current locale.
@@ -55,15 +97,15 @@ class Amount
*/
public function formatFlat(string $symbol, int $decimalPlaces, string $amount, ?bool $coloured = null): string
{
- $locale = app('steam')->getLocale();
- $rounded = app('steam')->bcround($amount, $decimalPlaces);
+ $locale = app('steam')->getLocale();
+ $rounded = app('steam')->bcround($amount, $decimalPlaces);
$coloured ??= true;
- $fmt = new \NumberFormatter($locale, \NumberFormatter::CURRENCY);
+ $fmt = new \NumberFormatter($locale, \NumberFormatter::CURRENCY);
$fmt->setSymbol(\NumberFormatter::CURRENCY_SYMBOL, $symbol);
$fmt->setAttribute(\NumberFormatter::MIN_FRACTION_DIGITS, $decimalPlaces);
$fmt->setAttribute(\NumberFormatter::MAX_FRACTION_DIGITS, $decimalPlaces);
- $result = (string) $fmt->format((float) $rounded); // intentional float
+ $result = (string) $fmt->format((float) $rounded); // intentional float
if (true === $coloured) {
if (1 === bccomp($rounded, '0')) {
@@ -109,7 +151,7 @@ class Amount
public function getDefaultCurrencyByUserGroup(UserGroup $userGroup): TransactionCurrency
{
- $cache = new CacheProperties();
+ $cache = new CacheProperties();
$cache->addProperty('getDefaultCurrencyByGroup');
$cache->addProperty($userGroup->id);
if ($cache->has()) {
@@ -172,20 +214,20 @@ class Amount
private function getLocaleInfo(): array
{
// get config from preference, not from translation:
- $locale = app('steam')->getLocale();
- $array = app('steam')->getLocaleArray($locale);
+ $locale = app('steam')->getLocale();
+ $array = app('steam')->getLocaleArray($locale);
setlocale(LC_MONETARY, $array);
- $info = localeconv();
+ $info = localeconv();
// correct variables
- $info['n_cs_precedes'] = $this->getLocaleField($info, 'n_cs_precedes');
- $info['p_cs_precedes'] = $this->getLocaleField($info, 'p_cs_precedes');
+ $info['n_cs_precedes'] = $this->getLocaleField($info, 'n_cs_precedes');
+ $info['p_cs_precedes'] = $this->getLocaleField($info, 'p_cs_precedes');
- $info['n_sep_by_space'] = $this->getLocaleField($info, 'n_sep_by_space');
- $info['p_sep_by_space'] = $this->getLocaleField($info, 'p_sep_by_space');
+ $info['n_sep_by_space'] = $this->getLocaleField($info, 'n_sep_by_space');
+ $info['p_sep_by_space'] = $this->getLocaleField($info, 'p_sep_by_space');
- $fmt = new \NumberFormatter($locale, \NumberFormatter::CURRENCY);
+ $fmt = new \NumberFormatter($locale, \NumberFormatter::CURRENCY);
$info['mon_decimal_point'] = $fmt->getSymbol(\NumberFormatter::MONETARY_SEPARATOR_SYMBOL);
$info['mon_thousands_sep'] = $fmt->getSymbol(\NumberFormatter::MONETARY_GROUPING_SEPARATOR_SYMBOL);
@@ -208,7 +250,7 @@ class Amount
public static function getAmountJsConfig(bool $sepBySpace, int $signPosn, string $sign, bool $csPrecedes): string
{
// negative first:
- $space = ' ';
+ $space = ' ';
// require space between symbol and amount?
if (false === $sepBySpace) {
@@ -217,11 +259,11 @@ class Amount
// there are five possible positions for the "+" or "-" sign (if it is even used)
// pos_a and pos_e could be the ( and ) symbol.
- $posA = ''; // before everything
- $posB = ''; // before currency symbol
- $posC = ''; // after currency symbol
- $posD = ''; // before amount
- $posE = ''; // after everything
+ $posA = ''; // before everything
+ $posB = ''; // before currency symbol
+ $posC = ''; // after currency symbol
+ $posD = ''; // before amount
+ $posE = ''; // after everything
// format would be (currency before amount)
// AB%sC_D%vE
@@ -263,11 +305,11 @@ class Amount
}
// default is amount before currency
- $format = $posA.$posD.'%v'.$space.$posB.'%s'.$posC.$posE;
+ $format = $posA . $posD . '%v' . $space . $posB . '%s' . $posC . $posE;
if ($csPrecedes) {
// alternative is currency before amount
- $format = $posA.$posB.'%s'.$posC.$space.$posD.'%v'.$posE;
+ $format = $posA . $posB . '%s' . $posC . $space . $posD . '%v' . $posE;
}
return $format;
diff --git a/app/Support/Steam.php b/app/Support/Steam.php
index ca846170c1..70518f43af 100644
--- a/app/Support/Steam.php
+++ b/app/Support/Steam.php
@@ -289,7 +289,7 @@ class Steam
;
$return['native_balance'] = $this->sumTransactions($array, 'native_amount');
// Log::debug(sprintf('native_balance is %s', $return['native_balance']));
- $return['native_balance'] = bcadd('' === (string) $account->native_virtual_balance ? '0' : $account->native_virtual_balance, $return['balance']);
+ $return['native_balance'] = bcadd('' === (string) $account->native_virtual_balance ? '0' : $account->native_virtual_balance, $return['native_balance']);
// Log::debug(sprintf('native_balance is %s (with virtual balance)', $return['native_balance']));
}
diff --git a/public/v1/js/ff/index.js b/public/v1/js/ff/index.js
index 5f963c126a..f053545079 100644
--- a/public/v1/js/ff/index.js
+++ b/public/v1/js/ff/index.js
@@ -26,6 +26,7 @@ $(function () {
});
+
function drawChart() {
"use strict";
lineChart(accountFrontpageUrl, 'accounts-chart');
@@ -37,13 +38,77 @@ function drawChart() {
columnChart('chart/category/frontpage', 'categories-chart');
columnChart(accountExpenseUrl, 'expense-accounts-chart');
columnChart(accountRevenueUrl, 'revenue-accounts-chart');
-
- // get balance box:
- getBalanceBox();
- getBillsBox();
- getAvailableBox();
- getNetWorthBox();
getPiggyBanks();
+ getAllBoxes();
+
+ function getAllBoxes() {
+ // get summary.
+ $.getJSON('api/v1/summary/basic?start=' + sessionStart + '&end=' + sessionEnd).done(function (data) {
+ var key;
+
+ // balance.
+ var balance_top = [];
+ var balance_bottom = [];
+
+ // bills
+ var unpaid = [];
+ var paid = [];
+
+ // left to spend.
+ var left_to_spend_top = [];
+ var left_to_spend_bottom = [];
+
+ // net worth
+ var net_worth = [];
+
+
+ for (key in data) {
+ // balance
+ if (key.substring(0, 11) === 'balance-in-') {
+ balance_top.push(data[key].value_parsed);
+ balance_bottom.push(data[key].sub_title);
+ }
+
+ // bills
+ if (key.substring(0, 16) === 'bills-unpaid-in-') {
+ unpaid.push(data[key].value_parsed);
+ }
+ if (key.substring(0, 14) === 'bills-paid-in-') {
+ paid.push(data[key].value_parsed);
+ }
+
+ // left to spend
+ if (key.substring(0, 17) === 'left-to-spend-in-') {
+ left_to_spend_top.push(data[key].value_parsed);
+ left_to_spend_bottom.push(data[key].sub_title);
+ if(parseFloat(data[key].monetary_value) < 0) {
+ $('#box-left-to-spend-box').removeClass('bg-green-gradient').addClass('bg-red-gradient');
+ }
+ }
+
+ // net worth
+ if (key.substring(0, 13) === 'net-worth-in-') {
+ net_worth.push(data[key].value_parsed);
+ }
+ }
+
+ // balance
+ $('#box-balance-sums').html(balance_top.join(', '));
+ $('#box-balance-list').html(balance_bottom.join(', '));
+
+ // bills
+ $('#box-bills-unpaid').html(unpaid.join(', '));
+ $('#box-bills-paid').html(paid.join(', '));
+
+ // left to spend
+ $('#box-left-to-spend').html(left_to_spend_top.join(', '));
+ $('#box-left-per-day').html(left_to_spend_bottom.join(', '));
+
+ // net worth
+ $('#box-net-worth').html(net_worth.join(', '));
+
+ });
+ }
//getBoxAmounts();
}
@@ -58,121 +123,3 @@ function getPiggyBanks() {
}
});
}
-
-function getNetWorthBox() {
- // box-net-worth
- $.getJSON('json/box/net-worth').done(function (data) {
- $('#box-net-worth').html(data.net_worths.join(', '));
- });
-}
-
-/**
- *
- */
-function getAvailableBox() {
- // box-left-to-spend
- // box-left-per-day
- // * 0) If the user has available amount this period and has overspent: overspent box.
- // * 1) If the user has available amount this period and has NOT overspent: left to spend box.
- // * 2) if the user has no available amount set this period: spent per day
- $.getJSON('json/box/available').done(function (data) {
- $('#box-left-to-spend-text').text(data.title);
- if (0 === data.display) {
- $('#box-left-to-spend-box').removeClass('bg-green-gradient').addClass('bg-red-gradient');
- $('#box-left-to-spend').html(data.left_to_spend);
- $('#box-left-per-day').html(data.left_per_day);
- }
- if (1 === data.display) {
- $('#box-left-to-spend').html(data.left_to_spend);
- $('#box-left-per-day').html(data.left_per_day);
- }
- if (2 === data.display) {
- $('#box-left-to-spend').html(data.spent_total);
- $('#box-left-per-day').html(data.spent_per_day);
- }
- });
-}
-
-/**
- *
- */
-function getBillsBox() {
- // box-bills-unpaid
- // box-bills-paid
-
- // get summary.
-
- $.getJSON('api/v1/summary/basic?start=' + sessionStart + '&end=' + sessionEnd).done(function (data) {
- var key;
- var unpaid = [];
- var paid = [];
- for (key in data) {
- //console.log(key);
- if (key.substr(0, 16) === 'bills-unpaid-in-') {
- // only when less than 3.
- if (unpaid.length < 3) {
- unpaid.push(data[key].value_parsed);
- }
- }
- if (key.substr(0, 14) === 'bills-paid-in-') {
- // only when less than 5.
- if (paid.length < 3) {
- paid.push(data[key].value_parsed);
- }
- }
- }
- $('#box-bills-unpaid').html(unpaid.join(', '));
- $('#box-bills-paid').html(paid.join(', '));
- });
-}
-
-/**
- *
- */
-function getBalanceBox() {
- // box-balance-sums
- // box-balance-list
- $.getJSON('json/box/balance').done(function (data) {
- if (data.size === 1) {
- // show balance in "sums", show single entry in list.
- for (var x in data.sums) {
- $('#box-balance-sums').html(data.sums[x]);
- $('#box-balance-list').html(data.incomes[x] + ' + ' + data.expenses[x]);
- }
- return;
- }
- // do not use "sums", only use list.
- $('#box-balance-progress').remove();
- var expense, string, sum, income, current;
-
- // first loop, echo only "preferred".
- for (x in data.sums) {
- current = $('#box-balance-list').html();
- sum = data.sums[x];
- expense = data.expenses[x];
- income = data.incomes[x];
- string = income + ' + ' + expense + ': ' + sum;
- if (data.preferred == x) {
- $('#box-balance-list').html(current + '' + string + '' + '
');
- }
- }
- // then list the others (only 1 space)
-
- var count = 0;
- for (x in data.sums) {
- if (count > 2) {
- return;
- }
- current = $('#box-balance-list').html();
- sum = data.sums[x];
- expense = data.expenses[x];
- income = data.incomes[x];
- string = income + ' + ' + expense + ': ' + sum;
- if (data.preferred != x) {
- $('#box-balance-list').html(current + '' + string + '' + '
');
- }
- count++;
-
- }
- });
-}
\ No newline at end of file