diff --git a/app/Http/Controllers/BudgetController.php b/app/Http/Controllers/BudgetController.php index 20dc8e3311..647e5d9ffc 100644 --- a/app/Http/Controllers/BudgetController.php +++ b/app/Http/Controllers/BudgetController.php @@ -245,6 +245,59 @@ class BudgetController extends Controller ); } + /** + * @param Carbon $start + * @param Carbon $end + * + * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View + */ + public function infoIncome(Carbon $start, Carbon $end) + { + // properties for cache + $cache = new CacheProperties; + $cache->addProperty($start); + $cache->addProperty($end); + $cache->addProperty('info-income'); + + if ($cache->has()) { + $result = $cache->get(); // @codeCoverageIgnore + } + if (!$cache->has()) { + $result = [ + 'available' => '0', + 'earned' => '0', + 'suggested' => '0', + ]; + $currency = Amount::getDefaultCurrency(); + $range = Preferences::get('viewRange', '1M')->data; + $begin = Navigation::subtractPeriod($start, $range, 3); + + // get average amount available. + $total = '0'; + $count = 0; + $currentStart = clone $begin; + while ($currentStart < $start) { + $currentEnd = Navigation::endOfPeriod($currentStart, $range); + $total = bcadd($total, $this->repository->getAvailableBudget($currency, $currentStart, $currentEnd)); + $currentStart = Navigation::addPeriod($currentStart, $range, 0); + $count++; + } + $result['available'] = bcdiv($total, strval($count)); + + // amount earned in this period: + $subDay = clone $end; + $subDay->subDay(); + /** @var JournalCollectorInterface $collector */ + $collector = app(JournalCollectorInterface::class); + $collector->setAllAssetAccounts()->setRange($begin, $subDay)->setTypes([TransactionType::DEPOSIT])->withOpposingAccount(); + $result['earned'] = bcdiv(strval($collector->getJournals()->sum('transaction_amount')),strval($count)); + $cache->store($result); + } + + + return view('budgets.info', compact('result', 'begin', 'currentEnd')); + } + /** * @param Request $request * @param JournalRepositoryInterface $repository diff --git a/config/intro.php b/config/intro.php index 05c861e4d6..99205178b2 100644 --- a/config/intro.php +++ b/config/intro.php @@ -42,6 +42,7 @@ return [ 'navigate_periods' => ['element' => '#periodNavigator'], 'new_budget' => ['element' => '#createBudgetBox'], 'list_of_budgets' => ['element' => '#budgetList'], + 'outro' => [], ], // reports: index, default report, audit, budget, cat, tag diff --git a/public/js/ff/budgets/index.js b/public/js/ff/budgets/index.js index e855f441c7..79cfd64722 100644 --- a/public/js/ff/budgets/index.js +++ b/public/js/ff/budgets/index.js @@ -10,6 +10,37 @@ /** global: spent, budgeted, available, currencySymbol, budgetIndexUri, updateIncomeUri, periodStart, periodEnd, budgetAmountUri, accounting */ +/** + * + */ +$(function () { + "use strict"; + + $('.updateIncome').on('click', updateIncome); + $('.infoIncome').on('click', infoIncome); + + /* + On start, fill the "spent"-bar using the content from the page. + */ + drawSpentBar(); + drawBudgetedBar(); + + /* + When the input changes, update the percentages for the budgeted bar: + */ + $('input[type="number"]').on('input', updateBudgetedAmounts); + + // + $('.selectPeriod').change(function (e) { + var sel = $(e.target).val(); + if (sel !== "x") { + var newUri = budgetIndexUri.replace("REPLACE", sel); + window.location.assign(newUri); + } + }); + +}); + function drawSpentBar() { "use strict"; if ($('.spentBar').length > 0) { @@ -55,6 +86,10 @@ function drawBudgetedBar() { } } +/** + * + * @param e + */ function updateBudgetedAmounts(e) { "use strict"; var target = $(e.target); @@ -90,7 +125,7 @@ function updateBudgetedAmounts(e) { // send a post to Firefly to update the amount: var newUri = budgetAmountUri.replace("REPLACE", id); - $.post(newUri, {amount: value,start: periodStart, end: periodEnd}).done(function (data) { + $.post(newUri, {amount: value, start: periodStart, end: periodEnd}).done(function (data) { // update the link if relevant: if (data.repetition > 0) { $('.budget-link[data-id="' + id + '"]').attr('href', 'budgets/show/' + id + '/' + data.repetition); @@ -101,33 +136,10 @@ function updateBudgetedAmounts(e) { } } -$(function () { - "use strict"; - - $('.updateIncome').on('click', updateIncome); - - /* - On start, fill the "spent"-bar using the content from the page. - */ - drawSpentBar(); - drawBudgetedBar(); - - /* - When the input changes, update the percentages for the budgeted bar: - */ - $('input[type="number"]').on('input', updateBudgetedAmounts); - - // - $('.selectPeriod').change(function (e) { - var sel = $(e.target).val(); - if (sel !== "x") { - var newUri = budgetIndexUri.replace("REPLACE", sel); - window.location.assign(newUri); - } - }); - -}); - +/** + * + * @returns {boolean} + */ function updateIncome() { "use strict"; $('#defaultModal').empty().load(updateIncomeUri, function () { @@ -136,3 +148,11 @@ function updateIncome() { return false; } + +function infoIncome() { + $('#defaultModal').empty().load(infoIncomeUri, function () { + $('#defaultModal').modal('show'); + }); + + return false; +} diff --git a/resources/lang/en_US/firefly.php b/resources/lang/en_US/firefly.php index ccf0183f78..792f93d839 100644 --- a/resources/lang/en_US/firefly.php +++ b/resources/lang/en_US/firefly.php @@ -532,6 +532,13 @@ return [ 'update_budget' => 'Update budget', 'update_budget_amount_range' => 'Update (expected) available amount between :start and :end', 'budget_period_navigator' => 'Period navigator', + 'info_on_available_amount' => 'What do I have available?', + 'available_amount_indication' => 'Use these amounts to get an indication of what your total budget could be.', + 'amount_budgeted' => 'Amount budgeted', + 'amount_earned' => 'Amount earned', + 'suggested' => 'Suggested', + 'average_between' => 'Average between :start and :end', + // bills: 'matching_on' => 'Matching on', diff --git a/resources/lang/en_US/intro.php b/resources/lang/en_US/intro.php index 02a0eead23..0fe735125b 100644 --- a/resources/lang/en_US/intro.php +++ b/resources/lang/en_US/intro.php @@ -31,6 +31,7 @@ return [ 'budgets_index_navigate_periods' => 'Navigate through periods to easily set budgets ahead of time.', 'budgets_index_new_budget' => 'Create new budgets as you see fit.', 'budgets_index_list_of_budgets' => 'Use this table to set the amounts for each budget and see how you are doing.', + 'budgets_index_outro' => 'To learn more about budgeting, checkout the help icon in the top right corner.', // reports (index) 'reports_index_intro' => 'Use these reports to get detailed insights in your finances.', diff --git a/resources/views/budgets/index.twig b/resources/views/budgets/index.twig index 74a26a5e5b..f150edb26a 100644 --- a/resources/views/budgets/index.twig +++ b/resources/views/budgets/index.twig @@ -16,10 +16,11 @@
{{ 'budgeted'|_ }}: {{ budgeted|formatAmountPlain }}
-
+
{{ trans('firefly.available_between',{start : periodStart, end: periodEnd }) }}: - {{ available|formatAmountPlain }} + {{ available|formatAmountPlain }} + +
@@ -232,6 +233,7 @@ var budgetIndexUri = "{{ route('budgets.index','REPLACE') }}"; var budgetAmountUri = "{{ route('budgets.amount','REPLACE') }}"; var updateIncomeUri = "{{ route('budgets.income',[start.format('Y-m-d'),end.format('Y-m-d')]) }}"; + var infoIncomeUri = "{{ route('budgets.income.info',[start.format('Y-m-d'),end.format('Y-m-d')]) }}"; var periodStart = "{{ start.format('Y-m-d') }}"; var periodEnd = "{{ end.format('Y-m-d') }}"; diff --git a/resources/views/budgets/info.twig b/resources/views/budgets/info.twig new file mode 100644 index 0000000000..3531f65b39 --- /dev/null +++ b/resources/views/budgets/info.twig @@ -0,0 +1,46 @@ + + diff --git a/routes/web.php b/routes/web.php index 026774b8b5..1b9c1c48bb 100755 --- a/routes/web.php +++ b/routes/web.php @@ -140,7 +140,8 @@ Route::group( Route::group( ['middleware' => 'user-full-auth', 'prefix' => 'budgets', 'as' => 'budgets.'], function () { - Route::get('income/{start_date}/{end_date}', ['uses' => 'BudgetController@updateIncome', 'as' => 'income']); + Route::get('income/{start_date}/{end_date}', ['uses' => 'BudgetController@updateIncome', 'as' => 'income']); + Route::get('info/{start_date}/{end_date}', ['uses' => 'BudgetController@infoIncome', 'as' => 'income.info']); Route::get('create', ['uses' => 'BudgetController@create', 'as' => 'create']); Route::get('edit/{budget}', ['uses' => 'BudgetController@edit', 'as' => 'edit']); Route::get('delete/{budget}', ['uses' => 'BudgetController@delete', 'as' => 'delete']);