From 951aa9535ecf8faead8a7ea2793b85cb48e7820c Mon Sep 17 00:00:00 2001 From: Ben Yanke Date: Mon, 5 Mar 2018 20:49:21 -0600 Subject: [PATCH 001/134] Allow user to specify port --- .env.docker | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.env.docker b/.env.docker index 2ed1c88904..4fae4718c9 100644 --- a/.env.docker +++ b/.env.docker @@ -21,7 +21,7 @@ TRUSTED_PROXIES=${TRUSTED_PROXIES} # If you use SQLite, set connection to `sqlite` and remove the database, username and password settings. DB_CONNECTION=mysql DB_HOST=${FF_DB_HOST} -DB_PORT=3306 +DB_PORT=${FF_DB_PORT} DB_DATABASE=${FF_DB_NAME} DB_USERNAME=${FF_DB_USER} DB_PASSWORD=${FF_DB_PASSWORD} @@ -88,4 +88,4 @@ DEMO_PASSWORD= IS_DOCKER=true IS_SANDSTORM=false IS_HEROKU=false -TZ=${TZ} \ No newline at end of file +TZ=${TZ} From d52d8d7970054b909fccd5cdfcb6bd341d0f4b84 Mon Sep 17 00:00:00 2001 From: James Cole Date: Wed, 7 Mar 2018 05:51:51 +0100 Subject: [PATCH 002/134] Expand exception code and fix demo user redirect. --- app/Exceptions/FireflyException.php | 3 ++- app/Exceptions/Handler.php | 3 ++- app/Http/Middleware/AuthenticateTwoFactor.php | 4 ++-- app/Http/Middleware/IsAdmin.php | 4 ++-- app/Http/Middleware/IsDemoUser.php | 14 ++++++++------ app/Http/Middleware/IsSandStormUser.php | 2 +- app/Http/Middleware/RedirectIfAuthenticated.php | 2 +- .../RedirectIfTwoFactorAuthenticated.php | 2 +- tests/Unit/Middleware/AuthenticateTest.php | 6 ++---- tests/Unit/Middleware/IsDemoUserTest.php | 4 +--- 10 files changed, 22 insertions(+), 22 deletions(-) diff --git a/app/Exceptions/FireflyException.php b/app/Exceptions/FireflyException.php index 538e094b06..b2c9916292 100644 --- a/app/Exceptions/FireflyException.php +++ b/app/Exceptions/FireflyException.php @@ -22,9 +22,10 @@ declare(strict_types=1); namespace FireflyIII\Exceptions; +use Exception; /** * Class FireflyException. */ -class FireflyException extends \Exception +class FireflyException extends Exception { } diff --git a/app/Exceptions/Handler.php b/app/Exceptions/Handler.php index 2dc4e0320c..a024203d97 100644 --- a/app/Exceptions/Handler.php +++ b/app/Exceptions/Handler.php @@ -70,14 +70,15 @@ class Handler extends ExceptionHandler return parent::render($request, $exception); } if ($exception instanceof NotFoundHttpException && $request->expectsJson()) { + // JSON error: return response()->json(['message' => 'Resource not found', 'exception' => 'NotFoundHttpException'], 404); } if ($exception instanceof AuthenticationException && $request->expectsJson()) { + // somehow Laravel handler does not catch this: return response()->json(['message' => 'Unauthenticated', 'exception' => 'AuthenticationException'], 401); } - if ($request->expectsJson()) { $isDebug = config('app.debug', false); if ($isDebug) { diff --git a/app/Http/Middleware/AuthenticateTwoFactor.php b/app/Http/Middleware/AuthenticateTwoFactor.php index ca6879d96c..97ed9bd749 100644 --- a/app/Http/Middleware/AuthenticateTwoFactor.php +++ b/app/Http/Middleware/AuthenticateTwoFactor.php @@ -61,7 +61,7 @@ class AuthenticateTwoFactor public function handle($request, Closure $next, ...$guards) { if ($this->auth->guest()) { - return redirect()->guest('login'); + return response()->redirectTo(route('login')); } $is2faEnabled = app('preferences')->get('twoFactorAuthEnabled', false)->data; @@ -71,7 +71,7 @@ class AuthenticateTwoFactor if ($is2faEnabled && $has2faSecret && !$is2faAuthed) { Log::debug('Does not seem to be 2 factor authed, redirect.'); - return redirect(route('two-factor.index')); + return response()->redirectTo(route('two-factor.index')); } return $next($request); diff --git a/app/Http/Middleware/IsAdmin.php b/app/Http/Middleware/IsAdmin.php index e06eecc07b..539cf378fe 100644 --- a/app/Http/Middleware/IsAdmin.php +++ b/app/Http/Middleware/IsAdmin.php @@ -48,12 +48,12 @@ class IsAdmin return response('Unauthorized.', 401); } - return redirect()->guest('login'); + return response()->redirectTo(route('login')); } /** @var User $user */ $user = auth()->user(); if (!$user->hasRole('owner')) { - return redirect(route('home')); + return response()->redirectTo(route('home')); } return $next($request); diff --git a/app/Http/Middleware/IsDemoUser.php b/app/Http/Middleware/IsDemoUser.php index 7f704adc14..10f110315d 100644 --- a/app/Http/Middleware/IsDemoUser.php +++ b/app/Http/Middleware/IsDemoUser.php @@ -23,9 +23,9 @@ declare(strict_types=1); namespace FireflyIII\Http\Middleware; use Closure; +use FireflyIII\Exceptions\IsDemoUserException; use FireflyIII\User; use Illuminate\Http\Request; -use Illuminate\Support\Facades\Auth; use Session; /** @@ -38,7 +38,6 @@ class IsDemoUser * * @param \Illuminate\Http\Request $request * @param \Closure $next - * @param string[] ...$guards * * @return mixed */ @@ -51,11 +50,14 @@ class IsDemoUser } if ($user->hasRole('demo')) { - Session::flash('info', strval(trans('firefly.not_available_demo_user'))); + $request->session()->flash('info', strval(trans('firefly.not_available_demo_user'))); + $current = $request->url(); + $previous = $request->session()->previousUrl(); + if ($current !== $previous) { + return response()->redirectTo($previous); + } - redirect($request->session()->previousUrl()); - - return $next($request); + return response()->redirectTo(route('index')); } return $next($request); diff --git a/app/Http/Middleware/IsSandStormUser.php b/app/Http/Middleware/IsSandStormUser.php index aba1be7020..4847fdef31 100644 --- a/app/Http/Middleware/IsSandStormUser.php +++ b/app/Http/Middleware/IsSandStormUser.php @@ -51,7 +51,7 @@ class IsSandStormUser if (1 === intval(getenv('SANDSTORM'))) { Session::flash('warning', strval(trans('firefly.sandstorm_not_available'))); - return redirect(route('index')); + return response()->redirectTo(route('index')); } return $next($request); diff --git a/app/Http/Middleware/RedirectIfAuthenticated.php b/app/Http/Middleware/RedirectIfAuthenticated.php index f318f14d5d..98d010590c 100644 --- a/app/Http/Middleware/RedirectIfAuthenticated.php +++ b/app/Http/Middleware/RedirectIfAuthenticated.php @@ -43,7 +43,7 @@ class RedirectIfAuthenticated public function handle($request, Closure $next, $guard = null) { if (Auth::guard($guard)->check()) { - return redirect(route('index')); + return response()->redirectTo(route('index')); } return $next($request); diff --git a/app/Http/Middleware/RedirectIfTwoFactorAuthenticated.php b/app/Http/Middleware/RedirectIfTwoFactorAuthenticated.php index 1827455932..f2b4f27e12 100644 --- a/app/Http/Middleware/RedirectIfTwoFactorAuthenticated.php +++ b/app/Http/Middleware/RedirectIfTwoFactorAuthenticated.php @@ -51,7 +51,7 @@ class RedirectIfTwoFactorAuthenticated $is2faAuthed = 'true' === $request->cookie('twoFactorAuthenticated'); if ($is2faEnabled && $has2faSecret && $is2faAuthed) { - return redirect(route('index')); + return response()->redirectTo(route('index')); } } diff --git a/tests/Unit/Middleware/AuthenticateTest.php b/tests/Unit/Middleware/AuthenticateTest.php index 39aff46071..b1022269dc 100644 --- a/tests/Unit/Middleware/AuthenticateTest.php +++ b/tests/Unit/Middleware/AuthenticateTest.php @@ -49,7 +49,6 @@ class AuthenticateTest extends TestCase public function testMiddlewareAjax() { Log::debug('Now at testMiddlewareAjax'); - //$this->withoutExceptionHandling(); $server = ['HTTP_X-Requested-With' => 'XMLHttpRequest']; $response = $this->get('/_test/authenticate', $server); $this->assertEquals(Response::HTTP_UNAUTHORIZED, $response->getStatusCode()); @@ -89,15 +88,14 @@ class AuthenticateTest extends TestCase public function testMiddlewareEmail() { Log::debug('Now at testMiddlewareEmail'); - //$this->withoutExceptionHandling(); $user = $this->user(); $user->blocked = 1; $user->blocked_code = 'email_changed'; $this->be($user); $response = $this->get('/_test/authenticate'); - //$this->assertEquals(Response::HTTP_FOUND, $response->getStatusCode()); + $this->assertEquals(Response::HTTP_FOUND, $response->getStatusCode()); $response->assertSessionHas('logoutMessage', strval(trans('firefly.email_changed_logout'))); - //$response->assertRedirect(route('login')); + $response->assertRedirect(route('login')); } /** diff --git a/tests/Unit/Middleware/IsDemoUserTest.php b/tests/Unit/Middleware/IsDemoUserTest.php index 40f36f4bb0..6e695cdfd9 100644 --- a/tests/Unit/Middleware/IsDemoUserTest.php +++ b/tests/Unit/Middleware/IsDemoUserTest.php @@ -39,7 +39,6 @@ class IsDemoUserTest extends TestCase */ public function testMiddlewareAuthenticated() { - $this->withoutExceptionHandling(); $this->be($this->user()); $response = $this->get('/_test/is-demo'); $this->assertEquals(Response::HTTP_OK, $response->getStatusCode()); @@ -50,7 +49,6 @@ class IsDemoUserTest extends TestCase */ public function testMiddlewareNotAuthenticated() { - $this->withoutExceptionHandling(); $response = $this->get('/_test/is-demo'); $this->assertEquals(Response::HTTP_OK, $response->getStatusCode()); } @@ -62,7 +60,7 @@ class IsDemoUserTest extends TestCase { $this->be($this->demoUser()); $response = $this->get('/_test/is-demo'); - $this->assertEquals(Response::HTTP_OK, $response->getStatusCode()); + $this->assertEquals(Response::HTTP_FOUND, $response->getStatusCode()); $response->assertSessionHas('info'); } From dd16e1b784fceef4ec9122001071273423c29f7f Mon Sep 17 00:00:00 2001 From: James Cole Date: Wed, 7 Mar 2018 05:52:34 +0100 Subject: [PATCH 003/134] Expand list of bills for #1102 --- resources/lang/en_US/firefly.php | 4 ++- resources/views/list/bills.twig | 62 ++++++++++++++++++++++++++++++-- 2 files changed, 63 insertions(+), 3 deletions(-) diff --git a/resources/lang/en_US/firefly.php b/resources/lang/en_US/firefly.php index e9c24d484a..99bc758bd0 100644 --- a/resources/lang/en_US/firefly.php +++ b/resources/lang/en_US/firefly.php @@ -170,7 +170,9 @@ return [ 'want_to_login' => 'I want to login', 'button_register' => 'Register', 'authorization' => 'Authorization', - + 'active_bills_only' => 'active bills only', + 'average_per_bill' => 'average per bill', + 'expected_total' => 'expected total', // API access 'authorization_request' => 'Firefly III v:version Authorization Request', 'authorization_request_intro' => ':client is requesting permission to access your financial administration. Would you like to authorize :client to access these records?', diff --git a/resources/views/list/bills.twig b/resources/views/list/bills.twig index 2a107273ed..0d37fddde7 100644 --- a/resources/views/list/bills.twig +++ b/resources/views/list/bills.twig @@ -16,7 +16,17 @@ + {% set sum_min =0 %} + {% set sum_max =0 %} + {% set expected_total = 0 %} + {% set count = 0 %} {% for entry in bills %} + {% if entry.active %} + {% set count = count + 1 %} + {% set sum_min = sum_min + entry.amount_min %} + {% set sum_max = sum_min + entry.amount_max %} + {% set expected_total = expected_total + ((entry.amount_min + entry.amount_max) / 2) %} + {% endif %}
0 and entry.active %} {% for date in entry.paid_dates %} - {{ formatDate(date, monthAndDayFormat) }}
+ {{ formatDate(date, monthAndDayFormat) }}
{% endfor %} @@ -119,9 +129,57 @@ {% endif %} - {% endfor %} + + + {{ 'sum'|_ }} ({{ 'active_bills_only'|_ }}) + + + {{ sum_min|formatAmount }} + + + + + {{ sum_max|formatAmount }} + + +   + + + {# calculate total#} + {% if count > 0 %} + {% set avg_min = (sum_min / count) %} + {% set avg_max = (sum_max / count) %} + {% else %} + {% set avg_min = 0 %} + {% set avg_max = 0 %} + {% endif %} + + + {{ 'average_per_bill'|_ }} ({{ 'active_bills_only'|_ }}) + + + {{ avg_min|formatAmount }} + + + + + {{ avg_max|formatAmount }} + + +   + + + {{ 'expected_total'|_ }} ({{ 'active_bills_only'|_ }}) + + + {{ expected_total|formatAmount }} + + +   + +
{{ paginator.render|raw }} From 6c63583e49053a9c2f96e60e00056cf35b71e6a7 Mon Sep 17 00:00:00 2001 From: James Cole Date: Wed, 7 Mar 2018 05:52:45 +0100 Subject: [PATCH 004/134] Fix test to always select correct journal. --- .../Triggers/ToAccountStartsTest.php | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/tests/Unit/TransactionRules/Triggers/ToAccountStartsTest.php b/tests/Unit/TransactionRules/Triggers/ToAccountStartsTest.php index 50d26f4b4e..afd8ea8715 100644 --- a/tests/Unit/TransactionRules/Triggers/ToAccountStartsTest.php +++ b/tests/Unit/TransactionRules/Triggers/ToAccountStartsTest.php @@ -36,8 +36,12 @@ class ToAccountStartsTest extends TestCase */ public function testTriggered() { - $journal = TransactionJournal::inRandomOrder()->whereNull('deleted_at')->first(); - $transaction = $journal->transactions()->where('amount', '>', 0)->first(); + $count = 0; + while ($count === 0) { + $journal = TransactionJournal::inRandomOrder()->whereNull('deleted_at')->first(); + $count = $journal->transactions()->where('amount', '>', 0)->count(); + $transaction = $journal->transactions()->where('amount', '>', 0)->first(); + } $account = $transaction->account; $trigger = ToAccountStarts::makeFromStrings(substr($account->name, 0, -3), false); @@ -50,8 +54,12 @@ class ToAccountStartsTest extends TestCase */ public function testTriggeredLonger() { - $journal = TransactionJournal::inRandomOrder()->whereNull('deleted_at')->first(); - $transaction = $journal->transactions()->where('amount', '>', 0)->first(); + $count = 0; + while ($count === 0) { + $journal = TransactionJournal::inRandomOrder()->whereNull('deleted_at')->first(); + $count = $journal->transactions()->where('amount', '>', 0)->count(); + $transaction = $journal->transactions()->where('amount', '>', 0)->first(); + } $account = $transaction->account; $trigger = ToAccountStarts::makeFromStrings('bla-bla-bla' . $account->name, false); From a5fd821e0c55324d1bb73e7eaad393036f35abb5 Mon Sep 17 00:00:00 2001 From: James Cole Date: Wed, 7 Mar 2018 10:18:22 +0100 Subject: [PATCH 005/134] Code to implement #1168 and #1197. --- app/Http/Controllers/PiggyBankController.php | 26 ++----- .../Transaction/ConvertController.php | 8 -- .../Transaction/SingleController.php | 57 +------------- .../Transaction/SplitController.php | 8 +- app/Support/ExpandedForm.php | 56 ++++++++++++++ config/twigbridge.php | 2 +- resources/views/piggy-banks/create.twig | 2 +- resources/views/piggy-banks/edit.twig | 2 +- resources/views/transactions/convert.twig | 6 +- .../views/transactions/single/create.twig | 4 +- resources/views/transactions/single/edit.twig | 4 +- resources/views/transactions/split/edit.twig | 11 +-- .../Controllers/PiggyBankControllerTest.php | 58 ++++++++------- .../Transaction/ConvertControllerTest.php | 74 +++++++++++++------ .../Transaction/SingleControllerTest.php | 29 +++----- .../Transaction/SplitControllerTest.php | 23 +++--- 16 files changed, 190 insertions(+), 180 deletions(-) diff --git a/app/Http/Controllers/PiggyBankController.php b/app/Http/Controllers/PiggyBankController.php index 7ba0315b5c..afc8279d20 100644 --- a/app/Http/Controllers/PiggyBankController.php +++ b/app/Http/Controllers/PiggyBankController.php @@ -23,11 +23,8 @@ declare(strict_types=1); namespace FireflyIII\Http\Controllers; use Carbon\Carbon; -use ExpandedForm; use FireflyIII\Http\Requests\PiggyBankFormRequest; -use FireflyIII\Models\AccountType; use FireflyIII\Models\PiggyBank; -use FireflyIII\Repositories\Account\AccountRepositoryInterface; use FireflyIII\Repositories\PiggyBank\PiggyBankRepositoryInterface; use Illuminate\Http\Request; use Illuminate\Pagination\LengthAwarePaginator; @@ -99,29 +96,20 @@ class PiggyBankController extends Controller } /** - * @param AccountRepositoryInterface $repository - * - * @return View + * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View */ - public function create(AccountRepositoryInterface $repository) + public function create() { - $accounts = ExpandedForm::makeSelectList($repository->getAccountsByType([AccountType::DEFAULT, AccountType::ASSET])); $subTitle = trans('firefly.new_piggy_bank'); $subTitleIcon = 'fa-plus'; - if (0 === count($accounts)) { - Session::flash('error', strval(trans('firefly.need_at_least_one_account'))); - - return redirect(route('new-user.index')); - } - // put previous url in session if not redirect from store (not "create another"). if (true !== session('piggy-banks.create.fromStore')) { $this->rememberPreviousUri('piggy-banks.create.uri'); } Session::forget('piggy-banks.create.fromStore'); - return view('piggy-banks.create', compact('accounts', 'subTitle', 'subTitleIcon')); + return view('piggy-banks.create', compact('subTitle', 'subTitleIcon')); } /** @@ -155,14 +143,12 @@ class PiggyBankController extends Controller } /** - * @param AccountRepositoryInterface $repository - * @param PiggyBank $piggyBank + * @param PiggyBank $piggyBank * * @return View */ - public function edit(AccountRepositoryInterface $repository, PiggyBank $piggyBank) + public function edit(PiggyBank $piggyBank) { - $accounts = ExpandedForm::makeSelectList($repository->getAccountsByType([AccountType::DEFAULT, AccountType::ASSET])); $subTitle = trans('firefly.update_piggy_title', ['name' => $piggyBank->name]); $subTitleIcon = 'fa-pencil'; $targetDate = null; @@ -191,7 +177,7 @@ class PiggyBankController extends Controller } Session::forget('piggy-banks.edit.fromUpdate'); - return view('piggy-banks.edit', compact('subTitle', 'subTitleIcon', 'piggyBank', 'accounts', 'preFilled')); + return view('piggy-banks.edit', compact('subTitle', 'subTitleIcon', 'piggyBank', 'preFilled')); } /** diff --git a/app/Http/Controllers/Transaction/ConvertController.php b/app/Http/Controllers/Transaction/ConvertController.php index 9541162376..5905de782f 100644 --- a/app/Http/Controllers/Transaction/ConvertController.php +++ b/app/Http/Controllers/Transaction/ConvertController.php @@ -22,11 +22,9 @@ declare(strict_types=1); namespace FireflyIII\Http\Controllers\Transaction; -use ExpandedForm; use FireflyIII\Exceptions\FireflyException; use FireflyIII\Http\Controllers\Controller; use FireflyIII\Models\Account; -use FireflyIII\Models\AccountType; use FireflyIII\Models\TransactionJournal; use FireflyIII\Models\TransactionType; use FireflyIII\Repositories\Account\AccountRepositoryInterface; @@ -40,9 +38,6 @@ use View; */ class ConvertController extends Controller { - /** @var AccountRepositoryInterface */ - private $accounts; - /** @var JournalRepositoryInterface */ private $repository; @@ -56,7 +51,6 @@ class ConvertController extends Controller // some useful repositories: $this->middleware( function ($request, $next) { - $this->accounts = app(AccountRepositoryInterface::class); $this->repository = app(JournalRepositoryInterface::class); app('view')->share('title', trans('firefly.transactions')); @@ -81,7 +75,6 @@ class ConvertController extends Controller } // @codeCoverageIgnoreEnd $positiveAmount = $this->repository->getJournalTotal($journal); - $assetAccounts = ExpandedForm::makeSelectList($this->accounts->getActiveAccountsByType([AccountType::DEFAULT, AccountType::ASSET])); $sourceType = $journal->transactionType; $subTitle = trans('firefly.convert_to_' . $destinationType->type, ['description' => $journal->description]); $subTitleIcon = 'fa-exchange'; @@ -110,7 +103,6 @@ class ConvertController extends Controller 'sourceType', 'destinationType', 'journal', - 'assetAccounts', 'positiveAmount', 'sourceAccount', 'destinationAccount', diff --git a/app/Http/Controllers/Transaction/SingleController.php b/app/Http/Controllers/Transaction/SingleController.php index 8dd3023290..d2b36e97e9 100644 --- a/app/Http/Controllers/Transaction/SingleController.php +++ b/app/Http/Controllers/Transaction/SingleController.php @@ -29,13 +29,10 @@ use FireflyIII\Events\UpdatedTransactionJournal; use FireflyIII\Helpers\Attachments\AttachmentHelperInterface; use FireflyIII\Http\Controllers\Controller; use FireflyIII\Http\Requests\JournalFormRequest; -use FireflyIII\Models\Account; -use FireflyIII\Models\AccountType; use FireflyIII\Models\Note; use FireflyIII\Models\Transaction; use FireflyIII\Models\TransactionJournal; use FireflyIII\Models\TransactionType; -use FireflyIII\Repositories\Account\AccountRepositoryInterface; use FireflyIII\Repositories\Budget\BudgetRepositoryInterface; use FireflyIII\Repositories\Currency\CurrencyRepositoryInterface; use FireflyIII\Repositories\Journal\JournalRepositoryInterface; @@ -51,9 +48,6 @@ use View; */ class SingleController extends Controller { - /** @var AccountRepositoryInterface */ - private $accounts; - /** @var AttachmentHelperInterface */ private $attachments; @@ -82,7 +76,6 @@ class SingleController extends Controller // some useful repositories: $this->middleware( function ($request, $next) { - $this->accounts = app(AccountRepositoryInterface::class); $this->budgets = app(BudgetRepositoryInterface::class); $this->piggyBanks = app(PiggyBankRepositoryInterface::class); $this->attachments = app(AttachmentHelperInterface::class); @@ -163,7 +156,6 @@ class SingleController extends Controller { $what = strtolower($what); $what = $request->old('what') ?? $what; - $assetAccounts = $this->groupedActiveAccountList(); $budgets = ExpandedForm::makeSelectListWithEmpty($this->budgets->getActiveBudgets()); $piggyBanks = $this->piggyBanks->getPiggyBanksWithAmount(); $piggies = ExpandedForm::makeSelectListWithEmpty($piggyBanks); @@ -192,7 +184,7 @@ class SingleController extends Controller return view( 'transactions.single.create', - compact('assetAccounts', 'subTitleIcon', 'budgets', 'what', 'piggies', 'subTitle', 'optionalFields', 'preFilled') + compact('subTitleIcon', 'budgets', 'what', 'piggies', 'subTitle', 'optionalFields', 'preFilled') ); } @@ -268,9 +260,8 @@ class SingleController extends Controller return redirect(route('transactions.split.edit', [$journal->id])); } - $what = strtolower($transactionType); - $assetAccounts = $this->groupedAccountList(); - $budgetList = ExpandedForm::makeSelectListWithEmpty($this->budgets->getBudgets()); + $what = strtolower($transactionType); + $budgetList = ExpandedForm::makeSelectListWithEmpty($this->budgets->getBudgets()); // view related code $subTitle = trans('breadcrumbs.edit_journal', ['description' => $journal->description]); @@ -330,7 +321,7 @@ class SingleController extends Controller return view( 'transactions.single.edit', - compact('journal', 'optionalFields', 'assetAccounts', 'what', 'budgetList', 'subTitle') + compact('journal', 'optionalFields', 'what', 'budgetList', 'subTitle') )->with('data', $preFilled); } @@ -440,46 +431,6 @@ class SingleController extends Controller return redirect($this->getPreviousUri('transactions.edit.uri')); } - /** - * @return array - */ - private function groupedAccountList(): array - { - $accounts = $this->accounts->getAccountsByType([AccountType::DEFAULT, AccountType::ASSET]); - $return = []; - /** @var Account $account */ - foreach ($accounts as $account) { - $type = $account->getMeta('accountRole'); - if (0 === strlen($type)) { - $type = 'no_account_type'; // @codeCoverageIgnore - } - $key = strval(trans('firefly.opt_group_' . $type)); - $return[$key][$account->id] = $account->name; - } - - return $return; - } - - /** - * @return array - */ - private function groupedActiveAccountList(): array - { - $accounts = $this->accounts->getActiveAccountsByType([AccountType::DEFAULT, AccountType::ASSET]); - $return = []; - /** @var Account $account */ - foreach ($accounts as $account) { - $type = $account->getMeta('accountRole'); - if (0 === strlen($type)) { - $type = 'no_account_type'; // @codeCoverageIgnore - } - $key = strval(trans('firefly.opt_group_' . $type)); - $return[$key][$account->id] = $account->name; - } - - return $return; - } - /** * @param TransactionJournal $journal * diff --git a/app/Http/Controllers/Transaction/SplitController.php b/app/Http/Controllers/Transaction/SplitController.php index b82633bef4..20c3fb9403 100644 --- a/app/Http/Controllers/Transaction/SplitController.php +++ b/app/Http/Controllers/Transaction/SplitController.php @@ -100,15 +100,13 @@ class SplitController extends Controller $uploadSize = min(Steam::phpBytes(ini_get('upload_max_filesize')), Steam::phpBytes(ini_get('post_max_size'))); $currencies = $this->currencies->get(); - $accountList = $this->accounts->getAccountsByType([AccountType::DEFAULT, AccountType::ASSET]); - $assetAccounts = ExpandedForm::makeSelectList($accountList); $optionalFields = Preferences::get('transaction_journal_optional_fields', [])->data; $budgets = ExpandedForm::makeSelectListWithEmpty($this->budgets->getActiveBudgets()); $preFilled = $this->arrayFromJournal($request, $journal); $subTitle = trans('breadcrumbs.edit_journal', ['description' => $journal->description]); $subTitleIcon = 'fa-pencil'; - - $accountArray = []; + $accountList = $this->accounts->getAccountsByType([AccountType::ASSET, AccountType::DEFAULT]); + $accountArray = []; // account array to display currency info: /** @var Account $account */ foreach ($accountList as $account) { @@ -159,7 +157,7 @@ class SplitController extends Controller // @codeCoverageIgnoreEnd $type = strtolower($this->repository->getTransactionType($journal)); - Session::flash('success', strval(trans('firefly.updated_' . $type, ['description' => $data['description']]))); + Session::flash('success', strval(trans('firefly.updated_' . $type, ['description' => $journal->description]))); Preferences::mark(); // @codeCoverageIgnoreStart diff --git a/app/Support/ExpandedForm.php b/app/Support/ExpandedForm.php index b04e92b11d..6af1139624 100644 --- a/app/Support/ExpandedForm.php +++ b/app/Support/ExpandedForm.php @@ -25,6 +25,10 @@ namespace FireflyIII\Support; use Amount as Amt; use Carbon\Carbon; use Eloquent; +use FireflyIII\Models\Account; +use FireflyIII\Models\AccountType; +use FireflyIII\Repositories\Account\AccountRepositoryInterface; +use FireflyIII\Repositories\Currency\CurrencyRepositoryInterface; use Illuminate\Support\Collection; use Illuminate\Support\MessageBag; use RuntimeException; @@ -61,6 +65,58 @@ class ExpandedForm return $this->currencyField($name, 'amount-small', $value, $options); } + /** + * @param string $name + * @param null $value + * @param array $options + * + * @return string + * @throws \Throwable + */ + public function assetAccountList(string $name, $value = null, array $options = []): string + { + // properties for cache + $cache = new CacheProperties; + $cache->addProperty('exp-form-asset-list'); + $cache->addProperty($name); + $cache->addProperty($value); + $cache->addProperty($options); + + if ($cache->has()) { + return $cache->get(); + } + // make repositories + /** @var AccountRepositoryInterface $repository */ + $repository = app(AccountRepositoryInterface::class); + /** @var CurrencyRepositoryInterface $currencyRepos */ + $currencyRepos = app(CurrencyRepositoryInterface::class); + + $assetAccounts = $repository->getAccountsByType([AccountType::ASSET, AccountType::DEFAULT]); + $defaultCurrency = app('amount')->getDefaultCurrency(); + $grouped = []; + // group accounts: + /** @var Account $account */ + foreach ($assetAccounts as $account) { + $balance = app('steam')->balance($account, new Carbon); + $currencyId = intval($account->getMeta('currency_id')); + $currency = $currencyRepos->findNull($currencyId); + $role = $account->getMeta('accountRole'); + if (0 === strlen($role)) { + $role = 'no_account_type'; // @codeCoverageIgnore + } + if (is_null($currency)) { + $currency = $defaultCurrency; + } + + $key = strval(trans('firefly.opt_group_' . $role)); + $grouped[$key][$account->id] = $account->name . ' (' . app('amount')->formatAnything($currency, $balance, false) . ')'; + } + $res = $this->select($name, $grouped, $value, $options); + $cache->store($res); + + return $res; + } + /** * @param $name * @param null $value diff --git a/config/twigbridge.php b/config/twigbridge.php index 5d7467be5b..2433a298c2 100644 --- a/config/twigbridge.php +++ b/config/twigbridge.php @@ -176,7 +176,7 @@ return [ 'is_safe' => [ 'date', 'text', 'select', 'balance', 'optionsList', 'checkbox', 'amount', 'tags', 'integer', 'textarea', 'location', 'multiRadio', 'file', 'multiCheckbox', 'staticText', 'amountSmall', 'password', 'nonSelectableBalance', 'nonSelectableAmount', - 'number', + 'number', 'assetAccountList', ], ], 'Form' => [ diff --git a/resources/views/piggy-banks/create.twig b/resources/views/piggy-banks/create.twig index 439177c5d7..ecedf82dc2 100644 --- a/resources/views/piggy-banks/create.twig +++ b/resources/views/piggy-banks/create.twig @@ -18,7 +18,7 @@
{{ ExpandedForm.text('name') }} - {{ ExpandedForm.select('account_id',accounts,null,{'label' : 'saveOnAccount'|_}) }} + {{ ExpandedForm.assetAccountList('account_id', null, {label: 'saveOnAccount'|_ }) }} {{ ExpandedForm.amount('targetamount') }}
diff --git a/resources/views/piggy-banks/edit.twig b/resources/views/piggy-banks/edit.twig index 54dbb62500..427a9670a5 100644 --- a/resources/views/piggy-banks/edit.twig +++ b/resources/views/piggy-banks/edit.twig @@ -19,7 +19,7 @@
{{ ExpandedForm.text('name') }} - {{ ExpandedForm.select('account_id',accounts,null,{'label' : 'saveOnAccount'|_}) }} + {{ ExpandedForm.assetAccountList('account_id', null, {label: 'saveOnAccount'|_ }) }} {{ ExpandedForm.amount('targetamount') }}
diff --git a/resources/views/transactions/convert.twig b/resources/views/transactions/convert.twig index f51af285fe..8ab8cedb31 100644 --- a/resources/views/transactions/convert.twig +++ b/resources/views/transactions/convert.twig @@ -92,8 +92,7 @@

- {{ ExpandedForm.select('destination_account_asset', assetAccounts) }} - + {{ ExpandedForm.assetAccountList('destination_account_asset', null) }} {% endif %} @@ -146,8 +145,7 @@

- - {{ ExpandedForm.select('source_account_asset', assetAccounts) }} + {{ ExpandedForm.assetAccountList('source_account_asset', null) }} {% endif %} {# FIVE #} diff --git a/resources/views/transactions/single/create.twig b/resources/views/transactions/single/create.twig index e8f2f7bde5..bdad680bf9 100644 --- a/resources/views/transactions/single/create.twig +++ b/resources/views/transactions/single/create.twig @@ -33,7 +33,7 @@ {{ ExpandedForm.text('description') }} {# SELECTABLE SOURCE ACCOUNT ONLY FOR WITHDRAWALS AND TRANSFERS #} - {{ ExpandedForm.select('source_account_id', assetAccounts, null, {label: trans('form.asset_source_account')}) }} + {{ ExpandedForm.assetAccountList('source_account_id', null, {label: trans('form.asset_source_account')}) }} {# FREE FORMAT SOURCE ACCOUNT ONLY FOR DEPOSITS #} {{ ExpandedForm.text('source_account_name', null, {label: trans('form.revenue_account')}) }} @@ -42,7 +42,7 @@ {{ ExpandedForm.text('destination_account_name', null, {label: trans('form.expense_account')}) }} {# SELECTABLE DESTINATION ACCOUNT ONLY FOR TRANSFERS AND DEPOSITS #} - {{ ExpandedForm.select('destination_account_id', assetAccounts, null, {label: trans('form.asset_destination_account')} ) }} + {{ ExpandedForm.assetAccountList('destination_account_id', null, {label: trans('form.asset_destination_account')} ) }} {# ALWAYS SHOW AMOUNT #} {{ ExpandedForm.amount('amount') }} diff --git a/resources/views/transactions/single/edit.twig b/resources/views/transactions/single/edit.twig index b3c2241db2..aba0cb3a51 100644 --- a/resources/views/transactions/single/edit.twig +++ b/resources/views/transactions/single/edit.twig @@ -38,7 +38,7 @@ {# SELECTABLE SOURCE ACCOUNT ONLY FOR WITHDRAWALS AND TRANSFERS #} {% if what == 'transfer' or what == 'withdrawal' %} - {{ ExpandedForm.select('source_account_id',assetAccounts, data.source_account_id, {label: trans('form.asset_source_account')}) }} + {{ ExpandedForm.assetAccountList('source_account_id', data.source_account_id, {label: trans('form.asset_source_account')}) }} {% endif %} {# FREE FORMAT SOURCE ACCOUNT ONLY FOR DEPOSITS #} @@ -53,7 +53,7 @@ {# SELECTABLE DESTINATION ACCOUNT ONLY FOR TRANSFERS AND DEPOSITS #} {% if what == 'transfer' or what == 'deposit' %} - {{ ExpandedForm.select('destination_account_id',assetAccounts, data.destination_account_id, {label: trans('form.asset_destination_account')} ) }} + {{ ExpandedForm.assetAccountList('destination_account_id', data.destination_account_id, {label: trans('form.asset_destination_account')} ) }} {% endif %} {# ALWAYS SHOW AMOUNT #} diff --git a/resources/views/transactions/split/edit.twig b/resources/views/transactions/split/edit.twig index 5859ec3f6f..e26cc3b229 100644 --- a/resources/views/transactions/split/edit.twig +++ b/resources/views/transactions/split/edit.twig @@ -43,17 +43,12 @@ {# show source if withdrawal or transfer #} {% if preFilled.what == 'withdrawal' or preFilled.what == 'transfer' %} - {{ ExpandedForm.select('journal_source_account_id', assetAccounts, preFilled.journal_source_account_id) }} + {{ ExpandedForm.assetAccountList('journal_source_account_id', preFilled.journal_source_account_id) }} {% endif %} {# show destination account id, if deposit (is asset): #} - {% if preFilled.what == 'deposit' %} - {{ ExpandedForm.select('journal_destination_account_id', assetAccounts, preFilled.journal_destination_account_id) }} - {% endif %} - - {# show static destination if transfer #} - {% if preFilled.what == 'transfer' %} - {{ ExpandedForm.select('journal_destination_account_id', assetAccounts, preFilled.journal_destination_account_id) }} + {% if preFilled.what == 'deposit' or preFilled.what == 'transfer' %} + {{ ExpandedForm.assetAccountList('journal_destination_account_id', preFilled.journal_destination_account_id) }} {% endif %} {# TOTAL AMOUNT IS STATIC TEXT #} diff --git a/tests/Feature/Controllers/PiggyBankControllerTest.php b/tests/Feature/Controllers/PiggyBankControllerTest.php index 90460a3bb7..61b8294b02 100644 --- a/tests/Feature/Controllers/PiggyBankControllerTest.php +++ b/tests/Feature/Controllers/PiggyBankControllerTest.php @@ -22,11 +22,14 @@ declare(strict_types=1); namespace Tests\Feature\Controllers; +use Amount; use FireflyIII\Models\Account; use FireflyIII\Models\AccountType; use FireflyIII\Models\PiggyBank; +use FireflyIII\Models\TransactionCurrency; use FireflyIII\Models\TransactionJournal; use FireflyIII\Repositories\Account\AccountRepositoryInterface; +use FireflyIII\Repositories\Currency\CurrencyRepositoryInterface; use FireflyIII\Repositories\Journal\JournalRepositoryInterface; use FireflyIII\Repositories\PiggyBank\PiggyBankRepositoryInterface; use Illuminate\Support\Collection; @@ -80,12 +83,25 @@ class PiggyBankControllerTest extends TestCase public function testCreate() { // mock stuff - $account = factory(Account::class)->make(); - $accountRepos = $this->mock(AccountRepositoryInterface::class); + + $journalRepos = $this->mock(JournalRepositoryInterface::class); - $journalRepos->shouldReceive('first')->once()->andReturn(new TransactionJournal); + + // new account list thing. + $currency = TransactionCurrency::first(); + $account = factory(Account::class)->make(); + $currencyRepos = $this->mock(CurrencyRepositoryInterface::class); + $currencyRepos->shouldReceive('findNull')->andReturn($currency); + + $accountRepos = $this->mock(AccountRepositoryInterface::class); $accountRepos->shouldReceive('getAccountsByType') - ->withArgs([[AccountType::DEFAULT, AccountType::ASSET]])->andReturn(new Collection([$account]))->once(); + ->withArgs([[AccountType::ASSET, AccountType::DEFAULT]])->andReturn(new Collection([$account]))->once(); + + Amount::shouldReceive('getDefaultCurrency')->andReturn($currency); + Amount::shouldReceive('balance')->andReturn('0'); + + $journalRepos->shouldReceive('first')->once()->andReturn(new TransactionJournal); + $this->be($this->user()); $response = $this->get(route('piggy-banks.create')); @@ -93,25 +109,6 @@ class PiggyBankControllerTest extends TestCase $response->assertSee('