mirror of
https://github.com/firefly-iii/firefly-iii.git
synced 2025-09-25 06:51:08 +00:00
Add budget warnings #1202
This commit is contained in:
@@ -85,6 +85,10 @@ class BudgetController extends Controller
|
|||||||
$start = Carbon::createFromFormat('Y-m-d', $request->get('start'));
|
$start = Carbon::createFromFormat('Y-m-d', $request->get('start'));
|
||||||
$end = Carbon::createFromFormat('Y-m-d', $request->get('end'));
|
$end = Carbon::createFromFormat('Y-m-d', $request->get('end'));
|
||||||
$budgetLimit = $this->repository->updateLimitAmount($budget, $start, $end, $amount);
|
$budgetLimit = $this->repository->updateLimitAmount($budget, $start, $end, $amount);
|
||||||
|
$largeDiff = false;
|
||||||
|
$warnText = '';
|
||||||
|
$average = '0';
|
||||||
|
$current = '0';
|
||||||
if (0 === bccomp($amount, '0')) {
|
if (0 === bccomp($amount, '0')) {
|
||||||
$budgetLimit = null;
|
$budgetLimit = null;
|
||||||
}
|
}
|
||||||
@@ -94,9 +98,43 @@ class BudgetController extends Controller
|
|||||||
$currency = app('amount')->getDefaultCurrency();
|
$currency = app('amount')->getDefaultCurrency();
|
||||||
$left = app('amount')->formatAnything($currency, bcadd($amount, $spent), true);
|
$left = app('amount')->formatAnything($currency, bcadd($amount, $spent), true);
|
||||||
|
|
||||||
|
|
||||||
|
// over or under budgeting, compared to previous budgets?
|
||||||
|
$average = $this->repository->budgetedPerDay($budget);
|
||||||
|
// current average per day:
|
||||||
|
$diff = $start->diffInDays($end);
|
||||||
|
$current = $amount;
|
||||||
|
if ($diff > 0) {
|
||||||
|
$current = bcdiv($amount, strval($diff));
|
||||||
|
}
|
||||||
|
if (bccomp(bcmul('1.1', $average), $current) === -1) {
|
||||||
|
$largeDiff = true;
|
||||||
|
$warnText = strval(
|
||||||
|
trans(
|
||||||
|
'firefly.over_budget_warn',
|
||||||
|
[
|
||||||
|
'amount' => app('amount')->formatAnything($currency, $average, false),
|
||||||
|
'over_amount' => app('amount')->formatAnything($currency, $current, false),
|
||||||
|
]
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
Preferences::mark();
|
Preferences::mark();
|
||||||
|
|
||||||
return response()->json(['left' => $left, 'name' => $budget->name, 'limit' => $budgetLimit ? $budgetLimit->id : 0, 'amount' => $amount]);
|
return response()->json(
|
||||||
|
[
|
||||||
|
'left' => $left,
|
||||||
|
'name' => $budget->name,
|
||||||
|
'limit' => $budgetLimit ? $budgetLimit->id : 0,
|
||||||
|
'amount' => $amount,
|
||||||
|
'current' => $current,
|
||||||
|
'average' => $average,
|
||||||
|
'large_diff' => $largeDiff,
|
||||||
|
'warn_text' => $warnText,
|
||||||
|
|
||||||
|
]
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -443,6 +481,7 @@ class BudgetController extends Controller
|
|||||||
$pageSize = intval(Preferences::get('listPageSize', 50)->data);
|
$pageSize = intval(Preferences::get('listPageSize', 50)->data);
|
||||||
$limits = $this->getLimits($budget, $start, $end);
|
$limits = $this->getLimits($budget, $start, $end);
|
||||||
$repetition = null;
|
$repetition = null;
|
||||||
|
|
||||||
// collector:
|
// collector:
|
||||||
/** @var JournalCollectorInterface $collector */
|
/** @var JournalCollectorInterface $collector */
|
||||||
$collector = app(JournalCollectorInterface::class);
|
$collector = app(JournalCollectorInterface::class);
|
||||||
|
@@ -48,6 +48,33 @@ class BudgetRepository implements BudgetRepositoryInterface
|
|||||||
/** @var User */
|
/** @var User */
|
||||||
private $user;
|
private $user;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A method that returns the amount of money budgeted per day for this budget,
|
||||||
|
* on average.
|
||||||
|
*
|
||||||
|
* @param Budget $budget
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function budgetedPerDay(Budget $budget): string
|
||||||
|
{
|
||||||
|
$total = '0';
|
||||||
|
$count = 0;
|
||||||
|
foreach ($budget->budgetlimits as $limit) {
|
||||||
|
$diff = strval($limit->start_date->diffInDays($limit->end_date));
|
||||||
|
$amount = strval($limit->amount);
|
||||||
|
$perDay = bcdiv($amount, $diff);
|
||||||
|
$total = bcadd($total, $perDay);
|
||||||
|
$count++;
|
||||||
|
}
|
||||||
|
$avg = $total;
|
||||||
|
if ($count > 0) {
|
||||||
|
$avg = bcdiv($total, strval($count));
|
||||||
|
}
|
||||||
|
|
||||||
|
return $avg;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return bool
|
* @return bool
|
||||||
*
|
*
|
||||||
|
@@ -39,6 +39,16 @@ interface BudgetRepositoryInterface
|
|||||||
*/
|
*/
|
||||||
public function cleanupBudgets(): bool;
|
public function cleanupBudgets(): bool;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A method that returns the amount of money budgeted per day for this budget,
|
||||||
|
* on average.
|
||||||
|
*
|
||||||
|
* @param Budget $budget
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function budgetedPerDay(Budget $budget): string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This method collects various info on budgets, used on the budget page and on the index.
|
* This method collects various info on budgets, used on the budget page and on the index.
|
||||||
*
|
*
|
||||||
|
8
public/js/ff/budgets/index.js
vendored
8
public/js/ff/budgets/index.js
vendored
@@ -148,6 +148,14 @@ function updateBudgetedAmounts(e) {
|
|||||||
if (data.limit > 0) {
|
if (data.limit > 0) {
|
||||||
link.attr('href', 'budgets/show/' + id + '/' + data.limit);
|
link.attr('href', 'budgets/show/' + id + '/' + data.limit);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// update the warning if relevant:
|
||||||
|
if (data.large_diff === true) {
|
||||||
|
$('span[class$="budget_warning"][data-id="' + id + '"]').html(data.warn_text).show();
|
||||||
|
console.log('Show warning for budget');
|
||||||
|
} else {
|
||||||
|
$('span[class$="budget_warning"][data-id="' + id + '"]').empty().hide();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
File diff suppressed because it is too large
Load Diff
@@ -183,6 +183,7 @@
|
|||||||
data-id="{{ budget.id }}" value="{{ repAmount }}" autocomplete="off"
|
data-id="{{ budget.id }}" value="{{ repAmount }}" autocomplete="off"
|
||||||
min="0" name="amount" type="number">
|
min="0" name="amount" type="number">
|
||||||
</div>
|
</div>
|
||||||
|
<span class="text-danger budget_warning" data-id="{{ budget.id }}" style="display:none;"></span>
|
||||||
</td>
|
</td>
|
||||||
<td class="hidden-sm hidden-xs spent" data-id="{{ budget.id }}" data-spent="{{ budgetInformation[budget.id]['spent'] }}"
|
<td class="hidden-sm hidden-xs spent" data-id="{{ budget.id }}" data-spent="{{ budgetInformation[budget.id]['spent'] }}"
|
||||||
data-value="{{ budgetInformation[budget.id]['spent'] }}">
|
data-value="{{ budgetInformation[budget.id]['spent'] }}">
|
||||||
|
Reference in New Issue
Block a user