This commit is contained in:
James Cole
2025-04-22 20:41:08 +02:00
parent dba8bba41a
commit 576c5f242c
3 changed files with 96 additions and 56 deletions

View File

@@ -43,6 +43,7 @@ use FireflyIII\Support\Http\Api\ExchangeRateConverter;
use FireflyIII\Support\Report\Summarizer\TransactionSummarizer;
use FireflyIII\User;
use Illuminate\Http\JsonResponse;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Log;
/**
@@ -104,10 +105,10 @@ class BasicController extends Controller
$billData = $this->getSubscriptionInformation($start, $end);
$spentData = $this->getLeftToSpendInfo($start, $end);
$netWorthData = $this->getNetWorthInfo($end);
// $balanceData = [];
// $billData = [];
// $balanceData = [];
// $billData = [];
// $spentData = [];
// $netWorthData = [];
// $netWorthData = [];
$total = array_merge($balanceData, $billData, $spentData, $netWorthData);
// give new keys
@@ -539,26 +540,63 @@ class BasicController extends Controller
),
];
}
unset($leftToSpend);
if (0 === count($return)) {
$currency = $this->nativeCurrency;
$return[$currency->id] = [
'key' => sprintf('left-to-spend-in-%s', $currency->code),
'title' => trans('firefly.box_left_to_spend_in_currency', ['currency' => $currency->symbol]),
'monetary_value' => '0',
'no_available_budgets' => true,
'currency_id' => (string) $currency->id,
'currency_code' => $currency->code,
'currency_symbol' => $currency->symbol,
'currency_decimal_places' => $currency->decimal_places,
'value_parsed' => app('amount')->formatFlat($currency->symbol, $currency->decimal_places, '0', false),
'local_icon' => 'money',
'sub_title' => app('amount')->formatFlat(
$currency->symbol,
$currency->decimal_places,
'0',
false
),
];
// a small trick to get every expense in this period, regardless of budget.
$spent = $this->opsRepository->sumExpenses($start, $end, null, new Collection());
foreach ($spent as $row) {
// either an amount was budgeted or 0 is available.
$currencyId = (int) $row['currency_id'];
$spentInCurrency = $row['sum'];
$perDay = '0';
if (0 !== $days && -1 === bccomp($spentInCurrency, '0')) {
$perDay = bcdiv($spentInCurrency, (string) $days);
}
Log::debug(sprintf('Spent %s %s', $row['currency_code'], $row['sum']));
$return[$currencyId] = [
'key' => sprintf('left-to-spend-in-%s', $row['currency_code']),
'title' => trans('firefly.spent'),
'no_available_budgets' => true,
'monetary_value' => $spentInCurrency,
'currency_id' => (string) $row['currency_id'],
'currency_code' => $row['currency_code'],
'currency_symbol' => $row['currency_symbol'],
'currency_decimal_places' => $row['currency_decimal_places'],
'value_parsed' => app('amount')->formatFlat($row['currency_symbol'], $row['currency_decimal_places'], $spentInCurrency, false),
'local_icon' => 'money',
'sub_title' => app('amount')->formatFlat(
$row['currency_symbol'],
$row['currency_decimal_places'],
$perDay,
false
),
];
}
// $amount = '0';
// // $days
// // fill in by money spent, just count it.
// $currency = $this->nativeCurrency;
// $return[$currency->id] = [
// 'key' => sprintf('left-to-spend-in-%s', $currency->code),
// 'title' => trans('firefly.box_left_to_spend_in_currency', ['currency' => $currency->symbol]),
// 'monetary_value' => '0',
// 'no_available_budgets' => true,
// 'currency_id' => (string) $currency->id,
// 'currency_code' => $currency->code,
// 'currency_symbol' => $currency->symbol,
// 'currency_decimal_places' => $currency->decimal_places,
// 'value_parsed' => app('amount')->formatFlat($currency->symbol, $currency->decimal_places, '0', false),
// 'local_icon' => 'money',
// 'sub_title' => app('amount')->formatFlat(
// $currency->symbol,
// $currency->decimal_places,
// '0',
// false
// ),
// ];
}
return array_values($return);

View File

@@ -31,7 +31,6 @@ use FireflyIII\Models\Account;
use FireflyIII\Models\Budget;
use FireflyIII\Models\TransactionCurrency;
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use FireflyIII\Support\Facades\Amount;
use FireflyIII\Support\Report\Summarizer\TransactionSummarizer;
use FireflyIII\Support\Repositories\UserGroup\UserGroupInterface;
use FireflyIII\Support\Repositories\UserGroup\UserGroupTrait;
@@ -63,7 +62,7 @@ class OperationsRepository implements OperationsRepositoryInterface, UserGroupIn
++$count;
app('log')->debug(sprintf('Found %d budget limits. Per day is %s, total is %s', $count, $perDay, $total));
}
$avg = $total;
$avg = $total;
if ($count > 0) {
$avg = bcdiv($total, (string) $count);
}
@@ -85,21 +84,21 @@ class OperationsRepository implements OperationsRepositoryInterface, UserGroupIn
// get all transactions:
/** @var GroupCollectorInterface $collector */
$collector = app(GroupCollectorInterface::class);
$collector = app(GroupCollectorInterface::class);
$collector->setAccounts($accounts)->setRange($start, $end);
$collector->setBudgets($budgets);
$journals = $collector->getExtractedJournals();
$journals = $collector->getExtractedJournals();
// loop transactions:
/** @var array $journal */
foreach ($journals as $journal) {
// prep data array for currency:
$budgetId = (int) $journal['budget_id'];
$budgetName = $journal['budget_name'];
$currencyId = (int) $journal['currency_id'];
$key = sprintf('%d-%d', $budgetId, $currencyId);
$budgetId = (int) $journal['budget_id'];
$budgetName = $journal['budget_name'];
$currencyId = (int) $journal['currency_id'];
$key = sprintf('%d-%d', $budgetId, $currencyId);
$data[$key] ??= [
$data[$key] ??= [
'id' => $budgetId,
'name' => sprintf('%s (%s)', $budgetName, $journal['currency_name']),
'sum' => '0',
@@ -137,13 +136,13 @@ class OperationsRepository implements OperationsRepositoryInterface, UserGroupIn
$collector->setBudgets($this->getBudgets());
}
$collector->withBudgetInformation()->withAccountInformation()->withCategoryInformation();
$journals = $collector->getExtractedJournals();
$array = [];
$journals = $collector->getExtractedJournals();
$array = [];
foreach ($journals as $journal) {
$currencyId = (int) $journal['currency_id'];
$budgetId = (int) $journal['budget_id'];
$budgetName = (string) $journal['budget_name'];
$currencyId = (int) $journal['currency_id'];
$budgetId = (int) $journal['budget_id'];
$budgetName = (string) $journal['budget_name'];
// catch "no category" entries.
if (0 === $budgetId) {
@@ -151,7 +150,7 @@ class OperationsRepository implements OperationsRepositoryInterface, UserGroupIn
}
// info about the currency:
$array[$currencyId] ??= [
$array[$currencyId] ??= [
'budgets' => [],
'currency_id' => $currencyId,
'currency_name' => $journal['currency_name'],
@@ -203,8 +202,9 @@ class OperationsRepository implements OperationsRepositoryInterface, UserGroupIn
?Collection $accounts = null,
?Collection $budgets = null,
?TransactionCurrency $currency = null,
bool $convertToNative = false
): array {
bool $convertToNative = false
): array
{
Log::debug(sprintf('Start of %s(date, date, array, array, "%s", "%s").', __METHOD__, $currency?->code, var_export($convertToNative, true)));
// 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.
@@ -212,8 +212,8 @@ class OperationsRepository implements OperationsRepositoryInterface, UserGroupIn
$repository = app(AccountRepositoryInterface::class);
$repository->setUser($this->user);
$subset = $repository->getAccountsByType(config('firefly.valid_liabilities'));
$selection = new Collection();
$subset = $repository->getAccountsByType(config('firefly.valid_liabilities'));
$selection = new Collection();
/** @var Account $account */
foreach ($subset as $account) {
@@ -223,12 +223,11 @@ class OperationsRepository implements OperationsRepositoryInterface, UserGroupIn
}
/** @var GroupCollectorInterface $collector */
$collector = app(GroupCollectorInterface::class);
$collector = app(GroupCollectorInterface::class);
$collector->setUser($this->user)
->setRange($start, $end)
->setRange($start, $end)
// ->excludeDestinationAccounts($selection)
->setTypes([TransactionTypeEnum::WITHDRAWAL->value])
;
->setTypes([TransactionTypeEnum::WITHDRAWAL->value]);
if (null !== $accounts) {
$collector->setAccounts($accounts);
@@ -240,8 +239,10 @@ class OperationsRepository implements OperationsRepositoryInterface, UserGroupIn
Log::debug(sprintf('Limit to normal currency %s', $currency->code));
$collector->setNormalCurrency($currency);
}
$collector->setBudgets($budgets);
$journals = $collector->getExtractedJournals();
if ($budgets->count() > 0) {
$collector->setBudgets($budgets);
}
$journals = $collector->getExtractedJournals();
// same but for transactions in the foreign currency:
if (null !== $currency) {

View File

@@ -62,6 +62,7 @@ function drawChart() {
// net worth
var net_worth = [];
var keepGreen = false;
var makeBlue = false;
for (key in data) {
// balance
@@ -80,17 +81,14 @@ function drawChart() {
// left to spend
if (key.substring(0, 17) === 'left-to-spend-in-') {
left_to_spend_top.push(data[key].value_parsed);
left_to_spend_bottom.push(data[key].sub_title);
if(true === data[key].no_available_budgets) {
left_to_spend_top.push('---');
left_to_spend_bottom.push('---');
keepGreen = true;
makeBlue = true;
$('#box-left-to-spend-text').text(data[key].title);
}
if(false === data[key].no_available_budgets) {
left_to_spend_top.push(data[key].value_parsed);
left_to_spend_bottom.push(data[key].sub_title);
if (parseFloat(data[key].monetary_value) > 0) {
keepGreen = true;
}
if(false === data[key].no_available_budgets && parseFloat(data[key].monetary_value) > 0) {
keepGreen = true;
}
}
@@ -102,6 +100,9 @@ function drawChart() {
if(!keepGreen) {
$('#box-left-to-spend-box').removeClass('bg-green-gradient').addClass('bg-red-gradient')
}
if(makeBlue) {
$('#box-left-to-spend-box').removeClass('bg-red-gradient').removeClass('bg-green-gradient').addClass('bg-blue-gradient')
}
// balance
$('#box-balance-sums').html(balance_top.join(', '));