mirror of
https://github.com/firefly-iii/firefly-iii.git
synced 2025-10-14 16:13:54 +00:00
Convert more charts.
This commit is contained in:
@@ -746,7 +746,7 @@ class GroupCollector implements GroupCollectorInterface
|
|||||||
$currentCollection = $collection;
|
$currentCollection = $collection;
|
||||||
$countFilters = count($this->postFilters);
|
$countFilters = count($this->postFilters);
|
||||||
$countCollection = count($currentCollection);
|
$countCollection = count($currentCollection);
|
||||||
if (0 === $countFilters && 0 === $countCollection) {
|
if (0 === $countFilters) {
|
||||||
return $currentCollection;
|
return $currentCollection;
|
||||||
}
|
}
|
||||||
app('log')->debug(sprintf('GroupCollector: postFilterCollection has %d filter(s) and %d transaction(s).', count($this->postFilters), count($currentCollection)));
|
app('log')->debug(sprintf('GroupCollector: postFilterCollection has %d filter(s) and %d transaction(s).', count($this->postFilters), count($currentCollection)));
|
||||||
|
@@ -36,6 +36,7 @@ use FireflyIII\Models\TransactionType;
|
|||||||
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
|
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
|
||||||
use FireflyIII\Repositories\UserGroups\Currency\CurrencyRepositoryInterface;
|
use FireflyIII\Repositories\UserGroups\Currency\CurrencyRepositoryInterface;
|
||||||
use FireflyIII\Support\CacheProperties;
|
use FireflyIII\Support\CacheProperties;
|
||||||
|
use FireflyIII\Support\Facades\Amount;
|
||||||
use FireflyIII\Support\Facades\Steam;
|
use FireflyIII\Support\Facades\Steam;
|
||||||
use FireflyIII\Support\Http\Controllers\AugumentData;
|
use FireflyIII\Support\Http\Controllers\AugumentData;
|
||||||
use FireflyIII\Support\Http\Controllers\ChartGeneration;
|
use FireflyIII\Support\Http\Controllers\ChartGeneration;
|
||||||
@@ -87,12 +88,14 @@ class AccountController extends Controller
|
|||||||
|
|
||||||
/** @var Carbon $end */
|
/** @var Carbon $end */
|
||||||
$end = clone session('end', today(config('app.timezone'))->endOfMonth());
|
$end = clone session('end', today(config('app.timezone'))->endOfMonth());
|
||||||
|
$convertToNative = app('preferences')->get('convert_to_native', false)->data;
|
||||||
$cache = new CacheProperties();
|
$cache = new CacheProperties();
|
||||||
$cache->addProperty($start);
|
$cache->addProperty($start);
|
||||||
$cache->addProperty($end);
|
$cache->addProperty($end);
|
||||||
|
$cache->addProperty($convertToNative);
|
||||||
$cache->addProperty('chart.account.expense-accounts');
|
$cache->addProperty('chart.account.expense-accounts');
|
||||||
if ($cache->has()) {
|
if ($cache->has()) {
|
||||||
return response()->json($cache->get());
|
// return response()->json($cache->get());
|
||||||
}
|
}
|
||||||
$start->subDay();
|
$start->subDay();
|
||||||
|
|
||||||
@@ -100,6 +103,7 @@ class AccountController extends Controller
|
|||||||
$currencies = [];
|
$currencies = [];
|
||||||
$chartData = [];
|
$chartData = [];
|
||||||
$tempData = [];
|
$tempData = [];
|
||||||
|
$default = Amount::getDefaultCurrency();
|
||||||
|
|
||||||
// grab all accounts and names
|
// grab all accounts and names
|
||||||
$accounts = $this->accountRepository->getAccountsByType([AccountTypeEnum::EXPENSE->value]);
|
$accounts = $this->accountRepository->getAccountsByType([AccountTypeEnum::EXPENSE->value]);
|
||||||
@@ -110,25 +114,43 @@ class AccountController extends Controller
|
|||||||
$endBalances = app('steam')->finalAccountsBalance($accounts, $end);
|
$endBalances = app('steam')->finalAccountsBalance($accounts, $end);
|
||||||
|
|
||||||
// loop the end balances. This is an array for each account ($expenses)
|
// loop the end balances. This is an array for each account ($expenses)
|
||||||
foreach ($endBalances as $accountId => $expenses) {
|
// loop the accounts, then check for balance and currency info.
|
||||||
$accountId = (int) $accountId;
|
foreach($accounts as $account) {
|
||||||
// loop each expense entry (each entry can be a different currency).
|
Log::debug(sprintf('Now in account #%d ("%s")', $account->id, $account->name));
|
||||||
foreach ($expenses as $currencyCode => $endAmount) {
|
$expenses = $endBalances[$account->id] ?? false;
|
||||||
if (3 !== strlen($currencyCode)) {
|
if(false === $expenses) {
|
||||||
|
Log::error(sprintf('Found no end balance for account #%d',$account->id));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* @var string $key
|
||||||
|
* @var string $endBalance
|
||||||
|
*/
|
||||||
|
foreach ($expenses as $key => $endBalance) {
|
||||||
|
if(!$convertToNative && 'native_balance' === $key) {
|
||||||
|
Log::debug(sprintf('[a] Will skip expense array "%s"', $key));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
if($convertToNative && 'native_balance' !== $key) {
|
||||||
|
Log::debug(sprintf('[b] Will skip expense array "%s"', $key));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
Log::debug(sprintf('Will process expense array "%s" with amount %s', $key, $endBalance));
|
||||||
|
$searchCode = $convertToNative ? $default->code: $key;
|
||||||
|
Log::debug(sprintf('Search code is %s', $searchCode));
|
||||||
// see if there is an accompanying start amount.
|
// see if there is an accompanying start amount.
|
||||||
// grab the difference and find the currency.
|
// grab the difference and find the currency.
|
||||||
$startAmount = (string) ($startBalances[$accountId][$currencyCode] ?? '0');
|
$startBalance = ($startBalances[$account->id][$key] ?? '0');
|
||||||
$diff = bcsub((string) $endAmount, $startAmount);
|
Log::debug(sprintf('Start balance is %s', $startBalance));
|
||||||
$currencies[$currencyCode] ??= $this->currencyRepository->findByCode($currencyCode);
|
$diff = bcsub($endBalance, $startBalance);
|
||||||
|
$currencies[$searchCode] ??= $this->currencyRepository->findByCode($searchCode);
|
||||||
if (0 !== bccomp($diff, '0')) {
|
if (0 !== bccomp($diff, '0')) {
|
||||||
// store the values in a temporary array.
|
// store the values in a temporary array.
|
||||||
$tempData[] = [
|
$tempData[] = [
|
||||||
'name' => $accountNames[$accountId],
|
'name' => $accountNames[$account->id],
|
||||||
'difference' => $diff,
|
'difference' => $diff,
|
||||||
'diff_float' => (float) $diff, // intentional float
|
'diff_float' => (float) $diff, // intentional float
|
||||||
'currency_id' => $currencies[$currencyCode]->id,
|
'currency_id' => $currencies[$searchCode]->id,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -140,8 +162,6 @@ class AccountController extends Controller
|
|||||||
}
|
}
|
||||||
$currencies = $newCurrencies;
|
$currencies = $newCurrencies;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// sort temp array by amount.
|
// sort temp array by amount.
|
||||||
$amounts = array_column($tempData, 'diff_float');
|
$amounts = array_column($tempData, 'diff_float');
|
||||||
array_multisort($amounts, SORT_DESC, $tempData);
|
array_multisort($amounts, SORT_DESC, $tempData);
|
||||||
|
@@ -38,10 +38,12 @@ use FireflyIII\Repositories\Budget\NoBudgetRepositoryInterface;
|
|||||||
use FireflyIII\Repositories\Budget\OperationsRepositoryInterface;
|
use FireflyIII\Repositories\Budget\OperationsRepositoryInterface;
|
||||||
use FireflyIII\Support\CacheProperties;
|
use FireflyIII\Support\CacheProperties;
|
||||||
use FireflyIII\Support\Chart\Budget\FrontpageChartGenerator;
|
use FireflyIII\Support\Chart\Budget\FrontpageChartGenerator;
|
||||||
|
use FireflyIII\Support\Facades\Amount;
|
||||||
use FireflyIII\Support\Http\Controllers\AugumentData;
|
use FireflyIII\Support\Http\Controllers\AugumentData;
|
||||||
use FireflyIII\Support\Http\Controllers\DateCalculation;
|
use FireflyIII\Support\Http\Controllers\DateCalculation;
|
||||||
use Illuminate\Http\JsonResponse;
|
use Illuminate\Http\JsonResponse;
|
||||||
use Illuminate\Support\Collection;
|
use Illuminate\Support\Collection;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class BudgetController.
|
* Class BudgetController.
|
||||||
@@ -83,11 +85,11 @@ class BudgetController extends Controller
|
|||||||
public function budget(Budget $budget): JsonResponse
|
public function budget(Budget $budget): JsonResponse
|
||||||
{
|
{
|
||||||
/** @var Carbon $start */
|
/** @var Carbon $start */
|
||||||
$start = $this->repository->firstUseDate($budget) ?? session('start', today(config('app.timezone')));
|
$start = $this->repository->firstUseDate($budget) ?? session('start', today(config('app.timezone')));
|
||||||
|
|
||||||
/** @var Carbon $end */
|
/** @var Carbon $end */
|
||||||
$end = session('end', today(config('app.timezone')));
|
$end = session('end', today(config('app.timezone')));
|
||||||
$cache = new CacheProperties();
|
$cache = new CacheProperties();
|
||||||
$cache->addProperty($start);
|
$cache->addProperty($start);
|
||||||
$cache->addProperty($end);
|
$cache->addProperty($end);
|
||||||
$cache->addProperty('chart.budget.budget');
|
$cache->addProperty('chart.budget.budget');
|
||||||
@@ -105,19 +107,19 @@ class BudgetController extends Controller
|
|||||||
$defaultEntries = [];
|
$defaultEntries = [];
|
||||||
while ($end >= $loopStart) {
|
while ($end >= $loopStart) {
|
||||||
/** @var Carbon $loopEnd */
|
/** @var Carbon $loopEnd */
|
||||||
$loopEnd = app('navigation')->endOfPeriod($loopStart, $step);
|
$loopEnd = app('navigation')->endOfPeriod($loopStart, $step);
|
||||||
$spent = $this->opsRepository->sumExpenses($loopStart, $loopEnd, null, $collection);
|
$spent = $this->opsRepository->sumExpenses($loopStart, $loopEnd, null, $collection);
|
||||||
$label = trim(app('navigation')->periodShow($loopStart, $step));
|
$label = trim(app('navigation')->periodShow($loopStart, $step));
|
||||||
|
|
||||||
foreach ($spent as $row) {
|
foreach ($spent as $row) {
|
||||||
$currencyId = $row['currency_id'];
|
$currencyId = $row['currency_id'];
|
||||||
$currencies[$currencyId] ??= $row; // don't mind the field 'sum'
|
$currencies[$currencyId] ??= $row; // don't mind the field 'sum'
|
||||||
// also store this day's sum:
|
// also store this day's sum:
|
||||||
$currencies[$currencyId]['spent'][$label] = $row['sum'];
|
$currencies[$currencyId]['spent'][$label] = $row['sum'];
|
||||||
}
|
}
|
||||||
$defaultEntries[$label] = 0;
|
$defaultEntries[$label] = 0;
|
||||||
// set loop start to the next period:
|
// set loop start to the next period:
|
||||||
$loopStart = clone $loopEnd;
|
$loopStart = clone $loopEnd;
|
||||||
$loopStart->addSecond();
|
$loopStart->addSecond();
|
||||||
}
|
}
|
||||||
// loop all currencies:
|
// loop all currencies:
|
||||||
@@ -133,7 +135,7 @@ class BudgetController extends Controller
|
|||||||
$chartData[$currencyId]['entries'][$label] = bcmul($spent, '-1');
|
$chartData[$currencyId]['entries'][$label] = bcmul($spent, '-1');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$data = $this->generator->multiSet(array_values($chartData));
|
$data = $this->generator->multiSet(array_values($chartData));
|
||||||
$cache->store($data);
|
$cache->store($data);
|
||||||
|
|
||||||
return response()->json($data);
|
return response()->json($data);
|
||||||
@@ -150,9 +152,9 @@ class BudgetController extends Controller
|
|||||||
throw new FireflyException('This budget limit is not part of this budget.');
|
throw new FireflyException('This budget limit is not part of this budget.');
|
||||||
}
|
}
|
||||||
|
|
||||||
$start = clone $budgetLimit->start_date;
|
$start = clone $budgetLimit->start_date;
|
||||||
$end = clone $budgetLimit->end_date;
|
$end = clone $budgetLimit->end_date;
|
||||||
$cache = new CacheProperties();
|
$cache = new CacheProperties();
|
||||||
$cache->addProperty($start);
|
$cache->addProperty($start);
|
||||||
$cache->addProperty($end);
|
$cache->addProperty($end);
|
||||||
$cache->addProperty('chart.budget.budget.limit');
|
$cache->addProperty('chart.budget.budget.limit');
|
||||||
@@ -162,11 +164,11 @@ class BudgetController extends Controller
|
|||||||
if ($cache->has()) {
|
if ($cache->has()) {
|
||||||
return response()->json($cache->get());
|
return response()->json($cache->get());
|
||||||
}
|
}
|
||||||
$locale = app('steam')->getLocale();
|
$locale = app('steam')->getLocale();
|
||||||
$entries = [];
|
$entries = [];
|
||||||
$amount = $budgetLimit->amount;
|
$amount = $budgetLimit->amount;
|
||||||
$budgetCollection = new Collection([$budget]);
|
$budgetCollection = new Collection([$budget]);
|
||||||
$currency = $budgetLimit->transactionCurrency;
|
$currency = $budgetLimit->transactionCurrency;
|
||||||
while ($start <= $end) {
|
while ($start <= $end) {
|
||||||
$current = clone $start;
|
$current = clone $start;
|
||||||
$expenses = $this->opsRepository->sumExpenses($current, $current, null, $budgetCollection, $currency);
|
$expenses = $this->opsRepository->sumExpenses($current, $current, null, $budgetCollection, $currency);
|
||||||
@@ -177,7 +179,7 @@ class BudgetController extends Controller
|
|||||||
|
|
||||||
$start->addDay();
|
$start->addDay();
|
||||||
}
|
}
|
||||||
$data = $this->generator->singleSet((string) trans('firefly.left'), $entries);
|
$data = $this->generator->singleSet((string) trans('firefly.left'), $entries);
|
||||||
// add currency symbol from budget limit:
|
// add currency symbol from budget limit:
|
||||||
$data['datasets'][0]['currency_symbol'] = $budgetLimit->transactionCurrency->symbol;
|
$data['datasets'][0]['currency_symbol'] = $budgetLimit->transactionCurrency->symbol;
|
||||||
$data['datasets'][0]['currency_code'] = $budgetLimit->transactionCurrency->code;
|
$data['datasets'][0]['currency_code'] = $budgetLimit->transactionCurrency->code;
|
||||||
@@ -198,8 +200,8 @@ class BudgetController extends Controller
|
|||||||
$cache->addProperty($budget->id);
|
$cache->addProperty($budget->id);
|
||||||
$cache->addProperty($budgetLimitId);
|
$cache->addProperty($budgetLimitId);
|
||||||
$cache->addProperty('chart.budget.expense-asset');
|
$cache->addProperty('chart.budget.expense-asset');
|
||||||
$start = session('first', today(config('app.timezone'))->startOfYear());
|
$start = session('first', today(config('app.timezone'))->startOfYear());
|
||||||
$end = today();
|
$end = today();
|
||||||
|
|
||||||
if (null !== $budgetLimit) {
|
if (null !== $budgetLimit) {
|
||||||
$start = $budgetLimit->start_date;
|
$start = $budgetLimit->start_date;
|
||||||
@@ -214,14 +216,14 @@ class BudgetController extends Controller
|
|||||||
}
|
}
|
||||||
$collector->setRange($start, $end);
|
$collector->setRange($start, $end);
|
||||||
$collector->setBudget($budget);
|
$collector->setBudget($budget);
|
||||||
$journals = $collector->getExtractedJournals();
|
$journals = $collector->getExtractedJournals();
|
||||||
$result = [];
|
$result = [];
|
||||||
$chartData = [];
|
$chartData = [];
|
||||||
|
|
||||||
// group by asset account ID:
|
// group by asset account ID:
|
||||||
foreach ($journals as $journal) {
|
foreach ($journals as $journal) {
|
||||||
$key = sprintf('%d-%d', (int) $journal['source_account_id'], $journal['currency_id']);
|
$key = sprintf('%d-%d', (int) $journal['source_account_id'], $journal['currency_id']);
|
||||||
$result[$key] ??= [
|
$result[$key] ??= [
|
||||||
'amount' => '0',
|
'amount' => '0',
|
||||||
'currency_symbol' => $journal['currency_symbol'],
|
'currency_symbol' => $journal['currency_symbol'],
|
||||||
'currency_code' => $journal['currency_code'],
|
'currency_code' => $journal['currency_code'],
|
||||||
@@ -230,20 +232,20 @@ class BudgetController extends Controller
|
|||||||
$result[$key]['amount'] = bcadd($journal['amount'], $result[$key]['amount']);
|
$result[$key]['amount'] = bcadd($journal['amount'], $result[$key]['amount']);
|
||||||
}
|
}
|
||||||
|
|
||||||
$names = $this->getAccountNames(array_keys($result));
|
$names = $this->getAccountNames(array_keys($result));
|
||||||
foreach ($result as $combinedId => $info) {
|
foreach ($result as $combinedId => $info) {
|
||||||
$parts = explode('-', $combinedId);
|
$parts = explode('-', $combinedId);
|
||||||
$assetId = (int) $parts[0];
|
$assetId = (int) $parts[0];
|
||||||
$title = sprintf('%s (%s)', $names[$assetId] ?? '(empty)', $info['currency_name']);
|
$title = sprintf('%s (%s)', $names[$assetId] ?? '(empty)', $info['currency_name']);
|
||||||
$chartData[$title]
|
$chartData[$title]
|
||||||
= [
|
= [
|
||||||
'amount' => $info['amount'],
|
'amount' => $info['amount'],
|
||||||
'currency_symbol' => $info['currency_symbol'],
|
'currency_symbol' => $info['currency_symbol'],
|
||||||
'currency_code' => $info['currency_code'],
|
'currency_code' => $info['currency_code'],
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
$data = $this->generator->multiCurrencyPieChart($chartData);
|
$data = $this->generator->multiCurrencyPieChart($chartData);
|
||||||
$cache->store($data);
|
$cache->store($data);
|
||||||
|
|
||||||
return response()->json($data);
|
return response()->json($data);
|
||||||
@@ -261,8 +263,8 @@ class BudgetController extends Controller
|
|||||||
$cache->addProperty($budget->id);
|
$cache->addProperty($budget->id);
|
||||||
$cache->addProperty($budgetLimitId);
|
$cache->addProperty($budgetLimitId);
|
||||||
$cache->addProperty('chart.budget.expense-category');
|
$cache->addProperty('chart.budget.expense-category');
|
||||||
$start = session('first', today(config('app.timezone'))->startOfYear());
|
$start = session('first', today(config('app.timezone'))->startOfYear());
|
||||||
$end = today();
|
$end = today();
|
||||||
if (null !== $budgetLimit) {
|
if (null !== $budgetLimit) {
|
||||||
$start = $budgetLimit->start_date;
|
$start = $budgetLimit->start_date;
|
||||||
$end = $budgetLimit->end_date;
|
$end = $budgetLimit->end_date;
|
||||||
@@ -276,12 +278,12 @@ class BudgetController extends Controller
|
|||||||
}
|
}
|
||||||
$collector->setRange($start, $end);
|
$collector->setRange($start, $end);
|
||||||
$collector->setBudget($budget)->withCategoryInformation();
|
$collector->setBudget($budget)->withCategoryInformation();
|
||||||
$journals = $collector->getExtractedJournals();
|
$journals = $collector->getExtractedJournals();
|
||||||
$result = [];
|
$result = [];
|
||||||
$chartData = [];
|
$chartData = [];
|
||||||
foreach ($journals as $journal) {
|
foreach ($journals as $journal) {
|
||||||
$key = sprintf('%d-%d', $journal['category_id'], $journal['currency_id']);
|
$key = sprintf('%d-%d', $journal['category_id'], $journal['currency_id']);
|
||||||
$result[$key] ??= [
|
$result[$key] ??= [
|
||||||
'amount' => '0',
|
'amount' => '0',
|
||||||
'currency_symbol' => $journal['currency_symbol'],
|
'currency_symbol' => $journal['currency_symbol'],
|
||||||
'currency_code' => $journal['currency_code'],
|
'currency_code' => $journal['currency_code'],
|
||||||
@@ -290,7 +292,7 @@ class BudgetController extends Controller
|
|||||||
$result[$key]['amount'] = bcadd($journal['amount'], $result[$key]['amount']);
|
$result[$key]['amount'] = bcadd($journal['amount'], $result[$key]['amount']);
|
||||||
}
|
}
|
||||||
|
|
||||||
$names = $this->getCategoryNames(array_keys($result));
|
$names = $this->getCategoryNames(array_keys($result));
|
||||||
foreach ($result as $combinedId => $info) {
|
foreach ($result as $combinedId => $info) {
|
||||||
$parts = explode('-', $combinedId);
|
$parts = explode('-', $combinedId);
|
||||||
$categoryId = (int) $parts[0];
|
$categoryId = (int) $parts[0];
|
||||||
@@ -301,7 +303,7 @@ class BudgetController extends Controller
|
|||||||
'currency_code' => $info['currency_code'],
|
'currency_code' => $info['currency_code'],
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
$data = $this->generator->multiCurrencyPieChart($chartData);
|
$data = $this->generator->multiCurrencyPieChart($chartData);
|
||||||
$cache->store($data);
|
$cache->store($data);
|
||||||
|
|
||||||
return response()->json($data);
|
return response()->json($data);
|
||||||
@@ -319,8 +321,8 @@ class BudgetController extends Controller
|
|||||||
$cache->addProperty($budget->id);
|
$cache->addProperty($budget->id);
|
||||||
$cache->addProperty($budgetLimitId);
|
$cache->addProperty($budgetLimitId);
|
||||||
$cache->addProperty('chart.budget.expense-expense');
|
$cache->addProperty('chart.budget.expense-expense');
|
||||||
$start = session('first', today(config('app.timezone'))->startOfYear());
|
$start = session('first', today(config('app.timezone'))->startOfYear());
|
||||||
$end = today();
|
$end = today();
|
||||||
if (null !== $budgetLimit) {
|
if (null !== $budgetLimit) {
|
||||||
$start = $budgetLimit->start_date;
|
$start = $budgetLimit->start_date;
|
||||||
$end = $budgetLimit->end_date;
|
$end = $budgetLimit->end_date;
|
||||||
@@ -334,14 +336,14 @@ class BudgetController extends Controller
|
|||||||
}
|
}
|
||||||
$collector->setRange($start, $end);
|
$collector->setRange($start, $end);
|
||||||
$collector->setTypes([TransactionType::WITHDRAWAL])->setBudget($budget)->withAccountInformation();
|
$collector->setTypes([TransactionType::WITHDRAWAL])->setBudget($budget)->withAccountInformation();
|
||||||
$journals = $collector->getExtractedJournals();
|
$journals = $collector->getExtractedJournals();
|
||||||
$result = [];
|
$result = [];
|
||||||
$chartData = [];
|
$chartData = [];
|
||||||
|
|
||||||
/** @var array $journal */
|
/** @var array $journal */
|
||||||
foreach ($journals as $journal) {
|
foreach ($journals as $journal) {
|
||||||
$key = sprintf('%d-%d', $journal['destination_account_id'], $journal['currency_id']);
|
$key = sprintf('%d-%d', $journal['destination_account_id'], $journal['currency_id']);
|
||||||
$result[$key] ??= [
|
$result[$key] ??= [
|
||||||
'amount' => '0',
|
'amount' => '0',
|
||||||
'currency_symbol' => $journal['currency_symbol'],
|
'currency_symbol' => $journal['currency_symbol'],
|
||||||
'currency_code' => $journal['currency_code'],
|
'currency_code' => $journal['currency_code'],
|
||||||
@@ -350,7 +352,7 @@ class BudgetController extends Controller
|
|||||||
$result[$key]['amount'] = bcadd($journal['amount'], $result[$key]['amount']);
|
$result[$key]['amount'] = bcadd($journal['amount'], $result[$key]['amount']);
|
||||||
}
|
}
|
||||||
|
|
||||||
$names = $this->getAccountNames(array_keys($result));
|
$names = $this->getAccountNames(array_keys($result));
|
||||||
foreach ($result as $combinedId => $info) {
|
foreach ($result as $combinedId => $info) {
|
||||||
$parts = explode('-', $combinedId);
|
$parts = explode('-', $combinedId);
|
||||||
$opposingId = (int) $parts[0];
|
$opposingId = (int) $parts[0];
|
||||||
@@ -363,7 +365,7 @@ class BudgetController extends Controller
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
$data = $this->generator->multiCurrencyPieChart($chartData);
|
$data = $this->generator->multiCurrencyPieChart($chartData);
|
||||||
$cache->store($data);
|
$cache->store($data);
|
||||||
|
|
||||||
return response()->json($data);
|
return response()->json($data);
|
||||||
@@ -374,25 +376,28 @@ class BudgetController extends Controller
|
|||||||
*/
|
*/
|
||||||
public function frontpage(): JsonResponse
|
public function frontpage(): JsonResponse
|
||||||
{
|
{
|
||||||
$start = session('start', today(config('app.timezone'))->startOfMonth());
|
$start = session('start', today(config('app.timezone'))->startOfMonth());
|
||||||
$end = session('end', today(config('app.timezone'))->endOfMonth());
|
$end = session('end', today(config('app.timezone'))->endOfMonth());
|
||||||
|
$convertToNative = app('preferences')->get('convert_to_native', false)->data;
|
||||||
// chart properties for cache:
|
// chart properties for cache:
|
||||||
$cache = new CacheProperties();
|
$cache = new CacheProperties();
|
||||||
$cache->addProperty($start);
|
$cache->addProperty($start);
|
||||||
$cache->addProperty($end);
|
$cache->addProperty($end);
|
||||||
|
$cache->addProperty($convertToNative);
|
||||||
$cache->addProperty('chart.budget.frontpage');
|
$cache->addProperty('chart.budget.frontpage');
|
||||||
if ($cache->has()) {
|
if ($cache->has()) {
|
||||||
return response()->json($cache->get());
|
// return response()->json($cache->get());
|
||||||
}
|
}
|
||||||
|
Log::debug(sprintf('Regenerate frontpage chart from scratch.'));
|
||||||
$chartGenerator = app(FrontpageChartGenerator::class);
|
$chartGenerator = app(FrontpageChartGenerator::class);
|
||||||
$chartGenerator->setUser(auth()->user());
|
$chartGenerator->setUser(auth()->user());
|
||||||
$chartGenerator->setStart($start);
|
$chartGenerator->setStart($start);
|
||||||
$chartGenerator->setEnd($end);
|
$chartGenerator->setEnd($end);
|
||||||
|
$chartGenerator->convertToNative = $convertToNative;
|
||||||
|
$chartGenerator->default = Amount::getDefaultCurrency();
|
||||||
|
|
||||||
$chartData = $chartGenerator->generate();
|
$chartData = $chartGenerator->generate();
|
||||||
$data = $this->generator->multiSet($chartData);
|
$data = $this->generator->multiSet($chartData);
|
||||||
$cache->store($data);
|
$cache->store($data);
|
||||||
|
|
||||||
return response()->json($data);
|
return response()->json($data);
|
||||||
@@ -408,7 +413,7 @@ class BudgetController extends Controller
|
|||||||
public function period(Budget $budget, TransactionCurrency $currency, Collection $accounts, Carbon $start, Carbon $end): JsonResponse
|
public function period(Budget $budget, TransactionCurrency $currency, Collection $accounts, Carbon $start, Carbon $end): JsonResponse
|
||||||
{
|
{
|
||||||
// chart properties for cache:
|
// chart properties for cache:
|
||||||
$cache = new CacheProperties();
|
$cache = new CacheProperties();
|
||||||
$cache->addProperty($start);
|
$cache->addProperty($start);
|
||||||
$cache->addProperty($end);
|
$cache->addProperty($end);
|
||||||
$cache->addProperty($accounts);
|
$cache->addProperty($accounts);
|
||||||
@@ -437,11 +442,11 @@ class BudgetController extends Controller
|
|||||||
],
|
],
|
||||||
];
|
];
|
||||||
|
|
||||||
$currentStart = clone $start;
|
$currentStart = clone $start;
|
||||||
while ($currentStart <= $end) {
|
while ($currentStart <= $end) {
|
||||||
$currentStart = app('navigation')->startOfPeriod($currentStart, $preferredRange);
|
$currentStart = app('navigation')->startOfPeriod($currentStart, $preferredRange);
|
||||||
$title = $currentStart->isoFormat($titleFormat);
|
$title = $currentStart->isoFormat($titleFormat);
|
||||||
$currentEnd = app('navigation')->endOfPeriod($currentStart, $preferredRange);
|
$currentEnd = app('navigation')->endOfPeriod($currentStart, $preferredRange);
|
||||||
|
|
||||||
// default limit is no limit:
|
// default limit is no limit:
|
||||||
$chartData[0]['entries'][$title] = 0;
|
$chartData[0]['entries'][$title] = 0;
|
||||||
@@ -450,7 +455,7 @@ class BudgetController extends Controller
|
|||||||
$chartData[1]['entries'][$title] = 0;
|
$chartData[1]['entries'][$title] = 0;
|
||||||
|
|
||||||
// get budget limit in this period for this currency.
|
// get budget limit in this period for this currency.
|
||||||
$limit = $this->blRepository->find($budget, $currency, $currentStart, $currentEnd);
|
$limit = $this->blRepository->find($budget, $currency, $currentStart, $currentEnd);
|
||||||
if (null !== $limit) {
|
if (null !== $limit) {
|
||||||
$chartData[1]['entries'][$title] = app('steam')->bcround($limit->amount, $currency->decimal_places);
|
$chartData[1]['entries'][$title] = app('steam')->bcround($limit->amount, $currency->decimal_places);
|
||||||
}
|
}
|
||||||
@@ -460,11 +465,11 @@ class BudgetController extends Controller
|
|||||||
$amount = app('steam')->positive($sum[$currency->id]['sum'] ?? '0');
|
$amount = app('steam')->positive($sum[$currency->id]['sum'] ?? '0');
|
||||||
$chartData[0]['entries'][$title] = app('steam')->bcround($amount, $currency->decimal_places);
|
$chartData[0]['entries'][$title] = app('steam')->bcround($amount, $currency->decimal_places);
|
||||||
|
|
||||||
$currentStart = clone $currentEnd;
|
$currentStart = clone $currentEnd;
|
||||||
$currentStart->addDay()->startOfDay();
|
$currentStart->addDay()->startOfDay();
|
||||||
}
|
}
|
||||||
|
|
||||||
$data = $this->generator->multiSet($chartData);
|
$data = $this->generator->multiSet($chartData);
|
||||||
$cache->store($data);
|
$cache->store($data);
|
||||||
|
|
||||||
return response()->json($data);
|
return response()->json($data);
|
||||||
@@ -476,7 +481,7 @@ class BudgetController extends Controller
|
|||||||
public function periodNoBudget(TransactionCurrency $currency, Collection $accounts, Carbon $start, Carbon $end): JsonResponse
|
public function periodNoBudget(TransactionCurrency $currency, Collection $accounts, Carbon $start, Carbon $end): JsonResponse
|
||||||
{
|
{
|
||||||
// chart properties for cache:
|
// chart properties for cache:
|
||||||
$cache = new CacheProperties();
|
$cache = new CacheProperties();
|
||||||
$cache->addProperty($start);
|
$cache->addProperty($start);
|
||||||
$cache->addProperty($end);
|
$cache->addProperty($end);
|
||||||
$cache->addProperty($accounts);
|
$cache->addProperty($accounts);
|
||||||
@@ -500,7 +505,7 @@ class BudgetController extends Controller
|
|||||||
$currentStart = app('navigation')->addPeriod($currentStart, $preferredRange, 0);
|
$currentStart = app('navigation')->addPeriod($currentStart, $preferredRange, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
$data = $this->generator->singleSet((string) trans('firefly.spent'), $chartData);
|
$data = $this->generator->singleSet((string) trans('firefly.spent'), $chartData);
|
||||||
$cache->store($data);
|
$cache->store($data);
|
||||||
|
|
||||||
return response()->json($data);
|
return response()->json($data);
|
||||||
|
@@ -49,8 +49,7 @@ class CategoryController extends Controller
|
|||||||
use ChartGeneration;
|
use ChartGeneration;
|
||||||
use DateCalculation;
|
use DateCalculation;
|
||||||
|
|
||||||
/** @var GeneratorInterface Chart generation methods. */
|
protected GeneratorInterface $generator;
|
||||||
protected $generator;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* CategoryController constructor.
|
* CategoryController constructor.
|
||||||
@@ -71,7 +70,7 @@ class CategoryController extends Controller
|
|||||||
public function all(Category $category): JsonResponse
|
public function all(Category $category): JsonResponse
|
||||||
{
|
{
|
||||||
// cache results:
|
// cache results:
|
||||||
$cache = new CacheProperties();
|
$cache = new CacheProperties();
|
||||||
$cache->addProperty('chart.category.all');
|
$cache->addProperty('chart.category.all');
|
||||||
$cache->addProperty($category->id);
|
$cache->addProperty($category->id);
|
||||||
if ($cache->has()) {
|
if ($cache->has()) {
|
||||||
@@ -79,11 +78,11 @@ class CategoryController extends Controller
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** @var CategoryRepositoryInterface $repository */
|
/** @var CategoryRepositoryInterface $repository */
|
||||||
$repository = app(CategoryRepositoryInterface::class);
|
$repository = app(CategoryRepositoryInterface::class);
|
||||||
$start = $repository->firstUseDate($category) ?? $this->getDate();
|
$start = $repository->firstUseDate($category) ?? $this->getDate();
|
||||||
$range = app('navigation')->getViewRange(false);
|
$range = app('navigation')->getViewRange(false);
|
||||||
$start = app('navigation')->startOfPeriod($start, $range);
|
$start = app('navigation')->startOfPeriod($start, $range);
|
||||||
$end = $this->getDate();
|
$end = $this->getDate();
|
||||||
|
|
||||||
/** @var WholePeriodChartGenerator $chartGenerator */
|
/** @var WholePeriodChartGenerator $chartGenerator */
|
||||||
$chartGenerator = app(WholePeriodChartGenerator::class);
|
$chartGenerator = app(WholePeriodChartGenerator::class);
|
||||||
@@ -105,15 +104,17 @@ class CategoryController extends Controller
|
|||||||
*/
|
*/
|
||||||
public function frontPage(): JsonResponse
|
public function frontPage(): JsonResponse
|
||||||
{
|
{
|
||||||
$start = session('start', today(config('app.timezone'))->startOfMonth());
|
$start = session('start', today(config('app.timezone'))->startOfMonth());
|
||||||
$end = session('end', today(config('app.timezone'))->endOfMonth());
|
$end = session('end', today(config('app.timezone'))->endOfMonth());
|
||||||
|
$convertToNative = app('preferences')->get('convert_to_native', false)->data;
|
||||||
// chart properties for cache:
|
// chart properties for cache:
|
||||||
$cache = new CacheProperties();
|
$cache = new CacheProperties();
|
||||||
$cache->addProperty($start);
|
$cache->addProperty($start);
|
||||||
$cache->addProperty($end);
|
$cache->addProperty($end);
|
||||||
|
$cache->addProperty($convertToNative);
|
||||||
$cache->addProperty('chart.category.frontpage');
|
$cache->addProperty('chart.category.frontpage');
|
||||||
if ($cache->has()) {
|
if ($cache->has()) {
|
||||||
return response()->json($cache->get());
|
// return response()->json($cache->get());
|
||||||
}
|
}
|
||||||
|
|
||||||
$frontpageGenerator = new FrontpageChartGenerator($start, $end);
|
$frontpageGenerator = new FrontpageChartGenerator($start, $end);
|
||||||
@@ -139,7 +140,7 @@ class CategoryController extends Controller
|
|||||||
if ($cache->has()) {
|
if ($cache->has()) {
|
||||||
return response()->json($cache->get());
|
return response()->json($cache->get());
|
||||||
}
|
}
|
||||||
$data = $this->reportPeriodChart($accounts, $start, $end, $category);
|
$data = $this->reportPeriodChart($accounts, $start, $end, $category);
|
||||||
|
|
||||||
$cache->store($data);
|
$cache->store($data);
|
||||||
|
|
||||||
@@ -160,8 +161,8 @@ class CategoryController extends Controller
|
|||||||
$noCatRepository = app(NoCategoryRepositoryInterface::class);
|
$noCatRepository = app(NoCategoryRepositoryInterface::class);
|
||||||
|
|
||||||
// this gives us all currencies
|
// this gives us all currencies
|
||||||
$expenses = $noCatRepository->listExpenses($start, $end, $accounts);
|
$expenses = $noCatRepository->listExpenses($start, $end, $accounts);
|
||||||
$income = $noCatRepository->listIncome($start, $end, $accounts);
|
$income = $noCatRepository->listIncome($start, $end, $accounts);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (null !== $category) {
|
if (null !== $category) {
|
||||||
@@ -169,9 +170,9 @@ class CategoryController extends Controller
|
|||||||
$opsRepository = app(OperationsRepositoryInterface::class);
|
$opsRepository = app(OperationsRepositoryInterface::class);
|
||||||
$categoryId = $category->id;
|
$categoryId = $category->id;
|
||||||
// this gives us all currencies
|
// this gives us all currencies
|
||||||
$collection = new Collection([$category]);
|
$collection = new Collection([$category]);
|
||||||
$expenses = $opsRepository->listExpenses($start, $end, $accounts, $collection);
|
$expenses = $opsRepository->listExpenses($start, $end, $accounts, $collection);
|
||||||
$income = $opsRepository->listIncome($start, $end, $accounts, $collection);
|
$income = $opsRepository->listIncome($start, $end, $accounts, $collection);
|
||||||
}
|
}
|
||||||
$currencies = array_unique(array_merge(array_keys($income), array_keys($expenses)));
|
$currencies = array_unique(array_merge(array_keys($income), array_keys($expenses)));
|
||||||
$periods = app('navigation')->listOfPeriods($start, $end);
|
$periods = app('navigation')->listOfPeriods($start, $end);
|
||||||
@@ -185,19 +186,19 @@ class CategoryController extends Controller
|
|||||||
$inKey = sprintf('%d-in', $currencyId);
|
$inKey = sprintf('%d-in', $currencyId);
|
||||||
$chartData[$outKey]
|
$chartData[$outKey]
|
||||||
= [
|
= [
|
||||||
'label' => sprintf('%s (%s)', (string) trans('firefly.spent'), $currencyInfo['currency_name']),
|
'label' => sprintf('%s (%s)', (string) trans('firefly.spent'), $currencyInfo['currency_name']),
|
||||||
'entries' => [],
|
'entries' => [],
|
||||||
'type' => 'bar',
|
'type' => 'bar',
|
||||||
'backgroundColor' => 'rgba(219, 68, 55, 0.5)', // red
|
'backgroundColor' => 'rgba(219, 68, 55, 0.5)', // red
|
||||||
];
|
];
|
||||||
|
|
||||||
$chartData[$inKey]
|
$chartData[$inKey]
|
||||||
= [
|
= [
|
||||||
'label' => sprintf('%s (%s)', (string) trans('firefly.earned'), $currencyInfo['currency_name']),
|
'label' => sprintf('%s (%s)', (string) trans('firefly.earned'), $currencyInfo['currency_name']),
|
||||||
'entries' => [],
|
'entries' => [],
|
||||||
'type' => 'bar',
|
'type' => 'bar',
|
||||||
'backgroundColor' => 'rgba(0, 141, 76, 0.5)', // green
|
'backgroundColor' => 'rgba(0, 141, 76, 0.5)', // green
|
||||||
];
|
];
|
||||||
// loop empty periods:
|
// loop empty periods:
|
||||||
foreach (array_keys($periods) as $period) {
|
foreach (array_keys($periods) as $period) {
|
||||||
$label = $periods[$period];
|
$label = $periods[$period];
|
||||||
@@ -205,7 +206,7 @@ class CategoryController extends Controller
|
|||||||
$chartData[$inKey]['entries'][$label] = '0';
|
$chartData[$inKey]['entries'][$label] = '0';
|
||||||
}
|
}
|
||||||
// loop income and expenses for this category.:
|
// loop income and expenses for this category.:
|
||||||
$outSet = $expenses[$currencyId]['categories'][$categoryId] ?? ['transaction_journals' => []];
|
$outSet = $expenses[$currencyId]['categories'][$categoryId] ?? ['transaction_journals' => []];
|
||||||
foreach ($outSet['transaction_journals'] as $journal) {
|
foreach ($outSet['transaction_journals'] as $journal) {
|
||||||
$amount = app('steam')->positive($journal['amount']);
|
$amount = app('steam')->positive($journal['amount']);
|
||||||
$date = $journal['date']->isoFormat($format);
|
$date = $journal['date']->isoFormat($format);
|
||||||
@@ -214,7 +215,7 @@ class CategoryController extends Controller
|
|||||||
$chartData[$outKey]['entries'][$date] = bcadd($amount, $chartData[$outKey]['entries'][$date]);
|
$chartData[$outKey]['entries'][$date] = bcadd($amount, $chartData[$outKey]['entries'][$date]);
|
||||||
}
|
}
|
||||||
|
|
||||||
$inSet = $income[$currencyId]['categories'][$categoryId] ?? ['transaction_journals' => []];
|
$inSet = $income[$currencyId]['categories'][$categoryId] ?? ['transaction_journals' => []];
|
||||||
foreach ($inSet['transaction_journals'] as $journal) {
|
foreach ($inSet['transaction_journals'] as $journal) {
|
||||||
$amount = app('steam')->positive($journal['amount']);
|
$amount = app('steam')->positive($journal['amount']);
|
||||||
$date = $journal['date']->isoFormat($format);
|
$date = $journal['date']->isoFormat($format);
|
||||||
@@ -240,7 +241,7 @@ class CategoryController extends Controller
|
|||||||
if ($cache->has()) {
|
if ($cache->has()) {
|
||||||
return response()->json($cache->get());
|
return response()->json($cache->get());
|
||||||
}
|
}
|
||||||
$data = $this->reportPeriodChart($accounts, $start, $end, null);
|
$data = $this->reportPeriodChart($accounts, $start, $end, null);
|
||||||
|
|
||||||
$cache->store($data);
|
$cache->store($data);
|
||||||
|
|
||||||
@@ -255,14 +256,14 @@ class CategoryController extends Controller
|
|||||||
*/
|
*/
|
||||||
public function specificPeriod(Category $category, Carbon $date): JsonResponse
|
public function specificPeriod(Category $category, Carbon $date): JsonResponse
|
||||||
{
|
{
|
||||||
$range = app('navigation')->getViewRange(false);
|
$range = app('navigation')->getViewRange(false);
|
||||||
$start = app('navigation')->startOfPeriod($date, $range);
|
$start = app('navigation')->startOfPeriod($date, $range);
|
||||||
$end = session()->get('end');
|
$end = session()->get('end');
|
||||||
if ($end < $start) {
|
if ($end < $start) {
|
||||||
[$end, $start] = [$start, $end];
|
[$end, $start] = [$start, $end];
|
||||||
}
|
}
|
||||||
|
|
||||||
$cache = new CacheProperties();
|
$cache = new CacheProperties();
|
||||||
$cache->addProperty($start);
|
$cache->addProperty($start);
|
||||||
$cache->addProperty($end);
|
$cache->addProperty($end);
|
||||||
$cache->addProperty($category->id);
|
$cache->addProperty($category->id);
|
||||||
|
@@ -57,7 +57,7 @@ class BudgetLimit extends Model
|
|||||||
'deleted' => Deleted::class,
|
'deleted' => Deleted::class,
|
||||||
];
|
];
|
||||||
|
|
||||||
protected $fillable = ['budget_id', 'start_date', 'end_date', 'start_date_tz', 'end_date_tz', 'amount', 'transaction_currency_id'];
|
protected $fillable = ['budget_id', 'start_date', 'end_date', 'start_date_tz', 'end_date_tz', 'amount', 'transaction_currency_id','native_amount'];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Route binder. Converts the key in the URL to the specified object (or throw 404).
|
* Route binder. Converts the key in the URL to the specified object (or throw 404).
|
||||||
|
@@ -37,25 +37,25 @@ class TransactionType extends Model
|
|||||||
use ReturnsIntegerIdTrait;
|
use ReturnsIntegerIdTrait;
|
||||||
use SoftDeletes;
|
use SoftDeletes;
|
||||||
|
|
||||||
#[\Deprecated]
|
#[\Deprecated] /** @deprecated */
|
||||||
public const string DEPOSIT = 'Deposit';
|
public const string DEPOSIT = 'Deposit';
|
||||||
|
|
||||||
#[\Deprecated]
|
#[\Deprecated] /** @deprecated */
|
||||||
public const string INVALID = 'Invalid';
|
public const string INVALID = 'Invalid';
|
||||||
|
|
||||||
#[\Deprecated]
|
#[\Deprecated] /** @deprecated */
|
||||||
public const string LIABILITY_CREDIT = 'Liability credit';
|
public const string LIABILITY_CREDIT = 'Liability credit';
|
||||||
|
|
||||||
#[\Deprecated]
|
#[\Deprecated] /** @deprecated */
|
||||||
public const string OPENING_BALANCE = 'Opening balance';
|
public const string OPENING_BALANCE = 'Opening balance';
|
||||||
|
|
||||||
#[\Deprecated]
|
#[\Deprecated] /** @deprecated */
|
||||||
public const string RECONCILIATION = 'Reconciliation';
|
public const string RECONCILIATION = 'Reconciliation';
|
||||||
|
|
||||||
#[\Deprecated]
|
#[\Deprecated] /** @deprecated */
|
||||||
public const string TRANSFER = 'Transfer';
|
public const string TRANSFER = 'Transfer';
|
||||||
|
|
||||||
#[\Deprecated]
|
#[\Deprecated] /** @deprecated */
|
||||||
public const string WITHDRAWAL = 'Withdrawal';
|
public const string WITHDRAWAL = 'Withdrawal';
|
||||||
|
|
||||||
protected $casts
|
protected $casts
|
||||||
|
@@ -211,6 +211,7 @@ class OperationsRepository implements OperationsRepositoryInterface
|
|||||||
?TransactionCurrency $currency = null
|
?TransactionCurrency $currency = null
|
||||||
): array
|
): array
|
||||||
{
|
{
|
||||||
|
Log::debug('Start of sumExpenses.');
|
||||||
// this collector excludes all transfers TO liabilities (which are also withdrawals)
|
// 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.
|
// 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)
|
// TODO this filter must be somewhere in AccountRepositoryInterface because I suspect its needed more often (A113)
|
||||||
@@ -237,7 +238,7 @@ class OperationsRepository implements OperationsRepositoryInterface
|
|||||||
$collector = app(GroupCollectorInterface::class);
|
$collector = app(GroupCollectorInterface::class);
|
||||||
$collector->setUser($this->user)
|
$collector->setUser($this->user)
|
||||||
->setRange($start, $end)
|
->setRange($start, $end)
|
||||||
// ->excludeDestinationAccounts($selection)
|
// ->excludeDestinationAccounts($selection)
|
||||||
->setTypes([TransactionType::WITHDRAWAL]);
|
->setTypes([TransactionType::WITHDRAWAL]);
|
||||||
|
|
||||||
if (null !== $accounts) {
|
if (null !== $accounts) {
|
||||||
@@ -247,6 +248,7 @@ class OperationsRepository implements OperationsRepositoryInterface
|
|||||||
$budgets = $this->getBudgets();
|
$budgets = $this->getBudgets();
|
||||||
}
|
}
|
||||||
if (null !== $currency) {
|
if (null !== $currency) {
|
||||||
|
Log::debug(sprintf('Limit to currency %s', $currency->code));
|
||||||
$collector->setCurrency($currency);
|
$collector->setCurrency($currency);
|
||||||
}
|
}
|
||||||
$collector->setBudgets($budgets);
|
$collector->setBudgets($budgets);
|
||||||
@@ -265,26 +267,47 @@ class OperationsRepository implements OperationsRepositoryInterface
|
|||||||
$result = $collector->getExtractedJournals();
|
$result = $collector->getExtractedJournals();
|
||||||
// app('log')->debug(sprintf('Found %d journals with currency %s.', count($result), $currency->code));
|
// app('log')->debug(sprintf('Found %d journals with currency %s.', count($result), $currency->code));
|
||||||
// do not use array_merge because you want keys to overwrite (otherwise you get double results):
|
// do not use array_merge because you want keys to overwrite (otherwise you get double results):
|
||||||
|
Log::debug(sprintf('Found %d extra journals in foreign currency.', count($result)));
|
||||||
$journals = $result + $journals;
|
$journals = $result + $journals;
|
||||||
}
|
}
|
||||||
$array = [];
|
$array = [];
|
||||||
|
|
||||||
foreach ($journals as $journal) {
|
foreach ($journals as $journal) {
|
||||||
|
// Log::debug(sprintf('Journal #%d.', $journal['transaction_journal_id']));
|
||||||
|
// Log::debug(sprintf('Amounts: %1$s %2$s (amount), %3$s %4$s (foreign_amount), %5$s %6$s (native_amount) %5$s %7$s (foreign native amount)',
|
||||||
|
// $journal['currency_code'], $journal['amount'], $journal['foreign_currency_code'], $journal['foreign_amount'],
|
||||||
|
// $default->code, $journal['native_amount'], $journal['native_foreign_amount'])
|
||||||
|
// );
|
||||||
|
// TODO same as in category::sumexpenses
|
||||||
|
$amount = '0';
|
||||||
$currencyId = (int) $journal['currency_id'];
|
$currencyId = (int) $journal['currency_id'];
|
||||||
$currencyName = $journal['currency_name'];
|
$currencyName = $journal['currency_name'];
|
||||||
$currencySymbol = $journal['currency_symbol'];
|
$currencySymbol = $journal['currency_symbol'];
|
||||||
$currencyCode = $journal['currency_code'];
|
$currencyCode = $journal['currency_code'];
|
||||||
$currencyDecimalPlaces = $journal['currency_decimal_places'];
|
$currencyDecimalPlaces = $journal['currency_decimal_places'];
|
||||||
|
if ($convertToNative) {
|
||||||
// if the user wants everything in native currency, use it.
|
$useNative = $default->id !== (int) $journal['currency_id'];
|
||||||
// if the foreign amount is in this currency it's OK because Amount::getAmountFromJournal catches that.
|
$amount = Amount::getAmountFromJournal($journal);
|
||||||
if ($convertToNative && $default->id !== (int) $journal['currency_id']) {
|
if($useNative) {
|
||||||
// use default currency info
|
$currencyId = $default->id;
|
||||||
$currencyId = $default->id;
|
$currencyName = $default->name;
|
||||||
$currencyName = $default->name;
|
$currencySymbol = $default->symbol;
|
||||||
$currencySymbol = $default->symbol;
|
$currencyCode = $default->code;
|
||||||
$currencyCode = $default->code;
|
$currencyDecimalPlaces = $default->decimal_places;
|
||||||
$currencyDecimalPlaces = $default->decimal_places;
|
}
|
||||||
|
}
|
||||||
|
if (!$convertToNative) {
|
||||||
|
$amount = $journal['amount'];
|
||||||
|
// if the amount is not in $currency (but should be), use the foreign_amount if that one is correct.
|
||||||
|
// otherwise, ignore the transaction all together.
|
||||||
|
if (null !== $currency && $currencyId !== $currency->id && $currency->id === (int) $journal['foreign_currency_id']) {
|
||||||
|
$amount = $journal['foreign_amount'];
|
||||||
|
$currencyId = (int) $journal['foreign_currency_id'];
|
||||||
|
$currencyName = $journal['foreign_currency_name'];
|
||||||
|
$currencySymbol = $journal['foreign_currency_symbol'];
|
||||||
|
$currencyCode = $journal['foreign_currency_code'];
|
||||||
|
$currencyDecimalPlaces = $journal['foreign_currency_decimal_places'];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
$array[$currencyId] ??= [
|
$array[$currencyId] ??= [
|
||||||
'sum' => '0',
|
'sum' => '0',
|
||||||
@@ -294,11 +317,10 @@ class OperationsRepository implements OperationsRepositoryInterface
|
|||||||
'currency_code' => $currencyCode,
|
'currency_code' => $currencyCode,
|
||||||
'currency_decimal_places' => $currencyDecimalPlaces,
|
'currency_decimal_places' => $currencyDecimalPlaces,
|
||||||
];
|
];
|
||||||
$amount = Amount::getAmountFromJournal($journal);
|
|
||||||
$array[$currencyId]['sum'] = bcadd($array[$currencyId]['sum'], app('steam')->negative($amount));
|
$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));
|
Log::debug(sprintf('Journal #%d adds amount %s %s', $journal['transaction_journal_id'], $currencyCode, $amount));
|
||||||
}
|
}
|
||||||
|
Log::debug('End of sumExpenses.', $array);
|
||||||
return $array;
|
return $array;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -27,9 +27,11 @@ namespace FireflyIII\Repositories\Category;
|
|||||||
use Carbon\Carbon;
|
use Carbon\Carbon;
|
||||||
use FireflyIII\Helpers\Collector\GroupCollectorInterface;
|
use FireflyIII\Helpers\Collector\GroupCollectorInterface;
|
||||||
use FireflyIII\Models\TransactionType;
|
use FireflyIII\Models\TransactionType;
|
||||||
|
use FireflyIII\Support\Facades\Amount;
|
||||||
use FireflyIII\User;
|
use FireflyIII\User;
|
||||||
use Illuminate\Contracts\Auth\Authenticatable;
|
use Illuminate\Contracts\Auth\Authenticatable;
|
||||||
use Illuminate\Support\Collection;
|
use Illuminate\Support\Collection;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class NoCategoryRepository
|
* Class NoCategoryRepository
|
||||||
@@ -151,18 +153,46 @@ class NoCategoryRepository implements NoCategoryRepositoryInterface
|
|||||||
}
|
}
|
||||||
$journals = $collector->getExtractedJournals();
|
$journals = $collector->getExtractedJournals();
|
||||||
$array = [];
|
$array = [];
|
||||||
|
// default currency information for native stuff.
|
||||||
|
$convertToNative = app('preferences')->get('convert_to_native', false)->data;
|
||||||
|
$default = app('amount')->getDefaultCurrency();
|
||||||
|
|
||||||
foreach ($journals as $journal) {
|
foreach ($journals as $journal) {
|
||||||
$currencyId = (int) $journal['currency_id'];
|
// Almost the same as in \FireflyIII\Repositories\Budget\OperationsRepository::sumExpenses
|
||||||
$array[$currencyId] ??= [
|
$amount = '0';
|
||||||
|
$currencyId = (int) $journal['currency_id'];
|
||||||
|
$currencyName = $journal['currency_name'];
|
||||||
|
$currencySymbol = $journal['currency_symbol'];
|
||||||
|
$currencyCode = $journal['currency_code'];
|
||||||
|
$currencyDecimalPlaces = $journal['currency_decimal_places'];
|
||||||
|
if ($convertToNative) {
|
||||||
|
$useNative = $default->id !== (int) $journal['currency_id'];
|
||||||
|
$amount = Amount::getAmountFromJournal($journal);
|
||||||
|
if ($useNative) {
|
||||||
|
$currencyId = $default->id;
|
||||||
|
$currencyName = $default->name;
|
||||||
|
$currencySymbol = $default->symbol;
|
||||||
|
$currencyCode = $default->code;
|
||||||
|
$currencyDecimalPlaces = $default->decimal_places;
|
||||||
|
}
|
||||||
|
Log::debug(sprintf('[a] Add amount %s %s', $currencyCode, $amount));
|
||||||
|
}
|
||||||
|
if (!$convertToNative) {
|
||||||
|
// ignore the amount in foreign currency.
|
||||||
|
Log::debug(sprintf('[b] Add amount %s %s', $currencyCode, $journal['amount']));
|
||||||
|
$amount = $journal['amount'];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
$array[$currencyId] ??= [
|
||||||
'sum' => '0',
|
'sum' => '0',
|
||||||
'currency_id' => $currencyId,
|
'currency_id' => (string) $currencyId,
|
||||||
'currency_name' => $journal['currency_name'],
|
'currency_name' => $currencyName,
|
||||||
'currency_symbol' => $journal['currency_symbol'],
|
'currency_symbol' => $currencySymbol,
|
||||||
'currency_code' => $journal['currency_code'],
|
'currency_code' => $currencyCode,
|
||||||
'currency_decimal_places' => $journal['currency_decimal_places'],
|
'currency_decimal_places' => $currencyDecimalPlaces,
|
||||||
];
|
];
|
||||||
$array[$currencyId]['sum'] = bcadd($array[$currencyId]['sum'], app('steam')->negative($journal['amount'] ?? '0'));
|
$array[$currencyId]['sum'] = bcadd($array[$currencyId]['sum'], app('steam')->negative($amount));
|
||||||
}
|
}
|
||||||
|
|
||||||
return $array;
|
return $array;
|
||||||
|
@@ -25,11 +25,14 @@ declare(strict_types=1);
|
|||||||
namespace FireflyIII\Repositories\Category;
|
namespace FireflyIII\Repositories\Category;
|
||||||
|
|
||||||
use Carbon\Carbon;
|
use Carbon\Carbon;
|
||||||
|
use FireflyIII\Enums\TransactionTypeEnum;
|
||||||
use FireflyIII\Helpers\Collector\GroupCollectorInterface;
|
use FireflyIII\Helpers\Collector\GroupCollectorInterface;
|
||||||
use FireflyIII\Models\TransactionType;
|
use FireflyIII\Models\TransactionType;
|
||||||
|
use FireflyIII\Support\Facades\Amount;
|
||||||
use FireflyIII\User;
|
use FireflyIII\User;
|
||||||
use Illuminate\Contracts\Auth\Authenticatable;
|
use Illuminate\Contracts\Auth\Authenticatable;
|
||||||
use Illuminate\Support\Collection;
|
use Illuminate\Support\Collection;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class OperationsRepository
|
* Class OperationsRepository
|
||||||
@@ -60,13 +63,13 @@ class OperationsRepository implements OperationsRepositoryInterface
|
|||||||
$collector->setCategories($this->getCategories());
|
$collector->setCategories($this->getCategories());
|
||||||
}
|
}
|
||||||
$collector->withCategoryInformation()->withAccountInformation()->withBudgetInformation();
|
$collector->withCategoryInformation()->withAccountInformation()->withBudgetInformation();
|
||||||
$journals = $collector->getExtractedJournals();
|
$journals = $collector->getExtractedJournals();
|
||||||
$array = [];
|
$array = [];
|
||||||
|
|
||||||
foreach ($journals as $journal) {
|
foreach ($journals as $journal) {
|
||||||
$currencyId = (int) $journal['currency_id'];
|
$currencyId = (int) $journal['currency_id'];
|
||||||
$categoryId = (int) $journal['category_id'];
|
$categoryId = (int) $journal['category_id'];
|
||||||
$categoryName = (string) $journal['category_name'];
|
$categoryName = (string) $journal['category_name'];
|
||||||
|
|
||||||
// catch "no category" entries.
|
// catch "no category" entries.
|
||||||
if (0 === $categoryId) {
|
if (0 === $categoryId) {
|
||||||
@@ -74,7 +77,7 @@ class OperationsRepository implements OperationsRepositoryInterface
|
|||||||
}
|
}
|
||||||
|
|
||||||
// info about the currency:
|
// info about the currency:
|
||||||
$array[$currencyId] ??= [
|
$array[$currencyId] ??= [
|
||||||
'categories' => [],
|
'categories' => [],
|
||||||
'currency_id' => (string) $currencyId,
|
'currency_id' => (string) $currencyId,
|
||||||
'currency_name' => $journal['currency_name'],
|
'currency_name' => $journal['currency_name'],
|
||||||
@@ -109,7 +112,7 @@ class OperationsRepository implements OperationsRepositoryInterface
|
|||||||
return $array;
|
return $array;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setUser(null|Authenticatable|User $user): void
|
public function setUser(null | Authenticatable | User $user): void
|
||||||
{
|
{
|
||||||
if ($user instanceof User) {
|
if ($user instanceof User) {
|
||||||
$this->user = $user;
|
$this->user = $user;
|
||||||
@@ -144,13 +147,13 @@ class OperationsRepository implements OperationsRepositoryInterface
|
|||||||
$collector->setCategories($this->getCategories());
|
$collector->setCategories($this->getCategories());
|
||||||
}
|
}
|
||||||
$collector->withCategoryInformation()->withAccountInformation();
|
$collector->withCategoryInformation()->withAccountInformation();
|
||||||
$journals = $collector->getExtractedJournals();
|
$journals = $collector->getExtractedJournals();
|
||||||
$array = [];
|
$array = [];
|
||||||
|
|
||||||
foreach ($journals as $journal) {
|
foreach ($journals as $journal) {
|
||||||
$currencyId = (int) $journal['currency_id'];
|
$currencyId = (int) $journal['currency_id'];
|
||||||
$categoryId = (int) $journal['category_id'];
|
$categoryId = (int) $journal['category_id'];
|
||||||
$categoryName = (string) $journal['category_name'];
|
$categoryName = (string) $journal['category_name'];
|
||||||
|
|
||||||
// catch "no category" entries.
|
// catch "no category" entries.
|
||||||
if (0 === $categoryId) {
|
if (0 === $categoryId) {
|
||||||
@@ -158,7 +161,7 @@ class OperationsRepository implements OperationsRepositoryInterface
|
|||||||
}
|
}
|
||||||
|
|
||||||
// info about the currency:
|
// info about the currency:
|
||||||
$array[$currencyId] ??= [
|
$array[$currencyId] ??= [
|
||||||
'categories' => [],
|
'categories' => [],
|
||||||
'currency_id' => (string) $currencyId,
|
'currency_id' => (string) $currencyId,
|
||||||
'currency_name' => $journal['currency_name'],
|
'currency_name' => $journal['currency_name'],
|
||||||
@@ -197,8 +200,7 @@ class OperationsRepository implements OperationsRepositoryInterface
|
|||||||
/** @var GroupCollectorInterface $collector */
|
/** @var GroupCollectorInterface $collector */
|
||||||
$collector = app(GroupCollectorInterface::class);
|
$collector = app(GroupCollectorInterface::class);
|
||||||
$collector->setUser($this->user)->setRange($start, $end)->setTypes([TransactionType::TRANSFER])
|
$collector->setUser($this->user)->setRange($start, $end)->setTypes([TransactionType::TRANSFER])
|
||||||
->setDestinationAccounts($accounts)->excludeSourceAccounts($accounts)
|
->setDestinationAccounts($accounts)->excludeSourceAccounts($accounts);
|
||||||
;
|
|
||||||
if (null !== $categories && $categories->count() > 0) {
|
if (null !== $categories && $categories->count() > 0) {
|
||||||
$collector->setCategories($categories);
|
$collector->setCategories($categories);
|
||||||
}
|
}
|
||||||
@@ -206,13 +208,13 @@ class OperationsRepository implements OperationsRepositoryInterface
|
|||||||
$collector->setCategories($this->getCategories());
|
$collector->setCategories($this->getCategories());
|
||||||
}
|
}
|
||||||
$collector->withCategoryInformation()->withAccountInformation()->withBudgetInformation();
|
$collector->withCategoryInformation()->withAccountInformation()->withBudgetInformation();
|
||||||
$journals = $collector->getExtractedJournals();
|
$journals = $collector->getExtractedJournals();
|
||||||
$array = [];
|
$array = [];
|
||||||
|
|
||||||
foreach ($journals as $journal) {
|
foreach ($journals as $journal) {
|
||||||
$currencyId = (int) $journal['currency_id'];
|
$currencyId = (int) $journal['currency_id'];
|
||||||
$categoryId = (int) $journal['category_id'];
|
$categoryId = (int) $journal['category_id'];
|
||||||
$categoryName = (string) $journal['category_name'];
|
$categoryName = (string) $journal['category_name'];
|
||||||
|
|
||||||
// catch "no category" entries.
|
// catch "no category" entries.
|
||||||
if (0 === $categoryId) {
|
if (0 === $categoryId) {
|
||||||
@@ -220,7 +222,7 @@ class OperationsRepository implements OperationsRepositoryInterface
|
|||||||
}
|
}
|
||||||
|
|
||||||
// info about the currency:
|
// info about the currency:
|
||||||
$array[$currencyId] ??= [
|
$array[$currencyId] ??= [
|
||||||
'categories' => [],
|
'categories' => [],
|
||||||
'currency_id' => (string) $currencyId,
|
'currency_id' => (string) $currencyId,
|
||||||
'currency_name' => $journal['currency_name'],
|
'currency_name' => $journal['currency_name'],
|
||||||
@@ -260,8 +262,7 @@ class OperationsRepository implements OperationsRepositoryInterface
|
|||||||
/** @var GroupCollectorInterface $collector */
|
/** @var GroupCollectorInterface $collector */
|
||||||
$collector = app(GroupCollectorInterface::class);
|
$collector = app(GroupCollectorInterface::class);
|
||||||
$collector->setUser($this->user)->setRange($start, $end)->setTypes([TransactionType::TRANSFER])
|
$collector->setUser($this->user)->setRange($start, $end)->setTypes([TransactionType::TRANSFER])
|
||||||
->setSourceAccounts($accounts)->excludeDestinationAccounts($accounts)
|
->setSourceAccounts($accounts)->excludeDestinationAccounts($accounts);
|
||||||
;
|
|
||||||
if (null !== $categories && $categories->count() > 0) {
|
if (null !== $categories && $categories->count() > 0) {
|
||||||
$collector->setCategories($categories);
|
$collector->setCategories($categories);
|
||||||
}
|
}
|
||||||
@@ -269,13 +270,13 @@ class OperationsRepository implements OperationsRepositoryInterface
|
|||||||
$collector->setCategories($this->getCategories());
|
$collector->setCategories($this->getCategories());
|
||||||
}
|
}
|
||||||
$collector->withCategoryInformation()->withAccountInformation()->withBudgetInformation();
|
$collector->withCategoryInformation()->withAccountInformation()->withBudgetInformation();
|
||||||
$journals = $collector->getExtractedJournals();
|
$journals = $collector->getExtractedJournals();
|
||||||
$array = [];
|
$array = [];
|
||||||
|
|
||||||
foreach ($journals as $journal) {
|
foreach ($journals as $journal) {
|
||||||
$currencyId = (int) $journal['currency_id'];
|
$currencyId = (int) $journal['currency_id'];
|
||||||
$categoryId = (int) $journal['category_id'];
|
$categoryId = (int) $journal['category_id'];
|
||||||
$categoryName = (string) $journal['category_name'];
|
$categoryName = (string) $journal['category_name'];
|
||||||
|
|
||||||
// catch "no category" entries.
|
// catch "no category" entries.
|
||||||
if (0 === $categoryId) {
|
if (0 === $categoryId) {
|
||||||
@@ -283,7 +284,7 @@ class OperationsRepository implements OperationsRepositoryInterface
|
|||||||
}
|
}
|
||||||
|
|
||||||
// info about the currency:
|
// info about the currency:
|
||||||
$array[$currencyId] ??= [
|
$array[$currencyId] ??= [
|
||||||
'categories' => [],
|
'categories' => [],
|
||||||
'currency_id' => (string) $currencyId,
|
'currency_id' => (string) $currencyId,
|
||||||
'currency_name' => $journal['currency_name'],
|
'currency_name' => $journal['currency_name'],
|
||||||
@@ -325,10 +326,11 @@ class OperationsRepository implements OperationsRepositoryInterface
|
|||||||
{
|
{
|
||||||
/** @var GroupCollectorInterface $collector */
|
/** @var GroupCollectorInterface $collector */
|
||||||
$collector = app(GroupCollectorInterface::class);
|
$collector = app(GroupCollectorInterface::class);
|
||||||
$collector->setUser($this->user)->setRange($start, $end)
|
$collector->setUser($this->user)->setRange($start, $end)->setTypes([TransactionTypeEnum::WITHDRAWAL->value]);
|
||||||
->setTypes([TransactionType::WITHDRAWAL])
|
|
||||||
;
|
|
||||||
|
|
||||||
|
// default currency information for native stuff.
|
||||||
|
$convertToNative = app('preferences')->get('convert_to_native', false)->data;
|
||||||
|
$default = app('amount')->getDefaultCurrency();
|
||||||
if (null !== $accounts && $accounts->count() > 0) {
|
if (null !== $accounts && $accounts->count() > 0) {
|
||||||
$collector->setAccounts($accounts);
|
$collector->setAccounts($accounts);
|
||||||
}
|
}
|
||||||
@@ -337,20 +339,47 @@ class OperationsRepository implements OperationsRepositoryInterface
|
|||||||
}
|
}
|
||||||
$collector->setCategories($categories);
|
$collector->setCategories($categories);
|
||||||
$collector->withCategoryInformation();
|
$collector->withCategoryInformation();
|
||||||
$journals = $collector->getExtractedJournals();
|
$journals = $collector->getExtractedJournals();
|
||||||
$array = [];
|
$array = [];
|
||||||
|
|
||||||
|
Log::debug(sprintf('Collected %d journals', count($journals)));
|
||||||
|
|
||||||
foreach ($journals as $journal) {
|
foreach ($journals as $journal) {
|
||||||
$currencyId = (int) $journal['currency_id'];
|
// Almost the same as in \FireflyIII\Repositories\Budget\OperationsRepository::sumExpenses
|
||||||
$array[$currencyId] ??= [
|
$amount = '0';
|
||||||
|
$currencyId = (int) $journal['currency_id'];
|
||||||
|
$currencyName = $journal['currency_name'];
|
||||||
|
$currencySymbol = $journal['currency_symbol'];
|
||||||
|
$currencyCode = $journal['currency_code'];
|
||||||
|
$currencyDecimalPlaces = $journal['currency_decimal_places'];
|
||||||
|
if ($convertToNative) {
|
||||||
|
$useNative = $default->id !== (int) $journal['currency_id'];
|
||||||
|
$amount = Amount::getAmountFromJournal($journal);
|
||||||
|
if ($useNative) {
|
||||||
|
$currencyId = $default->id;
|
||||||
|
$currencyName = $default->name;
|
||||||
|
$currencySymbol = $default->symbol;
|
||||||
|
$currencyCode = $default->code;
|
||||||
|
$currencyDecimalPlaces = $default->decimal_places;
|
||||||
|
}
|
||||||
|
Log::debug(sprintf('[a] Add amount %s %s', $currencyCode, $amount));
|
||||||
|
}
|
||||||
|
if (!$convertToNative) {
|
||||||
|
// ignore the amount in foreign currency.
|
||||||
|
Log::debug(sprintf('[b] Add amount %s %s', $currencyCode, $journal['amount']));
|
||||||
|
$amount = $journal['amount'];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
$array[$currencyId] ??= [
|
||||||
'sum' => '0',
|
'sum' => '0',
|
||||||
'currency_id' => (string) $currencyId,
|
'currency_id' => (string) $currencyId,
|
||||||
'currency_name' => $journal['currency_name'],
|
'currency_name' => $currencyName,
|
||||||
'currency_symbol' => $journal['currency_symbol'],
|
'currency_symbol' => $currencySymbol,
|
||||||
'currency_code' => $journal['currency_code'],
|
'currency_code' => $currencyCode,
|
||||||
'currency_decimal_places' => (int) $journal['currency_decimal_places'],
|
'currency_decimal_places' => $currencyDecimalPlaces,
|
||||||
];
|
];
|
||||||
$array[$currencyId]['sum'] = bcadd($array[$currencyId]['sum'], app('steam')->negative($journal['amount']));
|
$array[$currencyId]['sum'] = bcadd($array[$currencyId]['sum'], app('steam')->negative($amount));
|
||||||
}
|
}
|
||||||
|
|
||||||
return $array;
|
return $array;
|
||||||
@@ -364,8 +393,7 @@ class OperationsRepository implements OperationsRepositoryInterface
|
|||||||
/** @var GroupCollectorInterface $collector */
|
/** @var GroupCollectorInterface $collector */
|
||||||
$collector = app(GroupCollectorInterface::class);
|
$collector = app(GroupCollectorInterface::class);
|
||||||
$collector->setUser($this->user)->setRange($start, $end)
|
$collector->setUser($this->user)->setRange($start, $end)
|
||||||
->setTypes([TransactionType::DEPOSIT])
|
->setTypes([TransactionType::DEPOSIT]);
|
||||||
;
|
|
||||||
|
|
||||||
if (null !== $accounts && $accounts->count() > 0) {
|
if (null !== $accounts && $accounts->count() > 0) {
|
||||||
$collector->setAccounts($accounts);
|
$collector->setAccounts($accounts);
|
||||||
@@ -374,12 +402,12 @@ class OperationsRepository implements OperationsRepositoryInterface
|
|||||||
$categories = $this->getCategories();
|
$categories = $this->getCategories();
|
||||||
}
|
}
|
||||||
$collector->setCategories($categories);
|
$collector->setCategories($categories);
|
||||||
$journals = $collector->getExtractedJournals();
|
$journals = $collector->getExtractedJournals();
|
||||||
$array = [];
|
$array = [];
|
||||||
|
|
||||||
foreach ($journals as $journal) {
|
foreach ($journals as $journal) {
|
||||||
$currencyId = (int) $journal['currency_id'];
|
$currencyId = (int) $journal['currency_id'];
|
||||||
$array[$currencyId] ??= [
|
$array[$currencyId] ??= [
|
||||||
'sum' => '0',
|
'sum' => '0',
|
||||||
'currency_id' => (string) $currencyId,
|
'currency_id' => (string) $currencyId,
|
||||||
'currency_name' => $journal['currency_name'],
|
'currency_name' => $journal['currency_name'],
|
||||||
@@ -401,8 +429,7 @@ class OperationsRepository implements OperationsRepositoryInterface
|
|||||||
/** @var GroupCollectorInterface $collector */
|
/** @var GroupCollectorInterface $collector */
|
||||||
$collector = app(GroupCollectorInterface::class);
|
$collector = app(GroupCollectorInterface::class);
|
||||||
$collector->setUser($this->user)->setRange($start, $end)
|
$collector->setUser($this->user)->setRange($start, $end)
|
||||||
->setTypes([TransactionType::TRANSFER])
|
->setTypes([TransactionType::TRANSFER]);
|
||||||
;
|
|
||||||
|
|
||||||
if (null !== $accounts && $accounts->count() > 0) {
|
if (null !== $accounts && $accounts->count() > 0) {
|
||||||
$collector->setAccounts($accounts);
|
$collector->setAccounts($accounts);
|
||||||
@@ -411,12 +438,12 @@ class OperationsRepository implements OperationsRepositoryInterface
|
|||||||
$categories = $this->getCategories();
|
$categories = $this->getCategories();
|
||||||
}
|
}
|
||||||
$collector->setCategories($categories);
|
$collector->setCategories($categories);
|
||||||
$journals = $collector->getExtractedJournals();
|
$journals = $collector->getExtractedJournals();
|
||||||
$array = [];
|
$array = [];
|
||||||
|
|
||||||
foreach ($journals as $journal) {
|
foreach ($journals as $journal) {
|
||||||
$currencyId = (int) $journal['currency_id'];
|
$currencyId = (int) $journal['currency_id'];
|
||||||
$array[$currencyId] ??= [
|
$array[$currencyId] ??= [
|
||||||
'sum' => '0',
|
'sum' => '0',
|
||||||
'currency_id' => (string) $currencyId,
|
'currency_id' => (string) $currencyId,
|
||||||
'currency_name' => $journal['currency_name'],
|
'currency_name' => $journal['currency_name'],
|
||||||
|
@@ -30,6 +30,7 @@ use FireflyIII\Models\TransactionJournal;
|
|||||||
use FireflyIII\Models\UserGroup;
|
use FireflyIII\Models\UserGroup;
|
||||||
use FireflyIII\User;
|
use FireflyIII\User;
|
||||||
use Illuminate\Support\Collection;
|
use Illuminate\Support\Collection;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class Amount.
|
* Class Amount.
|
||||||
@@ -57,9 +58,11 @@ class Amount
|
|||||||
$currency = app('amount')->getDefaultCurrency();
|
$currency = app('amount')->getDefaultCurrency();
|
||||||
$field = $convertToNative && $currency->id !== $journal['currency_id'] ? 'native_amount' : 'amount';
|
$field = $convertToNative && $currency->id !== $journal['currency_id'] ? 'native_amount' : 'amount';
|
||||||
$amount = $journal[$field] ?? '0';
|
$amount = $journal[$field] ?? '0';
|
||||||
|
//Log::debug(sprintf('Field is %s, amount is %s', $field, $amount));
|
||||||
// fallback, the transaction has a foreign amount in $currency.
|
// fallback, the transaction has a foreign amount in $currency.
|
||||||
if ($convertToNative && null !== $journal['foreign_amount'] && $currency->id === $journal['foreign_currency_id']) {
|
if ($convertToNative && null !== $journal['foreign_amount'] && $currency->id === (int)$journal['foreign_currency_id']) {
|
||||||
$amount = $journal['foreign_amount'];
|
$amount = $journal['foreign_amount'];
|
||||||
|
//Log::debug(sprintf('Overruled, amount is now %s', $amount));
|
||||||
}
|
}
|
||||||
return $amount;
|
return $amount;
|
||||||
}
|
}
|
||||||
|
@@ -26,11 +26,13 @@ namespace FireflyIII\Support\Chart\Budget;
|
|||||||
use Carbon\Carbon;
|
use Carbon\Carbon;
|
||||||
use FireflyIII\Models\Budget;
|
use FireflyIII\Models\Budget;
|
||||||
use FireflyIII\Models\BudgetLimit;
|
use FireflyIII\Models\BudgetLimit;
|
||||||
|
use FireflyIII\Models\TransactionCurrency;
|
||||||
use FireflyIII\Repositories\Budget\BudgetLimitRepositoryInterface;
|
use FireflyIII\Repositories\Budget\BudgetLimitRepositoryInterface;
|
||||||
use FireflyIII\Repositories\Budget\BudgetRepositoryInterface;
|
use FireflyIII\Repositories\Budget\BudgetRepositoryInterface;
|
||||||
use FireflyIII\Repositories\Budget\OperationsRepositoryInterface;
|
use FireflyIII\Repositories\Budget\OperationsRepositoryInterface;
|
||||||
use FireflyIII\User;
|
use FireflyIII\User;
|
||||||
use Illuminate\Support\Collection;
|
use Illuminate\Support\Collection;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class FrontpageChartGenerator
|
* Class FrontpageChartGenerator
|
||||||
@@ -43,6 +45,9 @@ class FrontpageChartGenerator
|
|||||||
private Carbon $end;
|
private Carbon $end;
|
||||||
private string $monthAndDayFormat;
|
private string $monthAndDayFormat;
|
||||||
private Carbon $start;
|
private Carbon $start;
|
||||||
|
public bool $convertToNative = false;
|
||||||
|
public TransactionCurrency $default;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* FrontpageChartGenerator constructor.
|
* FrontpageChartGenerator constructor.
|
||||||
@@ -62,6 +67,7 @@ class FrontpageChartGenerator
|
|||||||
*/
|
*/
|
||||||
public function generate(): array
|
public function generate(): array
|
||||||
{
|
{
|
||||||
|
Log::debug('Now in generate for budget chart.');
|
||||||
$budgets = $this->budgetRepository->getActiveBudgets();
|
$budgets = $this->budgetRepository->getActiveBudgets();
|
||||||
$data = [
|
$data = [
|
||||||
['label' => (string) trans('firefly.spent_in_budget'), 'entries' => [], 'type' => 'bar'],
|
['label' => (string) trans('firefly.spent_in_budget'), 'entries' => [], 'type' => 'bar'],
|
||||||
@@ -74,6 +80,7 @@ class FrontpageChartGenerator
|
|||||||
foreach ($budgets as $budget) {
|
foreach ($budgets as $budget) {
|
||||||
$data = $this->processBudget($data, $budget);
|
$data = $this->processBudget($data, $budget);
|
||||||
}
|
}
|
||||||
|
Log::debug('DONE with generate budget chart.');
|
||||||
|
|
||||||
return $data;
|
return $data;
|
||||||
}
|
}
|
||||||
@@ -85,15 +92,19 @@ class FrontpageChartGenerator
|
|||||||
*/
|
*/
|
||||||
private function processBudget(array $data, Budget $budget): array
|
private function processBudget(array $data, Budget $budget): array
|
||||||
{
|
{
|
||||||
|
Log::debug(sprintf('Now processing budget #%d ("%s")', $budget->id, $budget->name));
|
||||||
// get all limits:
|
// get all limits:
|
||||||
$limits = $this->blRepository->getBudgetLimits($budget, $this->start, $this->end);
|
$limits = $this->blRepository->getBudgetLimits($budget, $this->start, $this->end);
|
||||||
|
Log::debug(sprintf('Found %d limit(s) for budget #%d.', $limits->count(), $budget->id));
|
||||||
// if no limits
|
// if no limits
|
||||||
if (0 === $limits->count()) {
|
if (0 === $limits->count()) {
|
||||||
return $this->noBudgetLimits($data, $budget);
|
$result = $this->noBudgetLimits($data, $budget);
|
||||||
|
Log::debug(sprintf('Now DONE processing budget #%d ("%s")', $budget->id, $budget->name));
|
||||||
|
return $result;
|
||||||
}
|
}
|
||||||
|
$result = $this->budgetLimits($data, $budget, $limits);
|
||||||
return $this->budgetLimits($data, $budget, $limits);
|
Log::debug(sprintf('Now DONE processing budget #%d ("%s")', $budget->id, $budget->name));
|
||||||
|
return $result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -120,10 +131,12 @@ class FrontpageChartGenerator
|
|||||||
*/
|
*/
|
||||||
private function budgetLimits(array $data, Budget $budget, Collection $limits): array
|
private function budgetLimits(array $data, Budget $budget, Collection $limits): array
|
||||||
{
|
{
|
||||||
|
Log::debug('Start processing budget limits.');
|
||||||
/** @var BudgetLimit $limit */
|
/** @var BudgetLimit $limit */
|
||||||
foreach ($limits as $limit) {
|
foreach ($limits as $limit) {
|
||||||
$data = $this->processLimit($data, $budget, $limit);
|
$data = $this->processLimit($data, $budget, $limit);
|
||||||
}
|
}
|
||||||
|
Log::debug('Done processing budget limits.');
|
||||||
|
|
||||||
return $data;
|
return $data;
|
||||||
}
|
}
|
||||||
@@ -134,12 +147,24 @@ class FrontpageChartGenerator
|
|||||||
*/
|
*/
|
||||||
private function processLimit(array $data, Budget $budget, BudgetLimit $limit): array
|
private function processLimit(array $data, Budget $budget, BudgetLimit $limit): array
|
||||||
{
|
{
|
||||||
$spent = $this->opsRepository->sumExpenses($limit->start_date, $limit->end_date, null, new Collection([$budget]), $limit->transactionCurrency);
|
$useNative = $this->convertToNative && $this->default->id !== $limit->transaction_currency_id;
|
||||||
|
$currency = $limit->transactionCurrency;
|
||||||
|
if ($useNative) {
|
||||||
|
Log::debug(sprintf('Processing limit #%d with %s %s', $limit->id, $this->default->code, $limit->native_amount));
|
||||||
|
$currency = null;
|
||||||
|
}
|
||||||
|
if (!$useNative) {
|
||||||
|
Log::debug(sprintf('Processing limit #%d with %s %s', $limit->id, $limit->transactionCurrency->code, $limit->amount));
|
||||||
|
}
|
||||||
|
|
||||||
|
$spent = $this->opsRepository->sumExpenses($limit->start_date, $limit->end_date, null, new Collection([$budget]), $currency);
|
||||||
|
Log::debug(sprintf('Spent array has %d entries.', count($spent)));
|
||||||
/** @var array $entry */
|
/** @var array $entry */
|
||||||
foreach ($spent as $entry) {
|
foreach ($spent as $entry) {
|
||||||
// only spent the entry where the entry's currency matches the budget limit's currency
|
// only spent the entry where the entry's currency matches the budget limit's currency
|
||||||
if ($entry['currency_id'] === $limit->transaction_currency_id) {
|
// or when useNative is true.
|
||||||
|
if ($entry['currency_id'] === $limit->transaction_currency_id || $useNative) {
|
||||||
|
Log::debug(sprintf('Process spent row (%s)', $entry['currency_code']));
|
||||||
$data = $this->processRow($data, $budget, $limit, $entry);
|
$data = $this->processRow($data, $budget, $limit, $entry);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -155,7 +180,7 @@ class FrontpageChartGenerator
|
|||||||
*/
|
*/
|
||||||
private function processRow(array $data, Budget $budget, BudgetLimit $limit, array $entry): array
|
private function processRow(array $data, Budget $budget, BudgetLimit $limit, array $entry): array
|
||||||
{
|
{
|
||||||
$title = sprintf('%s (%s)', $budget->name, $entry['currency_name']);
|
$title = sprintf('%s (%s)', $budget->name, $entry['currency_name']);
|
||||||
if ($limit->start_date->startOfDay()->ne($this->start->startOfDay()) || $limit->end_date->startOfDay()->ne($this->end->startOfDay())) {
|
if ($limit->start_date->startOfDay()->ne($this->start->startOfDay()) || $limit->end_date->startOfDay()->ne($this->end->startOfDay())) {
|
||||||
$title = sprintf(
|
$title = sprintf(
|
||||||
'%s (%s) (%s - %s)',
|
'%s (%s) (%s - %s)',
|
||||||
@@ -165,11 +190,15 @@ class FrontpageChartGenerator
|
|||||||
$limit->end_date->isoFormat($this->monthAndDayFormat)
|
$limit->end_date->isoFormat($this->monthAndDayFormat)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
$sumSpent = bcmul($entry['sum'], '-1'); // spent
|
$sumSpent = bcmul($entry['sum'], '-1'); // spent
|
||||||
|
$data[0]['entries'][$title] ??= '0';
|
||||||
|
$data[1]['entries'][$title] ??= '0';
|
||||||
|
$data[2]['entries'][$title] ??= '0';
|
||||||
|
|
||||||
$data[0]['entries'][$title] = 1 === bccomp($sumSpent, $limit->amount) ? $limit->amount : $sumSpent; // spent
|
|
||||||
$data[1]['entries'][$title] = 1 === bccomp($limit->amount, $sumSpent) ? bcadd($entry['sum'], $limit->amount) : '0'; // left to spent
|
$data[0]['entries'][$title] = bcadd($data[0]['entries'][$title], 1 === bccomp($sumSpent, $limit->amount) ? $limit->amount : $sumSpent); // spent
|
||||||
$data[2]['entries'][$title] = 1 === bccomp($limit->amount, $sumSpent) ? '0' : bcmul(bcadd($entry['sum'], $limit->amount), '-1'); // overspent
|
$data[1]['entries'][$title] = bcadd($data[1]['entries'][$title],1 === bccomp($limit->amount, $sumSpent) ? bcadd($entry['sum'], $limit->amount) : '0'); // left to spent
|
||||||
|
$data[2]['entries'][$title] = bcadd($data[2]['entries'][$title],1 === bccomp($limit->amount, $sumSpent) ? '0' : bcmul(bcadd($entry['sum'], $limit->amount), '-1')); // overspent
|
||||||
|
|
||||||
return $data;
|
return $data;
|
||||||
}
|
}
|
||||||
|
@@ -25,7 +25,7 @@ declare(strict_types=1);
|
|||||||
namespace FireflyIII\Support\Chart\Category;
|
namespace FireflyIII\Support\Chart\Category;
|
||||||
|
|
||||||
use Carbon\Carbon;
|
use Carbon\Carbon;
|
||||||
use FireflyIII\Models\AccountType;
|
use FireflyIII\Enums\AccountTypeEnum;
|
||||||
use FireflyIII\Models\Category;
|
use FireflyIII\Models\Category;
|
||||||
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
|
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
|
||||||
use FireflyIII\Repositories\Category\CategoryRepositoryInterface;
|
use FireflyIII\Repositories\Category\CategoryRepositoryInterface;
|
||||||
@@ -33,6 +33,7 @@ use FireflyIII\Repositories\Category\NoCategoryRepositoryInterface;
|
|||||||
use FireflyIII\Repositories\Category\OperationsRepositoryInterface;
|
use FireflyIII\Repositories\Category\OperationsRepositoryInterface;
|
||||||
use FireflyIII\Support\Http\Controllers\AugumentData;
|
use FireflyIII\Support\Http\Controllers\AugumentData;
|
||||||
use Illuminate\Support\Collection;
|
use Illuminate\Support\Collection;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class FrontpageChartGenerator
|
* Class FrontpageChartGenerator
|
||||||
@@ -65,13 +66,12 @@ class FrontpageChartGenerator
|
|||||||
|
|
||||||
public function generate(): array
|
public function generate(): array
|
||||||
{
|
{
|
||||||
$categories = $this->repository->getCategories();
|
Log::debug('Now in generate()');
|
||||||
$accounts = $this->accountRepos->getAccountsByType(
|
$categories = $this->repository->getCategories();
|
||||||
[AccountType::DEBT, AccountType::LOAN, AccountType::MORTGAGE, AccountType::ASSET, AccountType::DEFAULT]
|
$accounts = $this->accountRepos->getAccountsByType([AccountTypeEnum::DEBT->value, AccountTypeEnum::LOAN->value, AccountTypeEnum::MORTGAGE->value, AccountTypeEnum::ASSET->value, AccountTypeEnum::DEFAULT->value]);
|
||||||
);
|
|
||||||
|
|
||||||
// get expenses + income per category:
|
// get expenses + income per category:
|
||||||
$collection = [];
|
$collection = [];
|
||||||
|
|
||||||
/** @var Category $category */
|
/** @var Category $category */
|
||||||
foreach ($categories as $category) {
|
foreach ($categories as $category) {
|
||||||
@@ -82,10 +82,10 @@ class FrontpageChartGenerator
|
|||||||
// collect for no-category:
|
// collect for no-category:
|
||||||
$collection[] = $this->collectNoCatExpenses($accounts);
|
$collection[] = $this->collectNoCatExpenses($accounts);
|
||||||
|
|
||||||
$tempData = array_merge(...$collection);
|
$tempData = array_merge(...$collection);
|
||||||
|
|
||||||
// sort temp array by amount.
|
// sort temp array by amount.
|
||||||
$amounts = array_column($tempData, 'sum_float');
|
$amounts = array_column($tempData, 'sum_float');
|
||||||
array_multisort($amounts, SORT_ASC, $tempData);
|
array_multisort($amounts, SORT_ASC, $tempData);
|
||||||
|
|
||||||
$currencyData = $this->createCurrencyGroups($tempData);
|
$currencyData = $this->createCurrencyGroups($tempData);
|
||||||
@@ -95,9 +95,11 @@ class FrontpageChartGenerator
|
|||||||
|
|
||||||
private function collectExpenses(Category $category, Collection $accounts): array
|
private function collectExpenses(Category $category, Collection $accounts): array
|
||||||
{
|
{
|
||||||
|
Log::debug(sprintf('Collect expenses for category #%d ("%s")', $category->id, $category->name));
|
||||||
$spent = $this->opsRepos->sumExpenses($this->start, $this->end, $accounts, new Collection([$category]));
|
$spent = $this->opsRepos->sumExpenses($this->start, $this->end, $accounts, new Collection([$category]));
|
||||||
$tempData = [];
|
$tempData = [];
|
||||||
foreach ($spent as $currency) {
|
foreach ($spent as $currency) {
|
||||||
|
Log::debug(sprintf('Spent %s %s', $currency['currency_code'], $currency['sum']));
|
||||||
$this->addCurrency($currency);
|
$this->addCurrency($currency);
|
||||||
$tempData[] = [
|
$tempData[] = [
|
||||||
'name' => $category->name,
|
'name' => $category->name,
|
||||||
|
@@ -46,14 +46,15 @@ trait ChartGeneration
|
|||||||
protected function accountBalanceChart(Collection $accounts, Carbon $start, Carbon $end): array // chart helper method.
|
protected function accountBalanceChart(Collection $accounts, Carbon $start, Carbon $end): array // chart helper method.
|
||||||
{
|
{
|
||||||
// chart properties for cache:
|
// chart properties for cache:
|
||||||
|
$convertToNative = app('preferences')->get('convert_to_native', false)->data;
|
||||||
$cache = new CacheProperties();
|
$cache = new CacheProperties();
|
||||||
$cache->addProperty($start);
|
$cache->addProperty($start);
|
||||||
$cache->addProperty($end);
|
$cache->addProperty($end);
|
||||||
$cache->addProperty('chart.account.account-balance-chart');
|
$cache->addProperty('chart.account.account-balance-chart');
|
||||||
$cache->addProperty($accounts);
|
$cache->addProperty($accounts);
|
||||||
$convertToNative = app('preferences')->get('convert_to_native', false)->data;
|
$cache->addProperty($convertToNative);
|
||||||
if ($cache->has()) {
|
if ($cache->has()) {
|
||||||
// return $cache->get();
|
return $cache->get();
|
||||||
}
|
}
|
||||||
app('log')->debug('Regenerate chart.account.account-balance-chart from scratch.');
|
app('log')->debug('Regenerate chart.account.account-balance-chart from scratch.');
|
||||||
$locale = app('steam')->getLocale();
|
$locale = app('steam')->getLocale();
|
||||||
@@ -69,16 +70,10 @@ trait ChartGeneration
|
|||||||
|
|
||||||
/** @var Account $account */
|
/** @var Account $account */
|
||||||
foreach ($accounts as $account) {
|
foreach ($accounts as $account) {
|
||||||
// TODO we can use getAccountCurrency instead.
|
$currency = $accountRepos->getAccountCurrency($account) ?? $default;
|
||||||
$currency = $accountRepos->getAccountCurrency($account);
|
$useNative = $convertToNative && $default->id !== $currency->id;
|
||||||
if (null === $currency) {
|
$field =$useNative ? 'native_balance' : 'balance';
|
||||||
$currency = $default;
|
$currency = $useNative ? $default : $currency;
|
||||||
}
|
|
||||||
// if the user prefers the native currency, overrule the currency of the account.
|
|
||||||
if ($currency->id !== $default->id && $convertToNative) {
|
|
||||||
$currency = $default;
|
|
||||||
}
|
|
||||||
|
|
||||||
$currentSet = [
|
$currentSet = [
|
||||||
'label' => $account->name,
|
'label' => $account->name,
|
||||||
'currency_symbol' => $currency->symbol,
|
'currency_symbol' => $currency->symbol,
|
||||||
@@ -94,7 +89,7 @@ trait ChartGeneration
|
|||||||
$balance = $range[$format] ?? $previous;
|
$balance = $range[$format] ?? $previous;
|
||||||
$previous = $balance;
|
$previous = $balance;
|
||||||
$currentStart->addDay();
|
$currentStart->addDay();
|
||||||
$currentSet['entries'][$label] = $balance['balance']; // TODO or native_balance
|
$currentSet['entries'][$label] = $balance[$field];
|
||||||
}
|
}
|
||||||
$chartData[] = $currentSet;
|
$chartData[] = $currentSet;
|
||||||
}
|
}
|
||||||
|
@@ -38,8 +38,8 @@ class Steam
|
|||||||
{
|
{
|
||||||
public function getAccountCurrency(Account $account): ?TransactionCurrency
|
public function getAccountCurrency(Account $account): ?TransactionCurrency
|
||||||
{
|
{
|
||||||
$type = $account->accountType->type;
|
$type = $account->accountType->type;
|
||||||
$list = config('firefly.valid_currency_account_types');
|
$list = config('firefly.valid_currency_account_types');
|
||||||
|
|
||||||
// return null if not in this list.
|
// return null if not in this list.
|
||||||
if (!in_array($type, $list, true)) {
|
if (!in_array($type, $list, true)) {
|
||||||
@@ -74,7 +74,7 @@ class Steam
|
|||||||
$end->addDay()->endOfDay();
|
$end->addDay()->endOfDay();
|
||||||
|
|
||||||
// set up cache
|
// set up cache
|
||||||
$cache = new CacheProperties();
|
$cache = new CacheProperties();
|
||||||
$cache->addProperty($account->id);
|
$cache->addProperty($account->id);
|
||||||
$cache->addProperty('final-balance-in-range');
|
$cache->addProperty('final-balance-in-range');
|
||||||
$cache->addProperty($start);
|
$cache->addProperty($start);
|
||||||
@@ -83,52 +83,51 @@ class Steam
|
|||||||
// return $cache->get();
|
// return $cache->get();
|
||||||
}
|
}
|
||||||
|
|
||||||
$balances = [];
|
$balances = [];
|
||||||
$formatted = $start->format('Y-m-d');
|
$formatted = $start->format('Y-m-d');
|
||||||
$startBalance = $this->finalAccountBalance($account, $start);
|
$startBalance = $this->finalAccountBalance($account, $start);
|
||||||
$defaultCurrency = app('amount')->getDefaultCurrencyByUserGroup($account->user->userGroup);
|
$defaultCurrency = app('amount')->getDefaultCurrencyByUserGroup($account->user->userGroup);
|
||||||
$currency = $this->getAccountCurrency($account) ?? $defaultCurrency;
|
$currency = $this->getAccountCurrency($account) ?? $defaultCurrency;
|
||||||
$currencies = [
|
$currencies = [
|
||||||
$currency->id => $currency,
|
$currency->id => $currency,
|
||||||
$defaultCurrency->id => $defaultCurrency,
|
$defaultCurrency->id => $defaultCurrency,
|
||||||
];
|
];
|
||||||
$startBalance[$defaultCurrency->code] ??= '0';
|
$startBalance[$defaultCurrency->code] ??= '0';
|
||||||
$startBalance[$currency->code] ??= '0';
|
$startBalance[$currency->code] ??= '0';
|
||||||
$balances[$formatted] = $startBalance;
|
$balances[$formatted] = $startBalance;
|
||||||
|
|
||||||
|
|
||||||
// sums up the balance changes per day, for foreign, native and normal amounts.
|
// sums up the balance changes per day, for foreign, native and normal amounts.
|
||||||
$set = $account->transactions()
|
$set = $account->transactions()
|
||||||
->leftJoin('transaction_journals', 'transactions.transaction_journal_id', '=', 'transaction_journals.id')
|
->leftJoin('transaction_journals', 'transactions.transaction_journal_id', '=', 'transaction_journals.id')
|
||||||
->where('transaction_journals.date', '>=', $start->format('Y-m-d H:i:s'))
|
->where('transaction_journals.date', '>=', $start->format('Y-m-d H:i:s'))
|
||||||
->where('transaction_journals.date', '<=', $end->format('Y-m-d H:i:s'))
|
->where('transaction_journals.date', '<=', $end->format('Y-m-d H:i:s'))
|
||||||
->groupBy('transaction_journals.date')
|
->groupBy('transaction_journals.date')
|
||||||
->groupBy('transactions.transaction_currency_id')
|
->groupBy('transactions.transaction_currency_id')
|
||||||
->groupBy('transactions.foreign_currency_id')
|
->groupBy('transactions.foreign_currency_id')
|
||||||
->orderBy('transaction_journals.date', 'ASC')
|
->orderBy('transaction_journals.date', 'ASC')
|
||||||
->whereNull('transaction_journals.deleted_at')
|
->whereNull('transaction_journals.deleted_at')
|
||||||
->get(
|
->get(
|
||||||
[ // @phpstan-ignore-line
|
[ // @phpstan-ignore-line
|
||||||
'transaction_journals.date',
|
'transaction_journals.date',
|
||||||
'transactions.transaction_currency_id',
|
'transactions.transaction_currency_id',
|
||||||
\DB::raw('SUM(transactions.amount) AS modified'),
|
\DB::raw('SUM(transactions.amount) AS modified'),
|
||||||
'transactions.foreign_currency_id',
|
'transactions.foreign_currency_id',
|
||||||
\DB::raw('SUM(transactions.foreign_amount) AS modified_foreign'),
|
\DB::raw('SUM(transactions.foreign_amount) AS modified_foreign'),
|
||||||
\DB::raw('SUM(transactions.native_amount) AS modified_native'),
|
\DB::raw('SUM(transactions.native_amount) AS modified_native'),
|
||||||
]
|
]
|
||||||
)
|
);
|
||||||
;
|
|
||||||
|
|
||||||
$currentBalance = $startBalance;
|
$currentBalance = $startBalance;
|
||||||
|
|
||||||
/** @var Transaction $entry */
|
/** @var Transaction $entry */
|
||||||
foreach ($set as $entry) {
|
foreach ($set as $entry) {
|
||||||
|
|
||||||
// normal, native and foreign amount
|
// normal, native and foreign amount
|
||||||
$carbon = new Carbon($entry->date, $entry->date_tz);
|
$carbon = new Carbon($entry->date, $entry->date_tz);
|
||||||
$modified = (string) (null === $entry->modified ? '0' : $entry->modified);
|
$modified = (string) (null === $entry->modified ? '0' : $entry->modified);
|
||||||
$foreignModified = (string) (null === $entry->modified_foreign ? '0' : $entry->modified_foreign);
|
$foreignModified = (string) (null === $entry->modified_foreign ? '0' : $entry->modified_foreign);
|
||||||
$nativeModified = (string) (null === $entry->modified_native ? '0' : $entry->modified_native);
|
$nativeModified = (string) (null === $entry->modified_native ? '0' : $entry->modified_native);
|
||||||
|
|
||||||
// add "modified" to amount if the currency id matches the account currency id.
|
// add "modified" to amount if the currency id matches the account currency id.
|
||||||
if ($entry->transaction_currency_id === $currency->id) {
|
if ($entry->transaction_currency_id === $currency->id) {
|
||||||
@@ -137,7 +136,7 @@ class Steam
|
|||||||
}
|
}
|
||||||
|
|
||||||
// always add the native balance, even if it ends up at zero.
|
// always add the native balance, even if it ends up at zero.
|
||||||
$currentBalance['native_balance'] = bcadd($currentBalance['native_balance'], $nativeModified);
|
$currentBalance['native_balance'] = bcadd($currentBalance['native_balance'], $nativeModified);
|
||||||
|
|
||||||
// add modified foreign to the array
|
// add modified foreign to the array
|
||||||
if (null !== $entry->foreign_currency_id) {
|
if (null !== $entry->foreign_currency_id) {
|
||||||
@@ -183,10 +182,10 @@ class Steam
|
|||||||
// Log::debug(sprintf('Trying bcround("%s",%d)', $number, $precision));
|
// Log::debug(sprintf('Trying bcround("%s",%d)', $number, $precision));
|
||||||
if (str_contains($number, '.')) {
|
if (str_contains($number, '.')) {
|
||||||
if ('-' !== $number[0]) {
|
if ('-' !== $number[0]) {
|
||||||
return bcadd($number, '0.'.str_repeat('0', $precision).'5', $precision);
|
return bcadd($number, '0.' . str_repeat('0', $precision) . '5', $precision);
|
||||||
}
|
}
|
||||||
|
|
||||||
return bcsub($number, '0.'.str_repeat('0', $precision).'5', $precision);
|
return bcsub($number, '0.' . str_repeat('0', $precision) . '5', $precision);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $number;
|
return $number;
|
||||||
@@ -261,47 +260,60 @@ class Steam
|
|||||||
*/
|
*/
|
||||||
public function finalAccountBalance(Account $account, Carbon $date): array
|
public function finalAccountBalance(Account $account, Carbon $date): array
|
||||||
{
|
{
|
||||||
$native = app('amount')->getDefaultCurrencyByUserGroup($account->user->userGroup);
|
$native = app('amount')->getDefaultCurrencyByUserGroup($account->user->userGroup);
|
||||||
$currency = $this->getAccountCurrency($account) ?? $native;
|
$accountCurrency = $this->getAccountCurrency($account);
|
||||||
$return = [
|
$hasCurrency = null !== $accountCurrency;
|
||||||
|
$currency = $accountCurrency ?? $native;
|
||||||
|
if (!$hasCurrency) {
|
||||||
|
Log::debug('Gave account fake currency.');
|
||||||
|
// fake currency
|
||||||
|
$native = new TransactionCurrency();
|
||||||
|
}
|
||||||
|
$return = [
|
||||||
'native_balance' => '0',
|
'native_balance' => '0',
|
||||||
];
|
];
|
||||||
Log::debug(sprintf('Now in finalAccountBalance("%s", "%s")', $account->name, $date->format('Y-m-d H:i:s')));
|
Log::debug(sprintf('Now in finalAccountBalance("%s", "%s")', $account->name, $date->format('Y-m-d H:i:s')));
|
||||||
// first, the "balance", as described earlier.
|
// first, the "balance", as described earlier.
|
||||||
$array = $account->transactions()
|
$array = $account->transactions()
|
||||||
->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id')
|
->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id')
|
||||||
->where('transaction_journals.date', '<=', $date->format('Y-m-d H:i:s'))
|
->where('transaction_journals.date', '<=', $date->format('Y-m-d H:i:s'))
|
||||||
->where('transactions.transaction_currency_id', $currency->id)
|
->where('transactions.transaction_currency_id', $currency->id)
|
||||||
->get(['transactions.amount'])->toArray()
|
->get(['transactions.amount'])->toArray();
|
||||||
;
|
|
||||||
$return['balance'] = $this->sumTransactions($array, 'amount');
|
$return['balance'] = $this->sumTransactions($array, 'amount');
|
||||||
// Log::debug(sprintf('balance is %s', $return['balance']));
|
//Log::debug(sprintf('balance is %s', $return['balance']));
|
||||||
// add virtual balance:
|
// add virtual balance:
|
||||||
$return['balance'] = bcadd('' === (string) $account->virtual_balance ? '0' : $account->virtual_balance, $return['balance']);
|
$return['balance'] = bcadd('' === (string) $account->virtual_balance ? '0' : $account->virtual_balance, $return['balance']);
|
||||||
// Log::debug(sprintf('balance is %s (with virtual balance)', $return['balance']));
|
Log::debug(sprintf('balance is %s (with virtual balance)', $return['balance']));
|
||||||
|
|
||||||
// then, native balance (if necessary(
|
// then, native balance (if necessary(
|
||||||
if ($native->id !== $currency->id) {
|
if ($native->id !== $currency->id) {
|
||||||
|
Log::debug('Will grab native balance for transactions on this account.');
|
||||||
$array = $account->transactions()
|
$array = $account->transactions()
|
||||||
->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id')
|
->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id')
|
||||||
->where('transaction_journals.date', '<=', $date->format('Y-m-d H:i:s'))
|
->where('transaction_journals.date', '<=', $date->format('Y-m-d H:i:s'))
|
||||||
->get(['transactions.native_amount'])->toArray()
|
->get(['transactions.native_amount'])->toArray();
|
||||||
;
|
|
||||||
$return['native_balance'] = $this->sumTransactions($array, 'native_amount');
|
$return['native_balance'] = $this->sumTransactions($array, 'native_amount');
|
||||||
// Log::debug(sprintf('native_balance is %s', $return['native_balance']));
|
// 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['native_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']));
|
Log::debug(sprintf('native_balance is %s (with virtual balance)', $return['native_balance']));
|
||||||
}
|
}
|
||||||
|
|
||||||
// balance(s) in other currencies.
|
// balance(s) in other currencies.
|
||||||
$array = $account->transactions()
|
$array = $account->transactions()
|
||||||
->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id')
|
->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id')
|
||||||
->leftJoin('transaction_currencies', 'transaction_currencies.id', '=', 'transactions.transaction_currency_id')
|
->leftJoin('transaction_currencies', 'transaction_currencies.id', '=', 'transactions.transaction_currency_id')
|
||||||
->where('transaction_journals.date', '<=', $date->format('Y-m-d H:i:s'))
|
->where('transaction_journals.date', '<=', $date->format('Y-m-d H:i:s'))
|
||||||
->get(['transaction_currencies.code', 'transactions.amount'])->toArray()
|
->get(['transaction_currencies.code', 'transactions.amount'])->toArray();
|
||||||
;
|
$others = $this->groupAndSumTransactions($array, 'code', 'amount');
|
||||||
$others = $this->groupAndSumTransactions($array, 'code', 'amount');
|
|
||||||
// Log::debug('All others are (joined)', $others);
|
// if the account has no own currency preference, drop balance in favor of native balance
|
||||||
|
if (!$hasCurrency) {
|
||||||
|
Log::debug('Account has no currency preference, dropping balance in favor of native balance.');
|
||||||
|
$return['native_balance'] = bcadd($return['balance'], $return['native_balance']);
|
||||||
|
unset($return['balance']);
|
||||||
|
}
|
||||||
|
|
||||||
|
Log::debug('All others are (joined)', $others);
|
||||||
|
|
||||||
return array_merge($return, $others);
|
return array_merge($return, $others);
|
||||||
}
|
}
|
||||||
@@ -343,17 +355,17 @@ class Steam
|
|||||||
{
|
{
|
||||||
$list = [];
|
$list = [];
|
||||||
|
|
||||||
$set = auth()->user()->transactions()
|
$set = auth()->user()->transactions()
|
||||||
->whereIn('transactions.account_id', $accounts)
|
->whereIn('transactions.account_id', $accounts)
|
||||||
->groupBy(['transactions.account_id', 'transaction_journals.user_id'])
|
->groupBy(['transactions.account_id', 'transaction_journals.user_id'])
|
||||||
->get(['transactions.account_id', \DB::raw('MAX(transaction_journals.date) AS max_date')]) // @phpstan-ignore-line
|
->get(['transactions.account_id', \DB::raw('MAX(transaction_journals.date) AS max_date')]) // @phpstan-ignore-line
|
||||||
;
|
;
|
||||||
|
|
||||||
/** @var Transaction $entry */
|
/** @var Transaction $entry */
|
||||||
foreach ($set as $entry) {
|
foreach ($set as $entry) {
|
||||||
$date = new Carbon($entry->max_date, config('app.timezone'));
|
$date = new Carbon($entry->max_date, config('app.timezone'));
|
||||||
$date->setTimezone(config('app.timezone'));
|
$date->setTimezone(config('app.timezone'));
|
||||||
$list[(int)$entry->account_id] = $date;
|
$list[(int) $entry->account_id] = $date;
|
||||||
}
|
}
|
||||||
|
|
||||||
return $list;
|
return $list;
|
||||||
@@ -426,9 +438,9 @@ class Steam
|
|||||||
public function getSafeUrl(string $unknownUrl, string $safeUrl): string
|
public function getSafeUrl(string $unknownUrl, string $safeUrl): string
|
||||||
{
|
{
|
||||||
// Log::debug(sprintf('getSafeUrl(%s, %s)', $unknownUrl, $safeUrl));
|
// Log::debug(sprintf('getSafeUrl(%s, %s)', $unknownUrl, $safeUrl));
|
||||||
$returnUrl = $safeUrl;
|
$returnUrl = $safeUrl;
|
||||||
$unknownHost = parse_url($unknownUrl, PHP_URL_HOST);
|
$unknownHost = parse_url($unknownUrl, PHP_URL_HOST);
|
||||||
$safeHost = parse_url($safeUrl, PHP_URL_HOST);
|
$safeHost = parse_url($safeUrl, PHP_URL_HOST);
|
||||||
|
|
||||||
if (null !== $unknownHost && $unknownHost === $safeHost) {
|
if (null !== $unknownHost && $unknownHost === $safeHost) {
|
||||||
$returnUrl = $unknownUrl;
|
$returnUrl = $unknownUrl;
|
||||||
@@ -465,7 +477,7 @@ class Steam
|
|||||||
*/
|
*/
|
||||||
public function floatalize(string $value): string
|
public function floatalize(string $value): string
|
||||||
{
|
{
|
||||||
$value = strtoupper($value);
|
$value = strtoupper($value);
|
||||||
if (!str_contains($value, 'E')) {
|
if (!str_contains($value, 'E')) {
|
||||||
return $value;
|
return $value;
|
||||||
}
|
}
|
||||||
|
@@ -69,26 +69,31 @@ class General extends AbstractExtension
|
|||||||
$date = session('end', today(config('app.timezone'))->endOfMonth());
|
$date = session('end', today(config('app.timezone'))->endOfMonth());
|
||||||
$info = Steam::finalAccountBalance($account, $date);
|
$info = Steam::finalAccountBalance($account, $date);
|
||||||
$currency = Steam::getAccountCurrency($account);
|
$currency = Steam::getAccountCurrency($account);
|
||||||
$native = Amount::getDefaultCurrency();
|
$default = Amount::getDefaultCurrency();
|
||||||
$convertToNative = app('preferences')->get('convert_to_native', false)->data;
|
$convertToNative = app('preferences')->get('convert_to_native', false)->data;
|
||||||
|
$useNative = $convertToNative && $default->id !== $currency->id;
|
||||||
$strings = [];
|
$strings = [];
|
||||||
foreach ($info as $key => $balance) {
|
foreach ($info as $key => $balance) {
|
||||||
if ('balance' === $key) {
|
if ('balance' === $key) {
|
||||||
// balance in account currency.
|
// balance in account currency.
|
||||||
if (!$convertToNative || $currency->code === $native->code) {
|
if (!$useNative) {
|
||||||
$strings[] = app('amount')->formatAnything($currency, $balance, false);
|
$strings[] = app('amount')->formatAnything($currency, $balance, false);
|
||||||
}
|
}
|
||||||
|
if($useNative) {
|
||||||
|
$strings[] =sprintf('(%s)', app('amount')->formatAnything($currency, $balance, false));
|
||||||
|
}
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if ('native_balance' === $key) {
|
if ('native_balance' === $key) {
|
||||||
// balance in native currency.
|
// balance in native currency.
|
||||||
if ($convertToNative) {
|
if ($useNative) {
|
||||||
$strings[] = app('amount')->formatAnything($native, $balance, false);
|
$strings[] = app('amount')->formatAnything($default, $balance, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
// for multi currency accounts.
|
||||||
if ($key !== $currency->code) {
|
if ($key !== $currency->code) {
|
||||||
$strings[] = app('amount')->formatAnything(TransactionCurrency::where('code', $key)->first(), $balance, false);
|
$strings[] = app('amount')->formatAnything(TransactionCurrency::where('code', $key)->first(), $balance, false);
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user