mirror of
https://github.com/firefly-iii/firefly-iii.git
synced 2025-02-25 18:45:27 -06:00
Expand native amount things.
This commit is contained in:
parent
8805bcf6f6
commit
e8ef630424
@ -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(
|
||||
|
@ -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,
|
||||
|
@ -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';
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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']));
|
||||
}
|
||||
|
||||
|
@ -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 + '<span title="' + string + '">' + string + '</span>' + '<br>');
|
||||
}
|
||||
}
|
||||
// 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 + '<span title="' + string + '">' + string + '</span>' + '<br>');
|
||||
}
|
||||
count++;
|
||||
|
||||
}
|
||||
});
|
||||
}
|
Loading…
Reference in New Issue
Block a user