diff --git a/app/Http/Controllers/Popup/ReportController.php b/app/Http/Controllers/Popup/ReportController.php new file mode 100644 index 0000000000..e1e2b78d2b --- /dev/null +++ b/app/Http/Controllers/Popup/ReportController.php @@ -0,0 +1,106 @@ +get('attributes'); + $attributes = $this->parseAttributes($attributes); + $html = ''; + switch ($attributes['location']) { + default: + throw new FireflyException('Firefly cannot handle "' . e($attributes['location']) . '" '); + case 'budget-spent-amount': + $html = $this->budgetSpentAmount($attributes); + + break; + } + + return Response::json(['html' => $html]); + + + } + + /** + * @param array $attributes + * + * @return string + * @throws FireflyException + */ + private function budgetSpentAmount(array $attributes): string + { + // need to find the budget + // then search for expenses in the given period + // list them in some table format. + /** @var BudgetRepositoryInterface $repository */ + $repository = app('FireflyIII\Repositories\Budget\BudgetRepositoryInterface'); + $budget = $repository->find(intval($attributes['budgetId'])); + if (is_null($budget->id)) { + throw new FireflyException('Could not find a budget for value "' . e($attributes['budgetId']) . '".'); + } + + // get all expenses in budget in period: + $journals = $repository->getExpenses($budget, $attributes['accounts'], $attributes['startDate'], $attributes['endDate']); + + $view = view('popup.report.budget-spent-amount', compact('journals'))->render(); + + return $view; + } + + /** + * @param array $attributes + * + * @return array + * @throws FireflyException + */ + private function parseAttributes(array $attributes): array + { + $attributes['location'] = $attributes['location'] ?? ''; + $attributes['accounts'] = AccountList::routeBinder($attributes['accounts'] ?? '', ''); + try { + $attributes['startDate'] = Carbon::createFromFormat('Ymd', $attributes['startDate']); + } catch (InvalidArgumentException $e) { + throw new FireflyException('Could not parse start date "' . e($attributes['startDate']) . '".'); + } + + try { + $attributes['endDate'] = Carbon::createFromFormat('Ymd', $attributes['endDate']); + } catch (InvalidArgumentException $e) { + throw new FireflyException('Could not parse start date "' . e($attributes['endDate']) . '".'); + } + + + return $attributes; + } + +} \ No newline at end of file diff --git a/app/Http/routes.php b/app/Http/routes.php index caee07510f..043f945ef5 100644 --- a/app/Http/routes.php +++ b/app/Http/routes.php @@ -378,6 +378,14 @@ Route::group( Route::post('/transaction/destroy/{tj}', ['uses' => 'TransactionController@destroy', 'as' => 'transactions.destroy']); Route::post('/transaction/reorder', ['uses' => 'TransactionController@reorder', 'as' => 'transactions.reorder']); + /** + * POPUP Controllers + */ + /** + * Report popup + */ + Route::get('/popup/report', ['uses' => 'Popup\ReportController@info', 'as' => 'popup.report']); + } ); diff --git a/app/Repositories/Budget/BudgetRepository.php b/app/Repositories/Budget/BudgetRepository.php index ddacb85381..de8c6f91b5 100644 --- a/app/Repositories/Budget/BudgetRepository.php +++ b/app/Repositories/Budget/BudgetRepository.php @@ -372,6 +372,30 @@ class BudgetRepository extends ComponentRepository implements BudgetRepositoryIn return $data; } + /** + * Returns all expenses for the given budget and the given accounts, in the given period. + * + * @param Budget $budget + * @param Collection $accounts + * @param Carbon $start + * @param Carbon $end + * + * @return Collection + */ + public function getExpenses(Budget $budget, Collection $accounts, Carbon $start, Carbon $end):Collection + { + $ids = $accounts->pluck('id')->toArray(); + $set = $budget->transactionjournals() + ->before($end) + ->after($start) + ->expanded() + ->where('transaction_types.type', 'Withdrawal') + ->whereIn('source_account.id', $ids) + ->get(TransactionJournal::QUERYFIELDS); + + return $set; + } + /** * Returns the expenses for this budget grouped per day, with the date * in "date" (a string, not a Carbon) and the amount in "dailyAmount". diff --git a/app/Repositories/Budget/BudgetRepositoryInterface.php b/app/Repositories/Budget/BudgetRepositoryInterface.php index 01735d9313..43662e7048 100644 --- a/app/Repositories/Budget/BudgetRepositoryInterface.php +++ b/app/Repositories/Budget/BudgetRepositoryInterface.php @@ -132,6 +132,18 @@ interface BudgetRepositoryInterface */ public function getCurrentRepetition(Budget $budget, Carbon $start, Carbon $end); + /** + * Returns all expenses for the given budget and the given accounts, in the given period. + * + * @param Budget $budget + * @param Collection $accounts + * @param Carbon $start + * @param Carbon $end + * + * @return Collection + */ + public function getExpenses(Budget $budget, Collection $accounts, Carbon $start, Carbon $end):Collection; + /** * Returns the expenses for this budget grouped per day, with the date * in "date" (a string, not a Carbon) and the amount in "dailyAmount". diff --git a/public/js/reports/default/all.js b/public/js/reports/default/all.js new file mode 100644 index 0000000000..5153107544 --- /dev/null +++ b/public/js/reports/default/all.js @@ -0,0 +1,49 @@ +/* globals startDate, endDate, reportType, accountIds */ +/* + * all.js + * Copyright (C) 2016 Sander Dorigo + * + * This software may be modified and distributed under the terms + * of the MIT license. See the LICENSE file for details. + */ + +/** + * Created by sander on 01/04/16. + */ + +$(function () { + "use strict"; + + // find the little info buttons and respond to them. + $('.firefly-info-button').click(clickInfoButton); + +}); + +function clickInfoButton(e) { + "use strict"; + // find all data tags, regardless of what they are: + var element = $(e.target); + var attributes = element.data(); + + // add some more elements: + attributes.startDate = startDate; + attributes.endDate = endDate; + attributes.reportType = reportType; + attributes.accounts = accountIds; + + console.log(attributes); + $.getJSON('popup/report', {attributes: attributes}).success(respondInfoButton).fail(errorInfoButton); +} + +function errorInfoButton(data) { + "use strict"; + console.log(data); +} + +function respondInfoButton(data) { + "use strict"; + console.log(123); + $('#defaultModal').empty().html(data.html); + $('#defaultModal').modal('show'); + +} \ No newline at end of file diff --git a/public/js/reports/default/reports.js b/public/js/reports/default/reports.js deleted file mode 100644 index 8a42a47788..0000000000 --- a/public/js/reports/default/reports.js +++ /dev/null @@ -1,208 +0,0 @@ -/* globals google, startDate ,reportURL, endDate , reportType ,accountIds , picker:true, minDate, expenseRestShow:true, incomeRestShow:true, year, month, hideTheRest, showTheRest, showTheRestExpense, hideTheRestExpense, columnChart, lineChart, stackedColumnChart */ - - -$(function () { - "use strict"; - drawChart(); - - if ($('#inputDateRange').length > 0) { - - picker = $('#inputDateRange').daterangepicker( - { - locale: { - format: 'YYYY-MM-DD', - firstDay: 1, - }, - minDate: minDate, - drops: 'up', - } - ); - - - // set values from cookies, if any: - if (readCookie('report-type') !== null) { - $('select[name="report_type"]').val(readCookie('report-type')); - } - - if ((readCookie('report-accounts') !== null)) { - var arr = readCookie('report-accounts').split(','); - arr.forEach(function (val) { - $('input[type="checkbox"][value="' + val + '"]').prop('checked', true); - }); - } - - // set date: - var startStr = readCookie('report-start'); - var endStr = readCookie('report-end'); - if (startStr !== null && endStr !== null && startStr.length == 8 && endStr.length == 8) { - var startDate = moment(startStr, "YYYYMMDD"); - var endDate = moment(endStr, "YYYYMMDD"); - var datePicker = $('#inputDateRange').data('daterangepicker'); - datePicker.setStartDate(startDate); - datePicker.setEndDate(endDate); - } - } - - $('.openModal').on('click', openModal); - - $('.date-select').on('click', preSelectDate); - - $('#report-form').on('submit', catchSubmit); - - - // click open the top X income list: - $('#showIncomes').click(showIncomes); - // click open the top X expense list: - $('#showExpenses').click(showExpenses); -}); - -function catchSubmit() { - "use strict"; - // default;20141201;20141231;4;5 - // report name: - var url = '' + $('select[name="report_type"]').val() + '/'; - - // date, processed: - var picker = $('#inputDateRange').data('daterangepicker'); - url += moment(picker.startDate).format("YYYYMMDD") + '/'; - url += moment(picker.endDate).format("YYYYMMDD") + '/'; - - // all account ids: - var count = 0; - var accounts = []; - $.each($('.account-checkbox'), function (i, v) { - var c = $(v); - if (c.prop('checked')) { - url += c.val() + ';'; - accounts.push(c.val()); - count++; - } - }); - if (count > 0) { - // set cookie to remember choices. - createCookie('report-type', $('select[name="report_type"]').val(), 365); - createCookie('report-accounts', accounts, 365); - createCookie('report-start', moment(picker.startDate).format("YYYYMMDD"), 365); - createCookie('report-end', moment(picker.endDate).format("YYYYMMDD"), 365); - - window.location.href = reportURL + "/" + url; - } - //console.log(url); - - return false; -} - -function preSelectDate(e) { - "use strict"; - var link = $(e.target); - var picker = $('#inputDateRange').data('daterangepicker'); - picker.setStartDate(link.data('start')); - picker.setEndDate(link.data('end')); - return false; - -} - -function drawChart() { - "use strict"; - if (typeof columnChart !== 'undefined' && typeof year !== 'undefined' && typeof month === 'undefined') { - - columnChart('chart/report/in-out/' + reportType + '/' + startDate + '/' + endDate + '/' + accountIds, 'income-expenses-chart'); - columnChart('chart/report/in-out-sum/' + reportType + '/' + startDate + '/' + endDate + '/' + accountIds, 'income-expenses-sum-chart'); - } - if (typeof stackedColumnChart !== 'undefined' && typeof year !== 'undefined' && typeof month === 'undefined') { - stackedColumnChart('chart/budget/year/' + reportType + '/' + startDate + '/' + endDate + '/' + accountIds, 'budgets'); - stackedColumnChart('chart/category/spent-in-year/' + reportType + '/' + startDate + '/' + endDate + '/' + accountIds, 'categories-spent-in-year'); - stackedColumnChart('chart/category/earned-in-year/' + reportType + '/' + startDate + '/' + endDate + '/' + accountIds, 'categories-earned-in-year'); - } - - if (typeof lineChart !== 'undefined' && typeof accountIds !== 'undefined') { - lineChart('chart/account/report/' + reportType + '/' + startDate + '/' + endDate + '/' + accountIds, 'account-balances-chart'); - } -} - - -function openModal(e) { - "use strict"; - var target = $(e.target).parent(); - var URL = target.attr('href'); - - $.get(URL).done(function (data) { - $('#defaultModal').empty().html(data).modal('show'); - - }).fail(function () { - alert('Could not load data.'); - }); - - return false; -} - - -function showIncomes() { - "use strict"; - if (incomeRestShow) { - // hide everything, make button say "show" - $('#showIncomes').text(showTheRest); - $('.incomesCollapsed').removeClass('in').addClass('out'); - - // toggle: - incomeRestShow = false; - } else { - // show everything, make button say "hide". - $('#showIncomes').text(hideTheRest); - $('.incomesCollapsed').removeClass('out').addClass('in'); - - // toggle: - incomeRestShow = true; - } - - return false; -} - -function showExpenses() { - "use strict"; - if (expenseRestShow) { - // hide everything, make button say "show" - $('#showExpenses').text(showTheRestExpense); - $('.expenseCollapsed').removeClass('in').addClass('out'); - - // toggle: - expenseRestShow = false; - } else { - // show everything, make button say "hide". - $('#showExpenses').text(hideTheRestExpense); - $('.expenseCollapsed').removeClass('out').addClass('in'); - - // toggle: - expenseRestShow = true; - } - - return false; -} - -function createCookie(name, value, days) { - var expires; - - if (days) { - var date = new Date(); - date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000)); - expires = "; expires=" + date.toGMTString(); - } else { - expires = ""; - } - document.cookie = encodeURIComponent(name) + "=" + encodeURIComponent(value) + expires + "; path=/"; -} - -function readCookie(name) { - var nameEQ = encodeURIComponent(name) + "="; - var ca = document.cookie.split(';'); - for (var i = 0; i < ca.length; i++) { - var c = ca[i]; - while (c.charAt(0) === ' ') c = c.substring(1, c.length); - if (c.indexOf(nameEQ) === 0) return decodeURIComponent(c.substring(nameEQ.length, c.length)); - } - return null; -} - -function eraseCookie(name) { - createCookie(name, "", -1); -} \ No newline at end of file diff --git a/resources/views/popup/list/journals.twig b/resources/views/popup/list/journals.twig new file mode 100644 index 0000000000..83bdf76424 --- /dev/null +++ b/resources/views/popup/list/journals.twig @@ -0,0 +1,78 @@ +
| + | {{ trans('list.description') }} | +{{ trans('list.amount') }} | + +{{ trans('list.from') }} | +{{ trans('list.to') }} | + + {% if not hideBudgets %} ++ {% endif %} + + + {% if not hideCategories %} + | + {% endif %} + |
|---|---|---|---|---|---|---|
| + {{ journal|typeIcon }} + | ++ {{ journal.description }} + {% if journal.attachments|length > 0 %} + + {% endif %} + + | ++ {{ journal|formatJournal }} + | + ++ {% if journal.source_account_type == 'Cash account' %} + (cash) + {% else %} + {{ journal.source_account_name }} + {% endif %} + | ++ {% if journal.destination_account_type == 'Cash account' %} + (cash) + {% else %} + {{ journal.destination_account_name }} + {% endif %} + | + + + {% if not hideBudgets %} ++ {% if journal.budgets[0] %} + {{ journal.budgets[0].name }} + {% endif %} + | + {% endif %} + + + {% if not hideCategories %} ++ {% if journal.categories[0] %} + {{ journal.categories[0].name }} + {% endif %} + | + {% endif %} +