diff --git a/app/Console/Commands/Upgrade/TransferCurrenciesCorrections.php b/app/Console/Commands/Upgrade/TransferCurrenciesCorrections.php index e1a72e6a93..bcb5582f26 100644 --- a/app/Console/Commands/Upgrade/TransferCurrenciesCorrections.php +++ b/app/Console/Commands/Upgrade/TransferCurrenciesCorrections.php @@ -319,11 +319,13 @@ class TransferCurrenciesCorrections extends Command // both accounts must have currency preference: // @codeCoverageIgnoreStart if ($this->isNoCurrencyPresent()) { + $this->error( + sprintf('Source or destination accounts for transaction journal #%d have no currency information. Cannot fix this one.', $transfer->id)); + return; } // @codeCoverageIgnoreEnd - // fix source transaction having no currency. $this->fixSourceNoCurrency(); @@ -397,8 +399,6 @@ class TransferCurrenciesCorrections extends Command null === $this->sourceTransaction->foreign_amount && (int)$this->sourceTransaction->transaction_currency_id !== (int)$this->sourceCurrency->id ) { - - $message = sprintf( 'Transaction #%d has a currency setting #%d that should be #%d. Amount remains %s, currency is changed.', $this->sourceTransaction->id, diff --git a/app/Http/Controllers/Account/ShowController.php b/app/Http/Controllers/Account/ShowController.php index b2a32c327d..cd5bee7207 100644 --- a/app/Http/Controllers/Account/ShowController.php +++ b/app/Http/Controllers/Account/ShowController.php @@ -24,7 +24,7 @@ declare(strict_types=1); namespace FireflyIII\Http\Controllers\Account; use Carbon\Carbon; -use FireflyIII\Exceptions\FireflyException; +use Exception; use FireflyIII\Helpers\Collector\GroupCollectorInterface; use FireflyIII\Http\Controllers\Controller; use FireflyIII\Models\Account; @@ -36,7 +36,6 @@ use FireflyIII\Support\Http\Controllers\UserNavigation; use Illuminate\Http\Request; use Illuminate\Support\Collection; use View; -use Exception; /** * Class ShowController @@ -101,17 +100,18 @@ class ShowController extends Controller [$start, $end] = [$end, $start]; // @codeCoverageIgnore } - $objectType = config(sprintf('firefly.shortNamesByFullName.%s', $account->accountType->type)); - $today = new Carbon; - $subTitleIcon = config(sprintf('firefly.subIconsByIdentifier.%s', $account->accountType->type)); - $page = (int)$request->get('page'); - $pageSize = (int)app('preferences')->get('listPageSize', 50)->data; - $currency = $this->repository->getAccountCurrency($account) ?? app('amount')->getDefaultCurrency(); - $fStart = $start->formatLocalized($this->monthAndDayFormat); - $fEnd = $end->formatLocalized($this->monthAndDayFormat); - $subTitle = (string)trans('firefly.journals_in_period_for_account', ['name' => $account->name, 'start' => $fStart, 'end' => $fEnd]); - $chartUri = route('chart.account.period', [$account->id, $start->format('Y-m-d'), $end->format('Y-m-d')]); - $periods = $this->getAccountPeriodOverview($account, $end); + $objectType = config(sprintf('firefly.shortNamesByFullName.%s', $account->accountType->type)); + $today = new Carbon; + $subTitleIcon = config(sprintf('firefly.subIconsByIdentifier.%s', $account->accountType->type)); + $page = (int)$request->get('page'); + $pageSize = (int)app('preferences')->get('listPageSize', 50)->data; + $currency = $this->repository->getAccountCurrency($account) ?? app('amount')->getDefaultCurrency(); + $fStart = $start->formatLocalized($this->monthAndDayFormat); + $fEnd = $end->formatLocalized($this->monthAndDayFormat); + $subTitle = (string)trans('firefly.journals_in_period_for_account', ['name' => $account->name, 'start' => $fStart, 'end' => $fEnd]); + $chartUri = route('chart.account.period', [$account->id, $start->format('Y-m-d'), $end->format('Y-m-d')]); + $firstTransaction = $this->repository->oldestJournalDate($account) ?? $start; + $periods = $this->getAccountPeriodOverview($account, $firstTransaction, $end); /** @var GroupCollectorInterface $collector */ $collector = app(GroupCollectorInterface::class); @@ -138,10 +138,10 @@ class ShowController extends Controller * * @param Request $request * @param Account $account - * @throws Exception * @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector|View * * + * @throws Exception */ public function showAll(Request $request, Account $account) { diff --git a/app/Http/Controllers/Admin/ConfigurationController.php b/app/Http/Controllers/Admin/ConfigurationController.php index f9932b5236..f4b7982268 100644 --- a/app/Http/Controllers/Admin/ConfigurationController.php +++ b/app/Http/Controllers/Admin/ConfigurationController.php @@ -37,13 +37,14 @@ class ConfigurationController extends Controller { /** * ConfigurationController constructor. + * @codeCoverageIgnore */ public function __construct() { parent::__construct(); $this->middleware( - function ($request, $next) { + static function ($request, $next) { app('view')->share('title', (string)trans('firefly.administration')); app('view')->share('mainTitleIcon', 'fa-hand-spock-o'); diff --git a/app/Http/Controllers/Admin/HomeController.php b/app/Http/Controllers/Admin/HomeController.php index 16733d64f5..514185b49c 100644 --- a/app/Http/Controllers/Admin/HomeController.php +++ b/app/Http/Controllers/Admin/HomeController.php @@ -37,6 +37,7 @@ class HomeController extends Controller { /** * ConfigurationController constructor. + * @codeCoverageIgnore */ public function __construct() { diff --git a/app/Http/Controllers/Admin/LinkController.php b/app/Http/Controllers/Admin/LinkController.php index 4a3a3afcea..73a23be304 100644 --- a/app/Http/Controllers/Admin/LinkController.php +++ b/app/Http/Controllers/Admin/LinkController.php @@ -36,8 +36,13 @@ use View; */ class LinkController extends Controller { + + /** @var LinkTypeRepositoryInterface */ + private $repository; + /** * LinkController constructor. + * @codeCoverageIgnore */ public function __construct() { @@ -47,6 +52,7 @@ class LinkController extends Controller function ($request, $next) { app('view')->share('title', (string)trans('firefly.administration')); app('view')->share('mainTitleIcon', 'fa-hand-spock-o'); + $this->repository = app(LinkTypeRepositoryInterface::class); return $next($request); } @@ -61,11 +67,11 @@ class LinkController extends Controller */ public function create() { + Log::channel('audit')->info('User visits link index.'); + $subTitle = (string)trans('firefly.create_new_link_type'); $subTitleIcon = 'fa-link'; - Log::channel('audit')->info('User visits link index.'); - // put previous url in session if not redirect from store (not "create another"). if (true !== session('link-types.create.fromStore')) { $this->rememberPreviousUri('link-types.create.uri'); @@ -77,13 +83,12 @@ class LinkController extends Controller /** * Delete a link form. * - * @param Request $request - * @param LinkTypeRepositoryInterface $repository - * @param LinkType $linkType + * @param Request $request + * @param LinkType $linkType * * @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector|View */ - public function delete(Request $request, LinkTypeRepositoryInterface $repository, LinkType $linkType) + public function delete(Request $request, LinkType $linkType) { if (!$linkType->editable) { $request->session()->flash('error', (string)trans('firefly.cannot_edit_link_type', ['name' => $linkType->name])); @@ -92,18 +97,19 @@ class LinkController extends Controller } Log::channel('audit')->info(sprintf('User wants to delete link type #%d', $linkType->id)); - $subTitle = (string)trans('firefly.delete_link_type', ['name' => $linkType->name]); - $otherTypes = $repository->get(); - $count = $repository->countJournals($linkType); + $otherTypes = $this->repository->get(); + $count = $this->repository->countJournals($linkType); $moveTo = []; $moveTo[0] = (string)trans('firefly.do_not_save_connection'); + /** @var LinkType $otherType */ foreach ($otherTypes as $otherType) { if ($otherType->id !== $linkType->id) { $moveTo[$otherType->id] = sprintf('%s (%s / %s)', $otherType->name, $otherType->inward, $otherType->outward); } } + // put previous url in session $this->rememberPreviousUri('link-types.delete.uri'); @@ -113,18 +119,17 @@ class LinkController extends Controller /** * Actually destroy the link. * - * @param Request $request - * @param LinkTypeRepositoryInterface $repository - * @param LinkType $linkType + * @param Request $request + * @param LinkType $linkType * * @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector */ - public function destroy(Request $request, LinkTypeRepositoryInterface $repository, LinkType $linkType) + public function destroy(Request $request, LinkType $linkType) { Log::channel('audit')->info(sprintf('User destroyed link type #%d', $linkType->id)); $name = $linkType->name; - $moveTo = $repository->findNull((int)$request->get('move_link_type_before_delete')); - $repository->destroy($linkType, $moveTo); + $moveTo = $this->repository->findNull((int)$request->get('move_link_type_before_delete')); + $this->repository->destroy($linkType, $moveTo); $request->session()->flash('success', (string)trans('firefly.deleted_link_type', ['name' => $name])); app('preferences')->mark(); @@ -135,7 +140,7 @@ class LinkController extends Controller /** * Edit a link form. * - * @param Request $request + * @param Request $request * @param LinkType $linkType * * @return \Illuminate\Contracts\View\Factory|\Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector|\Illuminate\View\View @@ -164,20 +169,18 @@ class LinkController extends Controller /** * Show index of all links. * - * @param LinkTypeRepositoryInterface $repository - * * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View */ - public function index(LinkTypeRepositoryInterface $repository) + public function index() { $subTitle = (string)trans('firefly.journal_link_configuration'); $subTitleIcon = 'fa-link'; - $linkTypes = $repository->get(); + $linkTypes = $this->repository->get(); Log::channel('audit')->info('User on index of link types in admin.'); $linkTypes->each( - function (LinkType $linkType) use ($repository) { - $linkType->journalCount = $repository->countJournals($linkType); + function (LinkType $linkType) { + $linkType->journalCount = $this->repository->countJournals($linkType); } ); @@ -195,7 +198,7 @@ class LinkController extends Controller { $subTitle = (string)trans('firefly.overview_for_link', ['name' => $linkType->name]); $subTitleIcon = 'fa-link'; - $links = $linkType->transactionJournalLinks()->get(); + $links = $this->repository->getJournalLinks($linkType); Log::channel('audit')->info(sprintf('User viewing link type #%d', $linkType->id)); @@ -205,19 +208,18 @@ class LinkController extends Controller /** * Store the new link. * - * @param LinkTypeFormRequest $request - * @param LinkTypeRepositoryInterface $repository + * @param LinkTypeFormRequest $request * * @return $this|\Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector */ - public function store(LinkTypeFormRequest $request, LinkTypeRepositoryInterface $repository) + public function store(LinkTypeFormRequest $request) { $data = [ 'name' => $request->string('name'), 'inward' => $request->string('inward'), 'outward' => $request->string('outward'), ]; - $linkType = $repository->store($data); + $linkType = $this->repository->store($data); Log::channel('audit')->info('User stored new link type.', $linkType->toArray()); @@ -237,13 +239,12 @@ class LinkController extends Controller /** * Update an existing link. * - * @param LinkTypeFormRequest $request - * @param LinkTypeRepositoryInterface $repository - * @param LinkType $linkType + * @param LinkTypeFormRequest $request + * @param LinkType $linkType * * @return $this|\Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector */ - public function update(LinkTypeFormRequest $request, LinkTypeRepositoryInterface $repository, LinkType $linkType) + public function update(LinkTypeFormRequest $request, LinkType $linkType) { if (!$linkType->editable) { $request->session()->flash('error', (string)trans('firefly.cannot_edit_link_type', ['name' => $linkType->name])); @@ -256,7 +257,7 @@ class LinkController extends Controller 'inward' => $request->string('inward'), 'outward' => $request->string('outward'), ]; - $repository->update($linkType, $data); + $this->repository->update($linkType, $data); Log::channel('audit')->info(sprintf('User update link type #%d.', $linkType->id), $data); diff --git a/app/Http/Controllers/Admin/UserController.php b/app/Http/Controllers/Admin/UserController.php index 683269c659..328c3aeec7 100644 --- a/app/Http/Controllers/Admin/UserController.php +++ b/app/Http/Controllers/Admin/UserController.php @@ -35,6 +35,9 @@ use Log; */ class UserController extends Controller { + /** @var UserRepositoryInterface */ + private $repository; + /** * UserController constructor. */ @@ -46,7 +49,7 @@ class UserController extends Controller function ($request, $next) { app('view')->share('title', (string)trans('firefly.administration')); app('view')->share('mainTitleIcon', 'fa-hand-spock-o'); - + $this->repository = app(UserRepositoryInterface::class); return $next($request); } ); @@ -72,13 +75,12 @@ class UserController extends Controller * Destroy a user. * * @param User $user - * @param UserRepositoryInterface $repository * * @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector */ - public function destroy(User $user, UserRepositoryInterface $repository) + public function destroy(User $user) { - $repository->destroy($user); + $this->repository->destroy($user); session()->flash('success', (string)trans('firefly.user_deleted')); return redirect(route('admin.users')); @@ -114,22 +116,20 @@ class UserController extends Controller /** * Show index of user manager. * - * @param UserRepositoryInterface $repository - * * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View */ - public function index(UserRepositoryInterface $repository) + public function index() { $subTitle = (string)trans('firefly.user_administration'); $subTitleIcon = 'fa-users'; - $users = $repository->all(); + $users = $this->repository->all(); // add meta stuff. $users->each( - function (User $user) use ($repository) { + function (User $user) { $list = ['twoFactorAuthEnabled', 'twoFactorAuthSecret']; $preferences = app('preferences')->getArrayForUser($user, $list); - $user->isAdmin = $repository->hasRole($user, 'owner'); + $user->isAdmin = $this->repository->hasRole($user, 'owner'); $is2faEnabled = 1 === $preferences['twoFactorAuthEnabled']; $has2faSecret = null !== $preferences['twoFactorAuthSecret']; $user->has2FA = ($is2faEnabled && $has2faSecret); @@ -143,18 +143,17 @@ class UserController extends Controller /** * Show single user. * - * @param UserRepositoryInterface $repository * @param User $user * * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View */ - public function show(UserRepositoryInterface $repository, User $user) + public function show(User $user) { $title = (string)trans('firefly.administration'); $mainTitleIcon = 'fa-hand-spock-o'; $subTitle = (string)trans('firefly.single_user_administration', ['email' => $user->email]); $subTitleIcon = 'fa-user'; - $information = $repository->getUserData($user); + $information = $this->repository->getUserData($user); return view( 'admin.users.show', compact( @@ -168,22 +167,21 @@ class UserController extends Controller * * @param UserFormRequest $request * @param User $user - * @param UserRepositoryInterface $repository * * @return $this|\Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector */ - public function update(UserFormRequest $request, User $user, UserRepositoryInterface $repository) + public function update(UserFormRequest $request, User $user) { Log::debug('Actually here'); $data = $request->getUserData(); // update password if ('' !== $data['password']) { - $repository->changePassword($user, $data['password']); + $this->repository->changePassword($user, $data['password']); } - $repository->changeStatus($user, $data['blocked'], $data['blocked_code']); - $repository->updateEmail($user, $data['email']); + $this->repository->changeStatus($user, $data['blocked'], $data['blocked_code']); + $this->repository->updateEmail($user, $data['email']); session()->flash('success', (string)trans('firefly.updated_user', ['email' => $user->email])); app('preferences')->mark(); diff --git a/app/Http/Controllers/Auth/ForgotPasswordController.php b/app/Http/Controllers/Auth/ForgotPasswordController.php index 1ce51d9dab..02e886339b 100644 --- a/app/Http/Controllers/Auth/ForgotPasswordController.php +++ b/app/Http/Controllers/Auth/ForgotPasswordController.php @@ -33,6 +33,7 @@ use Log; /** * Class ForgotPasswordController + * @codeCoverageIgnore */ class ForgotPasswordController extends Controller { @@ -72,6 +73,7 @@ class ForgotPasswordController extends Controller $this->validateEmail($request); // verify if the user is not a demo user. If so, we give him back an error. + /** @var User $user */ $user = User::where('email', $request->get('email'))->first(); if (null !== $user && $repository->hasRole($user, 'demo')) { diff --git a/app/Http/Controllers/Budget/AmountController.php b/app/Http/Controllers/Budget/AmountController.php index 36a4e36f2b..5fc6194a91 100644 --- a/app/Http/Controllers/Budget/AmountController.php +++ b/app/Http/Controllers/Budget/AmountController.php @@ -69,22 +69,25 @@ class AmountController extends Controller /** - * Set the amount for a single budget in a specific period. Shows a waring when its a lot. + * Set the amount for a single budget in a specific period. * * @param Request $request - * @param BudgetRepositoryInterface $repository * @param Budget $budget * * @return JsonResponse * * @SuppressWarnings(PHPMD.ExcessiveMethodLength) */ - public function amount(Request $request, BudgetRepositoryInterface $repository, Budget $budget): JsonResponse + public function amount(Request $request, Budget $budget): JsonResponse { // grab vars from URI $amount = (string)$request->get('amount'); - $start = Carbon::createFromFormat('Y-m-d', $request->get('start')); - $end = Carbon::createFromFormat('Y-m-d', $request->get('end')); + + /** @var Carbon $start */ + $start = Carbon::createFromFormat('Y-m-d', $request->get('start')); + + /** @var Carbon $end */ + $end = Carbon::createFromFormat('Y-m-d', $request->get('end')); // grab other useful vars $currency = app('amount')->getDefaultCurrency(); @@ -95,11 +98,11 @@ class AmountController extends Controller $budgetLimit = $this->repository->updateLimitAmount($budget, $start, $end, $amount); // calculate what the user has spent in current period. - $spent = $repository->spentInPeriod(new Collection([$budget]), new Collection, $start, $end); + $spent = $this->repository->spentInPeriod(new Collection([$budget]), new Collection, $start, $end); // given the new budget, this is what they have left (and left per day?) $left = app('amount')->formatAnything($currency, bcadd($amount, $spent), true); - $leftPerDay = null; // + $leftPerDay = null; // If the user budgets ANY amount per day for this budget (anything but zero) Firefly III calculates how much he could spend per day. if (1 === bccomp(bcadd($amount, $spent), '0')) { @@ -113,7 +116,7 @@ class AmountController extends Controller // If the difference is very large, give the user a notification. $average = $this->repository->budgetedPerDay($budget); $current = bcdiv($amount, (string)$periodLength); - if (bccomp(bcmul('1.1', $average), $current) === -1) { + if (bccomp(bcmul('1.3', $average), $current) === -1) { $largeDiff = true; $warnText = (string)trans( 'firefly.over_budget_warn', @@ -141,68 +144,6 @@ class AmountController extends Controller ); } - - /** - * Shows some basic info about the income and the suggested budget. - * - * @param Carbon $start - * @param Carbon $end - * TODO remove this feature - * - * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View - */ - public function infoIncome(Carbon $start, Carbon $end) - { - $range = app('preferences')->get('viewRange', '1M')->data; - /** @var Carbon $searchBegin */ - $searchBegin = app('navigation')->subtractPeriod($start, $range, 3); - $searchEnd = app('navigation')->addPeriod($end, $range, 3); - $daysInPeriod = $start->diffInDays($end); - $daysInSearchPeriod = $searchBegin->diffInDays($searchEnd); - $average = $this->repository->getAverageAvailable($start, $end); - $available = bcmul($average, (string)$daysInPeriod); - - Log::debug(sprintf('Average is %s, so total available is %s because days is %d.', $average, $available, $daysInPeriod)); - - // amount earned in this period: - /** @var GroupCollectorInterface $collector */ - $collector = app(GroupCollectorInterface::class); - $collector->setRange($searchBegin, $searchEnd)->setTypes([TransactionType::DEPOSIT]); - $earned = $collector->getSum(); - // Total amount earned divided by the number of days in the whole search period is the average amount earned per day. - // This is multiplied by the number of days in the current period, showing you the average. - $earnedAverage = bcmul(bcdiv($earned, (string)$daysInSearchPeriod), (string)$daysInPeriod); - - Log::debug(sprintf('Earned is %s, earned average is %s', $earned, $earnedAverage)); - - // amount spent in period - /** @var GroupCollectorInterface $collector */ - $collector = app(GroupCollectorInterface::class); - $collector->setRange($searchBegin, $searchEnd)->setTypes([TransactionType::WITHDRAWAL]); - $spent = $collector->getSum(); - $spentAverage = app('steam')->positive(bcmul(bcdiv($spent, (string)$daysInSearchPeriod), (string)$daysInPeriod)); - - Log::debug(sprintf('Spent is %s, spent average is %s', $earned, $earnedAverage)); - - // the default suggestion is the money the user has spent, on average, over this period. - $suggested = $spentAverage; - - Log::debug(sprintf('Suggested is now %s (spent average)', $suggested)); - - // if the user makes less per period, suggest that amount instead. - if (1 === bccomp($spentAverage, $earnedAverage)) { - Log::debug( - sprintf('Because earned average (%s) is less than spent average (%s) will suggest earned average instead.', $earnedAverage, $spentAverage) - ); - $suggested = $earnedAverage; - } - - $result = ['available' => $available, 'earned' => $earnedAverage, 'spent' => $spentAverage, 'suggested' => $suggested,]; - - return view('budgets.info', compact('result', 'searchBegin', 'searchEnd', 'start', 'end')); - } - - /** * Store an available budget for the current period. * @@ -212,7 +153,9 @@ class AmountController extends Controller */ public function postUpdateIncome(BudgetIncomeRequest $request): RedirectResponse { + /** @var Carbon $start */ $start = Carbon::createFromFormat('Y-m-d', $request->string('start')); + /** @var Carbon $end */ $end = Carbon::createFromFormat('Y-m-d', $request->string('end')); $defaultCurrency = app('amount')->getDefaultCurrency(); $amount = $request->get('amount'); @@ -240,6 +183,6 @@ class AmountController extends Controller $available = round($available, $defaultCurrency->decimal_places); $page = (int)$request->get('page'); - return view('budgets.income', compact('available', 'start', 'end', 'page')); + return view('budgets.income', compact('available', 'start', 'end', 'page','defaultCurrency')); } } diff --git a/app/Http/Controllers/Budget/CreateController.php b/app/Http/Controllers/Budget/CreateController.php index daa47876d9..eb930fba73 100644 --- a/app/Http/Controllers/Budget/CreateController.php +++ b/app/Http/Controllers/Budget/CreateController.php @@ -40,6 +40,7 @@ class CreateController extends Controller /** * CreateController constructor. + * @codeCoverageIgnore */ public function __construct() { diff --git a/app/Http/Controllers/Budget/DeleteController.php b/app/Http/Controllers/Budget/DeleteController.php index 36d3798390..0b913ed23d 100644 --- a/app/Http/Controllers/Budget/DeleteController.php +++ b/app/Http/Controllers/Budget/DeleteController.php @@ -40,6 +40,7 @@ class DeleteController extends Controller /** * DeleteController constructor. + * @codeCoverageIgnore */ public function __construct() { diff --git a/app/Http/Controllers/Budget/EditController.php b/app/Http/Controllers/Budget/EditController.php index f2d9398399..d74c8b7479 100644 --- a/app/Http/Controllers/Budget/EditController.php +++ b/app/Http/Controllers/Budget/EditController.php @@ -42,6 +42,7 @@ class EditController extends Controller /** * EditController constructor. + * @codeCoverageIgnore */ public function __construct() { diff --git a/app/Http/Controllers/Budget/IndexController.php b/app/Http/Controllers/Budget/IndexController.php index d9aa50ae96..6c52b522bd 100644 --- a/app/Http/Controllers/Budget/IndexController.php +++ b/app/Http/Controllers/Budget/IndexController.php @@ -45,6 +45,7 @@ class IndexController extends Controller /** * IndexController constructor. + * @codeCoverageIgnore */ public function __construct() { diff --git a/app/Http/Controllers/Budget/ShowController.php b/app/Http/Controllers/Budget/ShowController.php index 26cb9e5134..1fb7370ac7 100644 --- a/app/Http/Controllers/Budget/ShowController.php +++ b/app/Http/Controllers/Budget/ShowController.php @@ -43,20 +43,22 @@ use Illuminate\Http\Request; class ShowController extends Controller { use PeriodOverview, AugumentData; + /** @var JournalRepositoryInterface */ + private $journalRepos; /** * ShowController constructor. + * + * @codeCoverageIgnore */ public function __construct() { parent::__construct(); - - app('view')->share('hideBudgets', true); - $this->middleware( function ($request, $next) { app('view')->share('title', (string)trans('firefly.budgets')); app('view')->share('mainTitleIcon', 'fa-tasks'); + $this->journalRepos = app(JournalRepositoryInterface::class); return $next($request); } @@ -82,9 +84,13 @@ class ShowController extends Controller 'firefly.without_budget_between', ['start' => $start->formatLocalized($this->monthAndDayFormat), 'end' => $end->formatLocalized($this->monthAndDayFormat)] ); - $periods = $this->getNoBudgetPeriodOverview($end); - $page = (int)$request->get('page'); - $pageSize = (int)app('preferences')->get('listPageSize', 50)->data; + + // get first journal ever to set off the budget period overview. + $first = $this->journalRepos->firstNull(); + $firstDate = null !== $first ? $first->date : $start; + $periods = $this->getNoBudgetPeriodOverview($firstDate, $end); + $page = (int)$request->get('page'); + $pageSize = (int)app('preferences')->get('listPageSize', 50)->data; /** @var GroupCollectorInterface $collector */ $collector = app(GroupCollectorInterface::class); @@ -100,16 +106,13 @@ class ShowController extends Controller * Shows ALL transactions without a budget. * * @param Request $request - * @param JournalRepositoryInterface $repository * * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View - * - * @SuppressWarnings(PHPMD.UnusedLocalVariable) */ - public function noBudgetAll(Request $request, JournalRepositoryInterface $repository) + public function noBudgetAll(Request $request) { $subTitle = (string)trans('firefly.all_journals_without_budget'); - $first = $repository->firstNull(); + $first = $this->journalRepos->firstNull(); $start = null === $first ? new Carbon : $first->date; $end = new Carbon; $page = (int)$request->get('page'); @@ -169,7 +172,7 @@ class ShowController extends Controller public function showByBudgetLimit(Request $request, Budget $budget, BudgetLimit $budgetLimit) { if ($budgetLimit->budget->id !== $budget->id) { - throw new FireflyException('This budget limit is not part of this budget.'); + throw new FireflyException('This budget limit is not part of this budget.'); // @codeCoverageIgnore } $page = (int)$request->get('page'); diff --git a/app/Http/Requests/BudgetFormRequest.php b/app/Http/Requests/BudgetFormRequest.php index c803cdaaaa..937704396f 100644 --- a/app/Http/Requests/BudgetFormRequest.php +++ b/app/Http/Requests/BudgetFormRequest.php @@ -28,6 +28,7 @@ use FireflyIII\Models\Budget; * Class BudgetFormRequest. * * @codeCoverageIgnore + * TODO after 4.8.0, split for update/store */ class BudgetFormRequest extends Request { diff --git a/app/Http/Requests/LinkTypeFormRequest.php b/app/Http/Requests/LinkTypeFormRequest.php index 7e75f6abcf..05d086a263 100644 --- a/app/Http/Requests/LinkTypeFormRequest.php +++ b/app/Http/Requests/LinkTypeFormRequest.php @@ -23,7 +23,7 @@ declare(strict_types=1); namespace FireflyIII\Http\Requests; /** - * Class BillFormRequest. + * Class LinkTypeFormRequest. */ class LinkTypeFormRequest extends Request { diff --git a/app/Support/Http/Controllers/PeriodOverview.php b/app/Support/Http/Controllers/PeriodOverview.php index 5ff7318427..a5a402a2bc 100644 --- a/app/Support/Http/Controllers/PeriodOverview.php +++ b/app/Support/Http/Controllers/PeriodOverview.php @@ -29,9 +29,7 @@ use FireflyIII\Models\Account; use FireflyIII\Models\Category; use FireflyIII\Models\Tag; use FireflyIII\Models\Transaction; -use FireflyIII\Models\TransactionCurrency; use FireflyIII\Models\TransactionType; -use FireflyIII\Repositories\Account\AccountRepositoryInterface; use FireflyIII\Repositories\Category\CategoryRepositoryInterface; use FireflyIII\Repositories\Journal\JournalRepositoryInterface; use FireflyIII\Repositories\Tag\TagRepositoryInterface; @@ -44,15 +42,26 @@ use Log; * * TODO verify this all works as expected. * + * - Always request start date and end date. * - Group expenses, income, etc. under this period. - * - Returns collection of arrays. Possible fields are: - * - start (string), - * end (string), + * - Returns collection of arrays. Fields * title (string), - * spent (string), - * earned (string), - * transferred (string) + * route (string) + * total_transactions (int) + * spent (array), + * earned (array), + * transferred_away (array) + * transferred_in (array) * + * each array has the following format: + * currency_id => [ + * currency_id : 1, (int) + * currency_symbol : X (str) + * currency_name: Euro (str) + * currency_code: EUR (str) + * amount: -1234 (str) + * count: 23 + * ] * */ trait PeriodOverview @@ -63,20 +72,15 @@ trait PeriodOverview * and for each period, the amount of money spent and earned. This is a complex operation which is cached for * performance reasons. * - * The method has been refactored recently for better performance. - * * @param Account $account The account involved * @param Carbon $date The start date. + * @param Carbon $end The end date. * - * @return Collection + * @return array */ - protected function getAccountPeriodOverview(Account $account, Carbon $date): Collection + protected function getAccountPeriodOverview(Account $account, Carbon $start, Carbon $end): array { - /** @var AccountRepositoryInterface $repository */ - $repository = app(AccountRepositoryInterface::class); - $range = app('preferences')->get('viewRange', '1M')->data; - $end = $repository->oldestJournalDate($account) ?? Carbon::now()->subMonth()->startOfMonth(); - $start = clone $date; + $range = app('preferences')->get('viewRange', '1M')->data; if ($end < $start) { [$start, $end] = [$end, $start]; // @codeCoverageIgnore @@ -93,43 +97,54 @@ trait PeriodOverview } /** @var array $dates */ $dates = app('navigation')->blockPeriods($start, $end, $range); - $entries = new Collection; + $entries = []; + + // collect all expenses in this period: + /** @var GroupCollectorInterface $collector */ + $collector = app(GroupCollectorInterface::class); + $collector->setAccounts(new Collection([$account])); + $collector->setRange($start, $end); + $collector->setTypes([TransactionType::DEPOSIT]); + $earnedSet = $collector->getExtractedJournals(); + + // collect all income in this period: + /** @var GroupCollectorInterface $collector */ + $collector = app(GroupCollectorInterface::class); + $collector->setAccounts(new Collection([$account])); + $collector->setRange($start, $end); + $collector->setTypes([TransactionType::WITHDRAWAL]); + $spentSet = $collector->getExtractedJournals(); + + // collect all transfers in this period: + /** @var GroupCollectorInterface $collector */ + $collector = app(GroupCollectorInterface::class); + $collector->setAccounts(new Collection([$account])); + $collector->setRange($start, $end); + $collector->setTypes([TransactionType::TRANSFER]); + $transferSet = $collector->getExtractedJournals(); + // loop dates foreach ($dates as $currentDate) { - - // collect from start to end: - /** @var GroupCollectorInterface $collector */ - $collector = app(GroupCollectorInterface::class); - $collector->setAccounts(new Collection([$account])); - $collector->setRange($currentDate['start'], $currentDate['end']); - $collector->setTypes([TransactionType::DEPOSIT]); - $earnedSet = $collector->getExtractedJournals(); - - $earned = $this->groupByCurrency($earnedSet); - - /** @var GroupCollectorInterface $collector */ - $collector = app(GroupCollectorInterface::class); - $collector->setAccounts(new Collection([$account])); - $collector->setRange($currentDate['start'], $currentDate['end']); - $collector->setTypes([TransactionType::WITHDRAWAL]); - $spentSet = $collector->getExtractedJournals(); - $spent = $this->groupByCurrency($spentSet); - $title = app('navigation')->periodShow($currentDate['start'], $currentDate['period']); - /** @noinspection PhpUndefinedMethodInspection */ - $entries->push( - [ - 'transactions' => count($spentSet) + count($earnedSet), - 'title' => $title, - 'spent' => $spent, - 'earned' => $earned, - 'transferred' => '0', - 'route' => route('accounts.show', [$account->id, $currentDate['start']->format('Y-m-d'), $currentDate['end']->format('Y-m-d')]), - ] - ); - } - //$cache->store($entries); + $earned = $this->filterJournalsByDate($earnedSet, $currentDate['start'], $currentDate['end']); + $spent = $this->filterJournalsByDate($spentSet, $currentDate['start'], $currentDate['end']); + $transferredAway = $this->filterTransferredAway($account, $this->filterJournalsByDate($transferSet, $currentDate['start'], $currentDate['end'])); + $transferredIn = $this->filterTransferredIn($account, $this->filterJournalsByDate($transferSet, $currentDate['start'], $currentDate['end'])); + $entries[] = + [ + 'title' => $title, + 'route' => + route('accounts.show', [$account->id, $currentDate['start']->format('Y-m-d'), $currentDate['end']->format('Y-m-d')]), + + 'total_transactions' => count($spent) + count($earned) + count($transferredAway) + count($transferredIn), + 'spent' => $this->groupByCurrency($spent), + 'earned' => $this->groupByCurrency($earned), + 'transferred_away' => $this->groupByCurrency($transferredAway), + 'transferred_in' => $this->groupByCurrency($transferredIn), + ]; + } + $cache->store($entries); return $entries; } @@ -144,6 +159,7 @@ trait PeriodOverview */ protected function getCategoryPeriodOverview(Category $category, Carbon $date): Collection { + die('not yet complete'); /** @var JournalRepositoryInterface $journalRepository */ $journalRepository = app(JournalRepositoryInterface::class); $range = app('preferences')->get('viewRange', '1M')->data; @@ -208,17 +224,13 @@ trait PeriodOverview * * This method has been refactored recently. * + * @param Carbon $start * @param Carbon $date * - * @return Collection + * @return array */ - protected function getNoBudgetPeriodOverview(Carbon $date): Collection + protected function getNoBudgetPeriodOverview(Carbon $start, Carbon $end): array { - /** @var JournalRepositoryInterface $repository */ - $repository = app(JournalRepositoryInterface::class); - $first = $repository->firstNull(); - $end = null === $first ? new Carbon : $first->date; - $start = clone $date; $range = app('preferences')->get('viewRange', '1M')->data; if ($end < $start) { @@ -231,32 +243,33 @@ trait PeriodOverview $cache->addProperty('no-budget-period-entries'); if ($cache->has()) { - return $cache->get(); // @codeCoverageIgnore + //return $cache->get(); // @codeCoverageIgnore } /** @var array $dates */ $dates = app('navigation')->blockPeriods($start, $end, $range); - $entries = new Collection; + $entries = []; + + + // get all expenses without a budget. + /** @var GroupCollectorInterface $collector */ + $collector = app(GroupCollectorInterface::class); + $collector->setRange($start, $end)->withoutBudget()->withAccountInformation()->setTypes([TransactionType::WITHDRAWAL]); + $journals = $collector->getExtractedJournals(); + foreach ($dates as $currentDate) { - /** @var GroupCollectorInterface $collector */ - $collector = app(GroupCollectorInterface::class); - $collector->setRange($currentDate['start'], $currentDate['end'])->withoutBudget()->withAccountInformation()->setTypes( - [TransactionType::WITHDRAWAL] - ); - $journals = $collector->getExtractedJournals(); - $count = count($journals); - $spent = $this->groupByCurrency($journals); + $set = $this->filterJournalsByDate($journals, $currentDate['start'], $currentDate['end']); $title = app('navigation')->periodShow($currentDate['end'], $currentDate['period']); - $entries->push( + $entries[] = [ - 'transactions' => $count, - 'title' => $title, - 'spent' => $spent, - 'earned' => '0', - 'transferred' => '0', + 'title' => $title, 'route' => route('budgets.no-budget', [$currentDate['start']->format('Y-m-d'), $currentDate['end']->format('Y-m-d')]), - ] - ); + 'total_transactions' => count($set), + 'spent' => $this->groupByCurrency($set), + 'earned' => [], + 'transferred_away' => [], + 'transferred_in' => [], + ]; } $cache->store($entries); @@ -275,6 +288,7 @@ trait PeriodOverview */ protected function getNoCategoryPeriodOverview(Carbon $theDate): Collection // period overview method. { + die('not yet complete'); Log::debug(sprintf('Now in getNoCategoryPeriodOverview(%s)', $theDate->format('Y-m-d'))); $range = app('preferences')->get('viewRange', '1M')->data; $first = $this->journalRepos->firstNull(); @@ -361,6 +375,7 @@ trait PeriodOverview */ protected function getTagPeriodOverview(Tag $tag, Carbon $date): Collection // period overview for tags. { + die('not yet complete'); /** @var TagRepositoryInterface $repository */ $repository = app(TagRepositoryInterface::class); $range = app('preferences')->get('viewRange', '1M')->data; @@ -423,6 +438,7 @@ trait PeriodOverview */ protected function getTransactionPeriodOverview(string $transactionType, Carbon $endDate): Collection { + die('not yet complete'); /** @var JournalRepositoryInterface $repository */ $repository = app(JournalRepositoryInterface::class); $range = app('preferences')->get('viewRange', '1M')->data; @@ -519,6 +535,65 @@ trait PeriodOverview return $return; } + /** + * Return only transactions where $account is the source. + * @param Account $account + * @param array $journals + * @return array + */ + private function filterTransferredAway(Account $account, array $journals): array + { + $return = []; + /** @var array $journal */ + foreach ($journals as $journal) { + if ($account->id === (int)$journal['source_account_id']) { + $return[] = $journal; + } + } + + return $return; + } + + /** + * Return only transactions where $account is the source. + * @param Account $account + * @param array $journals + * @return array + */ + private function filterTransferredIn(Account $account, array $journals): array + { + $return = []; + /** @var array $journal */ + foreach ($journals as $journal) { + if ($account->id === (int)$journal['destination_account_id']) { + $return[] = $journal; + } + } + + return $return; + } + + /** + * Filter a list of journals by a set of dates, and then group them by currency. + * + * @param array $array + * @param Carbon $start + * @param Carbon $end + * @return array + */ + private function filterJournalsByDate(array $array, Carbon $start, Carbon $end): array + { + $result = []; + /** @var array $journal */ + foreach ($array as $journal) { + if ($journal['date'] <= $end && $journal['date'] >= $start) { + $result[] = $journal; + } + } + + return $result; + } + /** * @param array $journals * @@ -529,19 +604,40 @@ trait PeriodOverview $return = []; /** @var array $journal */ foreach ($journals as $journal) { - $currencyId = (int)$journal['currency_id']; + $currencyId = (int)$journal['currency_id']; + $foreignCurrencyId = $journal['foreign_currency_id']; if (!isset($return[$currencyId])) { - $currency = new TransactionCurrency; - $currency->symbol = $journal['currency_symbol']; - $currency->decimal_places = $journal['currency_decimal_places']; - $currency->name = $journal['currency_name']; - $return[$currencyId] = [ - 'amount' => '0', - 'currency' => $currency, - //'currency' => 'x',//$currency, + $return[$currencyId] = [ + 'amount' => '0', + 'count' => 0, + 'currency_id' => $currencyId, + 'currency_name' => $journal['currency_name'], + 'currency_code' => $journal['currency_code'], + 'currency_symbol' => $journal['currency_symbol'], + 'currency_decimal_places' => $journal['currency_decimal_places'], ]; } $return[$currencyId]['amount'] = bcadd($return[$currencyId]['amount'], $journal['amount']); + $return[$currencyId]['count']++; + + + if (null !== $foreignCurrencyId) { + if (!isset($return[$foreignCurrencyId])) { + $return[$foreignCurrencyId] = [ + 'amount' => '0', + 'count' => 0, + 'currency_id' => (int)$foreignCurrencyId, + 'currency_name' => $journal['foreign_currency_name'], + 'currency_code' => $journal['foreign_currency_code'], + 'currency_symbol' => $journal['foreign_currency_symbol'], + 'currency_decimal_places' => $journal['foreign_currency_decimal_places'], + ]; + + } + $return[$foreignCurrencyId]['count']++; + $return[$foreignCurrencyId]['amount'] = bcadd($return[$foreignCurrencyId]['amount'], $journal['foreign_amount']); + } + } return $return; diff --git a/app/Support/Twig/TransactionGroupTwig.php b/app/Support/Twig/TransactionGroupTwig.php index 52d00ddabb..65b459e83d 100644 --- a/app/Support/Twig/TransactionGroupTwig.php +++ b/app/Support/Twig/TransactionGroupTwig.php @@ -25,6 +25,8 @@ namespace FireflyIII\Support\Twig\Extension; use Carbon\Carbon; use DB; +use FireflyIII\Models\Transaction; +use FireflyIII\Models\TransactionJournal; use FireflyIII\Models\TransactionType; use Log; use Twig_Extension; @@ -43,7 +45,8 @@ class TransactionGroupTwig extends Twig_Extension public function getFunctions(): array { return [ - $this->transactionAmount(), + $this->journalArrayAmount(), + $this->journalObjectAmount(), $this->groupAmount(), $this->journalHasMeta(), $this->journalGetMetaDate(), @@ -160,18 +163,44 @@ class TransactionGroupTwig extends Twig_Extension } /** + * Shows the amount for a single journal array. + * * @return Twig_SimpleFunction */ - public function transactionAmount(): Twig_SimpleFunction + public function journalArrayAmount(): Twig_SimpleFunction { return new Twig_SimpleFunction( - 'transactionAmount', + 'journalArrayAmount', function (array $array): string { // if is not a withdrawal, amount positive. - $result = $this->normalAmount($array); + $result = $this->normalJournalArrayAmount($array); // now append foreign amount, if any. if (null !== $array['foreign_amount']) { - $foreign = $this->foreignAmount($array); + $foreign = $this->foreignJournalArrayAmount($array); + $result = sprintf('%s (%s)', $result, $foreign); + } + + return $result; + }, + ['is_safe' => ['html']] + ); + } + + /** + * Shows the amount for a single journal object. + * + * @return Twig_SimpleFunction + */ + public function journalObjectAmount(): Twig_SimpleFunction + { + return new Twig_SimpleFunction( + 'journalObjectAmount', + function (TransactionJournal $journal): string { + // if is not a withdrawal, amount positive. + $result = $this->normalJournalObjectAmount($journal); + // now append foreign amount, if any. + if ($this->journalObjectHasForeign($journal)) { + $foreign = $this->foreignJournalObjectAmount($journal); $result = sprintf('%s (%s)', $result, $foreign); } @@ -188,7 +217,7 @@ class TransactionGroupTwig extends Twig_Extension * * @return string */ - private function foreignAmount(array $array): string + private function foreignJournalArrayAmount(array $array): string { $type = $array['transaction_type_type'] ?? TransactionType::WITHDRAWAL; $amount = $array['foreign_amount'] ?? '0'; @@ -207,6 +236,35 @@ class TransactionGroupTwig extends Twig_Extension return $result; } + /** + * Generate foreign amount for journal from a transaction group. + * + * @param TransactionJournal $journal + * + * @return string + */ + private function foreignJournalObjectAmount(TransactionJournal $journal): string + { + $type = $journal->transactionType->type; + /** @var Transaction $first */ + $first = $journal->transactions()->where('amount', '<', 0)->first(); + $currency = $first->foreignCurrency; + $amount = $first->foreign_amount ?? '0'; + $colored = true; + if ($type !== TransactionType::WITHDRAWAL) { + $amount = bcmul($amount, '-1'); + } + if ($type === TransactionType::TRANSFER) { + $colored = false; + } + $result = app('amount')->formatFlat($currency->symbol, (int)$currency->decimal_places, $amount, $colored); + if ($type === TransactionType::TRANSFER) { + $result = sprintf('%s', $result); + } + + return $result; + } + /** * Generate normal amount for transaction from a transaction group. * @@ -214,7 +272,7 @@ class TransactionGroupTwig extends Twig_Extension * * @return string */ - private function normalAmount(array $array): string + private function normalJournalArrayAmount(array $array): string { $type = $array['transaction_type_type'] ?? TransactionType::WITHDRAWAL; $amount = $array['amount'] ?? '0'; @@ -232,4 +290,44 @@ class TransactionGroupTwig extends Twig_Extension return $result; } + + /** + * Generate normal amount for transaction from a transaction group. + * + * @param TransactionJournal $journal + * + * @return string + */ + private function normalJournalObjectAmount(TransactionJournal $journal): string + { + $type = $journal->transactionType->type; + $first = $journal->transactions()->where('amount', '<', 0)->first(); + $currency = $journal->transactionCurrency; + $amount = $first->amount ?? '0'; + $colored = true; + if ($type !== TransactionType::WITHDRAWAL) { + $amount = bcmul($amount, '-1'); + } + if ($type === TransactionType::TRANSFER) { + $colored = false; + } + $result = app('amount')->formatFlat($currency->symbol, (int)$currency->decimal_places, $amount, $colored); + if ($type === TransactionType::TRANSFER) { + $result = sprintf('%s', $result); + } + + return $result; + } + + /** + * @param TransactionJournal $journal + * @return bool + */ + private function journalObjectHasForeign(TransactionJournal $journal): bool + { + /** @var Transaction $first */ + $first = $journal->transactions()->where('amount', '<', 0)->first(); + + return null !== $first->foreign_amount; + } } \ No newline at end of file diff --git a/app/Support/Twig/Translation.php b/app/Support/Twig/Translation.php index 05985bde61..a1c0c8eead 100644 --- a/app/Support/Twig/Translation.php +++ b/app/Support/Twig/Translation.php @@ -48,4 +48,34 @@ class Translation extends Twig_Extension return $filters; } + + /** + * {@inheritdoc} + */ + public function getFunctions(): array + { + return [ + $this->journalLinkTranslation(), + ]; + } + + /** + * @return Twig_SimpleFunction + */ + public function journalLinkTranslation(): Twig_SimpleFunction + { + return new Twig_SimpleFunction( + 'journalLinkTranslation', + function (string $direction, string $original) { + $key = sprintf('firefly.%s_%s', $original, $direction); + $translation = trans($key); + if ($key === $translation) { + return $original; + } + + return $translation; + }, + ['is_safe' => ['html']] + ); + } } diff --git a/public/v1/js/ff/budgets/index.js b/public/v1/js/ff/budgets/index.js index bc7ad2387d..34642d15d0 100644 --- a/public/v1/js/ff/budgets/index.js +++ b/public/v1/js/ff/budgets/index.js @@ -26,7 +26,6 @@ $(function () { "use strict"; $('.updateIncome').on('click', updateIncome); - $('.infoIncome').on('click', infoIncome); /* On start, fill the "spent"-bar using the content from the page. @@ -239,11 +238,3 @@ function updateIncome() { return false; } - -function infoIncome() { - $('#defaultModal').empty().load(infoIncomeUri, function () { - $('#defaultModal').modal('show'); - }); - - return false; -} diff --git a/resources/views/v1/accounts/show.twig b/resources/views/v1/accounts/show.twig index 7ddd64f498..4dac1f580f 100644 --- a/resources/views/v1/accounts/show.twig +++ b/resources/views/v1/accounts/show.twig @@ -101,7 +101,7 @@ {% endif %}
- {% if periods.count > 0 %} + {% if periods|length > 0 %} {{ 'show_all_no_filter'|_ }} @@ -129,7 +129,7 @@
@@ -40,7 +40,7 @@
{{ 'transactions'|_ }} | -{{ period.transactions }} | +{{ period.total_transactions }} | |
{{ 'spent'|_ }} | - {{ formatAmountBySymbol(entry.amount * -1, entry.currency.symbol, entry.currency.decimal_places) }} + + {{ formatAmountBySymbol(entry.amount, entry.currency_symbol, entry.currency_decimal_places) }} + | ||
{{ 'earned'|_ }} | -{{ formatAmountBySymbol(entry.amount, entry.currency.symbol, entry.currency.decimal_places) }} | ++ + {{ formatAmountBySymbol(entry.amount*-1, entry.currency_symbol, entry.currency_decimal_places) }} + + | |
{{ 'transferred'|_ }} | -{{ formatAmountBySymbol(array.sum, array.currency_symbol, array.currency_decimal_places, false) }} + | {{ 'transferred_away'|_ }} | ++ + {{ formatAmountBySymbol(entry.amount*-1, entry.currency_symbol, entry.currency_decimal_places) }} + + | +
{{ 'transferred_in'|_ }} | ++ + {{ formatAmountBySymbol(entry.amount*-1, entry.currency_symbol, entry.currency_decimal_places) }} + | {{ transaction.description }} | {{ transaction.date.formatLocalized(monthAndDayFormat) }} - | +{{ transaction|transactionAmount }} | diff --git a/routes/web.php b/routes/web.php index ff56ab611f..bc535be081 100644 --- a/routes/web.php +++ b/routes/web.php @@ -219,7 +219,6 @@ Route::group( // update budget amount and income amount Route::get('income/{start_date}/{end_date}', ['uses' => 'Budget\AmountController@updateIncome', 'as' => 'income']); - Route::get('info/{start_date}/{end_date}', ['uses' => 'Budget\AmountController@infoIncome', 'as' => 'income.info']); Route::post('income', ['uses' => 'Budget\AmountController@postUpdateIncome', 'as' => 'income.post']); Route::post('amount/{budget}', ['uses' => 'Budget\AmountController@amount', 'as' => 'amount']); diff --git a/tests/Feature/Controllers/Account/CreateControllerTest.php b/tests/Feature/Controllers/Account/CreateControllerTest.php index 7081d3604c..a5d8fa226b 100644 --- a/tests/Feature/Controllers/Account/CreateControllerTest.php +++ b/tests/Feature/Controllers/Account/CreateControllerTest.php @@ -63,28 +63,19 @@ class CreateControllerTest extends TestCase public function testCreate(): void { // mock stuff - $journalRepos = $this->mock(JournalRepositoryInterface::class); + $accountRepos = $this->mock(AccountRepositoryInterface::class); $repository = $this->mock(CurrencyRepositoryInterface::class); $userRepos = $this->mock(UserRepositoryInterface::class); - $euro = $this->getEuro(); $repository->shouldReceive('get')->andReturn(new Collection); - // used for session range. - $journalRepos->shouldReceive('firstNull')->once()->andReturn(new TransactionJournal); - // mock hasRole for user repository: $userRepos->shouldReceive('hasRole')->withArgs([Mockery::any(), 'owner'])->andReturn(true)->atLeast()->once(); - Amount::shouldReceive('getDefaultCurrency')->atLeast()->once()->andReturn($euro); - - // mock default calls to Preferences: - $this->mockDefaultPreferences(); + // mock default calls + $this->mockDefaultSession(); $this->mockIntroPreference('shown_demo_accounts_create_asset'); - // mock default calls to Configuration: - $this->mockDefaultConfiguration(); - // get all types: $accountRepos->shouldReceive('getAccountTypeByType')->withArgs(['Debt'])->andReturn(AccountType::find(11))->once(); $accountRepos->shouldReceive('getAccountTypeByType')->withArgs(['Loan'])->andReturn(AccountType::find(9))->once(); @@ -105,31 +96,22 @@ class CreateControllerTest extends TestCase public function testStore(): void { // mock stuff - $journalRepos = $this->mock(JournalRepositoryInterface::class); + $repository = $this->mock(AccountRepositoryInterface::class); $asset = $this->getRandomAsset(); - $euro = $this->getEuro(); - $repository->shouldReceive('store')->once()->andReturn($asset); - $journalRepos->shouldReceive('firstNull')->once()->andReturn(new TransactionJournal); - // mock default calls to Configuration: - $this->mockDefaultConfiguration(); + $repository->shouldReceive('store')->once()->andReturn($asset); + + // mock default session stuff + $this->mockDefaultSession(); // change the preference: $emptyPref = new Preference; $emptyPref->data = []; Preferences::shouldReceive('get')->atLeast()->once()->withArgs(['frontPageAccounts', []])->andReturn($emptyPref); Preferences::shouldReceive('set')->atLeast()->once()->withArgs(['frontPageAccounts', [$asset->id]]); - Amount::shouldReceive('getDefaultCurrency')->atLeast()->once()->andReturn($euro); - - Preferences::shouldReceive('mark')->atLeast()->once()->withNoArgs(); - // mock default calls to Preferences: - $this->mockDefaultPreferences(); - - - $this->session(['accounts.create.uri' => 'http://localhost/x']); $this->be($this->user()); $data = [ @@ -151,28 +133,20 @@ class CreateControllerTest extends TestCase public function testStoreAnother(): void { // mock stuff - $journalRepos = $this->mock(JournalRepositoryInterface::class); $repository = $this->mock(AccountRepositoryInterface::class); $asset = $this->getRandomAsset(); - $euro = $this->getEuro(); $repository->shouldReceive('store')->once()->andReturn($asset); - $journalRepos->shouldReceive('firstNull')->once()->andReturn(new TransactionJournal); // change the preference: $emptyPref = new Preference; $emptyPref->data = []; Preferences::shouldReceive('get')->atLeast()->once()->withArgs(['frontPageAccounts', []])->andReturn($emptyPref); Preferences::shouldReceive('set')->atLeast()->once()->withArgs(['frontPageAccounts', [$asset->id]]); - Amount::shouldReceive('getDefaultCurrency')->atLeast()->once()->andReturn($euro); - // mock default calls to Preferences: - $this->mockDefaultPreferences(); - //$this->mockIntroPreference('shown_demo_accounts_create_asset'); - - // mock default calls to Configuration: - $this->mockDefaultConfiguration(); + // mock default session stuff + $this->mockDefaultSession(); @@ -201,28 +175,18 @@ class CreateControllerTest extends TestCase public function testStoreLiability(): void { // mock stuff - $journalRepos = $this->mock(JournalRepositoryInterface::class); $repository = $this->mock(AccountRepositoryInterface::class); $liability = $this->getRandomLoan(); $loan = AccountType::where('type', AccountType::LOAN)->first(); - $euro = $this->getEuro(); $repository->shouldReceive('store')->once()->andReturn($liability); - $journalRepos->shouldReceive('firstNull')->once()->andReturn(new TransactionJournal); - Amount::shouldReceive('getDefaultCurrency')->atLeast()->once()->andReturn($euro); + // mock default session stuff + $this->mockDefaultSession(); // change the preference: $emptyPref = new Preference; $emptyPref->data = []; Preferences::shouldReceive('get')->atLeast()->once()->withArgs(['frontPageAccounts', []])->andReturn($emptyPref); - - // mock default calls to Preferences: - $this->mockDefaultPreferences(); - //$this->mockIntroPreference('shown_demo_accounts_create_asset'); - - // mock default calls to Configuration: - $this->mockDefaultConfiguration(); - Preferences::shouldReceive('mark')->atLeast()->once()->withNoArgs(); $this->session(['accounts.create.uri' => 'http://localhost']); diff --git a/tests/Feature/Controllers/Account/DeleteControllerTest.php b/tests/Feature/Controllers/Account/DeleteControllerTest.php index c306f3693f..b34d904205 100644 --- a/tests/Feature/Controllers/Account/DeleteControllerTest.php +++ b/tests/Feature/Controllers/Account/DeleteControllerTest.php @@ -62,25 +62,15 @@ class DeleteControllerTest extends TestCase public function testDelete(): void { // mock stuff - $journalRepos = $this->mock(JournalRepositoryInterface::class); $repository = $this->mock(AccountRepositoryInterface::class); $userRepos = $this->mock(UserRepositoryInterface::class); $asset = $this->getRandomAsset(); - $repository->shouldReceive('getAccountsByType')->withArgs([[AccountType::ASSET]])->andReturn(new Collection); - $journalRepos->shouldReceive('firstNull')->once()->andReturn(new TransactionJournal); - // mock hasRole for user repository: + $repository->shouldReceive('getAccountsByType')->withArgs([[AccountType::ASSET]])->andReturn(new Collection); $userRepos->shouldReceive('hasRole')->withArgs([Mockery::any(), 'owner'])->andReturn(true)->atLeast()->once(); - // mock Amount - $euro = $this->getEuro(); - Amount::shouldReceive('getDefaultCurrency')->atLeast()->once()->andReturn($euro); - - // mock calls to Preferences: - $this->mockDefaultPreferences(); - - // mock calls to Configuration: - $this->mockDefaultConfiguration(); + // mock default session stuff + $this->mockDefaultSession(); $this->be($this->user()); $response = $this->get(route('accounts.delete', [$asset->id])); @@ -96,25 +86,16 @@ class DeleteControllerTest extends TestCase public function testDestroy(): void { // mock stuff - $journalRepos = $this->mock(JournalRepositoryInterface::class); $repository = $this->mock(AccountRepositoryInterface::class); $asset = $this->getRandomAsset(); - $euro = $this->getEuro(); $repository->shouldReceive('findNull')->withArgs([0])->once()->andReturn(null); $repository->shouldReceive('destroy')->andReturn(true); - $journalRepos->shouldReceive('firstNull')->once()->andReturn(new TransactionJournal); - // mock calls to Preferences: - $this->mockDefaultPreferences(); - - // mock calls to Configuration: - $this->mockDefaultConfiguration(); + // mock default session stuff + $this->mockDefaultSession(); Preferences::shouldReceive('mark')->atLeast()->once(); - // mock Amount - Amount::shouldReceive('getDefaultCurrency')->atLeast()->once()->andReturn($euro); - $this->session(['accounts.delete.uri' => 'http://localhost/accounts/show/1']); $this->be($this->user()); diff --git a/tests/Feature/Controllers/Account/EditControllerTest.php b/tests/Feature/Controllers/Account/EditControllerTest.php index 12d6b233b8..5317002766 100644 --- a/tests/Feature/Controllers/Account/EditControllerTest.php +++ b/tests/Feature/Controllers/Account/EditControllerTest.php @@ -62,25 +62,20 @@ class EditControllerTest extends TestCase */ public function testEdit(): void { - $journalRepos = $this->mock(JournalRepositoryInterface::class); $repository = $this->mock(CurrencyRepositoryInterface::class); $accountRepos = $this->mock(AccountRepositoryInterface::class); $userRepos = $this->mock(UserRepositoryInterface::class); $asset = $this->getRandomAsset(); $euro = $this->getEuro(); - Amount::shouldReceive('getDefaultCurrency')->atLeast()->once()->andReturn($euro); + // mock default session stuff + $this->mockDefaultSession(); - // mock preferences: - $this->mockDefaultPreferences(); - - //$repository->shouldReceive('findNull')->withArgs([1])->andReturn($euro)->atLeast()->once(); // mock hasRole for user repository: $userRepos->shouldReceive('hasRole')->withArgs([Mockery::any(), 'owner'])->andReturn(true)->atLeast()->once(); $repository->shouldReceive('get')->andReturn(new Collection)->atLeast()->once(); - $journalRepos->shouldReceive('firstNull')->once()->andReturn(new TransactionJournal); $accountRepos->shouldReceive('getAccountCurrency')->andReturn($euro)->once(); $accountRepos->shouldReceive('getNoteText')->andReturn('Some text')->once(); $accountRepos->shouldReceive('getOpeningBalanceAmount')->andReturnNull()->atLeast()->once(); @@ -100,12 +95,6 @@ class EditControllerTest extends TestCase $accountRepos->shouldReceive('getAccountTypeByType')->withArgs(['Loan'])->andReturn(AccountType::find(9))->once(); $accountRepos->shouldReceive('getAccountTypeByType')->withArgs(['Mortgage'])->andReturn(AccountType::find(12))->once(); - // mock calls to Preferences: - //$this->mockDefaultPreferences(); - - // mock calls to Configuration: - $this->mockDefaultConfiguration(); - $this->be($this->user()); $response = $this->get(route('accounts.edit', [$asset->id])); $response->assertStatus(200); @@ -120,7 +109,6 @@ class EditControllerTest extends TestCase */ public function testEditLiability(): void { - $journalRepos = $this->mock(JournalRepositoryInterface::class); $repository = $this->mock(CurrencyRepositoryInterface::class); $accountRepos = $this->mock(AccountRepositoryInterface::class); $userRepos = $this->mock(UserRepositoryInterface::class); @@ -131,7 +119,7 @@ class EditControllerTest extends TestCase //$repository->shouldReceive('findNull')->once()->andReturn($euro); $repository->shouldReceive('get')->andReturn(new Collection); - $journalRepos->shouldReceive('firstNull')->once()->andReturn(new TransactionJournal); + $accountRepos->shouldReceive('getNoteText')->andReturn('Some text')->once(); $accountRepos->shouldReceive('getOpeningBalanceAmount')->andReturnNull(); $accountRepos->shouldReceive('getOpeningBalanceDate')->andReturnNull(); @@ -151,16 +139,8 @@ class EditControllerTest extends TestCase $accountRepos->shouldReceive('getAccountTypeByType')->withArgs(['Loan'])->andReturn(AccountType::find(9))->once(); $accountRepos->shouldReceive('getAccountTypeByType')->withArgs(['Mortgage'])->andReturn(AccountType::find(12))->once(); - // mock Amount - $euro = $this->getEuro(); - Amount::shouldReceive('getDefaultCurrency')->atLeast()->once()->andReturn($euro); - - // mock calls to Preferences: - $this->mockDefaultPreferences(); - - // mock calls to Configuration: - $this->mockDefaultConfiguration(); - + // mock default session stuff + $this->mockDefaultSession(); $this->be($this->user()); $response = $this->get(route('accounts.edit', [$loan->id])); @@ -177,7 +157,6 @@ class EditControllerTest extends TestCase public function testEditNull(): void { // mock stuff - $journalRepos = $this->mock(JournalRepositoryInterface::class); $repository = $this->mock(CurrencyRepositoryInterface::class); $accountRepos = $this->mock(AccountRepositoryInterface::class); $userRepos = $this->mock(UserRepositoryInterface::class); @@ -185,10 +164,7 @@ class EditControllerTest extends TestCase // mock hasRole for user repository: $userRepos->shouldReceive('hasRole')->withArgs([Mockery::any(), 'owner'])->andReturn(true)->atLeast()->once(); - Amount::shouldReceive('getDefaultCurrency')->andReturn(TransactionCurrency::find(2)); - //$repository->shouldReceive('findNull')->once()->andReturn(null); $repository->shouldReceive('get')->andReturn(new Collection); - $journalRepos->shouldReceive('firstNull')->once()->andReturn(new TransactionJournal); $accountRepos->shouldReceive('getNoteText')->andReturn('Some text')->once(); $accountRepos->shouldReceive('getOpeningBalanceAmount')->andReturnNull(); $accountRepos->shouldReceive('getOpeningBalanceDate')->andReturnNull(); @@ -203,11 +179,8 @@ class EditControllerTest extends TestCase $accountRepos->shouldReceive('getMetaValue')->withArgs([Mockery::any(), 'interest_period'])->andReturn('monthly'); $accountRepos->shouldReceive('getAccountCurrency')->andReturn($euro)->once(); - // mock calls to Preferences: - $this->mockDefaultPreferences(); - - // mock calls to Configuration: - $this->mockDefaultConfiguration(); + // mock default session stuff + $this->mockDefaultSession(); // get all types: $accountRepos->shouldReceive('getAccountTypeByType')->withArgs(['Debt'])->andReturn(AccountType::find(11))->once(); @@ -232,18 +205,15 @@ class EditControllerTest extends TestCase public function testUpdate(): void { // mock stuff - $journalRepos = $this->mock(JournalRepositoryInterface::class); $repository = $this->mock(AccountRepositoryInterface::class); $this->mock(CurrencyRepositoryInterface::class); $repository->shouldReceive('update')->once(); - $journalRepos->shouldReceive('firstNull')->once()->andReturn(new TransactionJournal); - - - $euro = $this->getEuro(); - Amount::shouldReceive('getDefaultCurrency')->atLeast()->once()->andReturn($euro); Preferences::shouldReceive('mark')->atLeast()->once(); + // mock default session stuff + $this->mockDefaultSession(); + $this->session(['accounts.edit.uri' => 'http://localhost/javascript/account']); $this->be($this->user()); $data = [ @@ -252,12 +222,6 @@ class EditControllerTest extends TestCase 'what' => 'asset', ]; - // mock calls to Preferences: - $this->mockDefaultPreferences(); - - // mock calls to Configuration: - $this->mockDefaultConfiguration(); - $response = $this->post(route('accounts.update', [1]), $data); $response->assertStatus(302); $response->assertSessionHas('success'); @@ -271,11 +235,9 @@ class EditControllerTest extends TestCase public function testUpdateAgain(): void { // mock stuff - $journalRepos = $this->mock(JournalRepositoryInterface::class); $repository = $this->mock(AccountRepositoryInterface::class); $this->mock(CurrencyRepositoryInterface::class); $repository->shouldReceive('update')->once(); - $journalRepos->shouldReceive('firstNull')->once()->andReturn(new TransactionJournal); $this->session(['accounts.edit.uri' => 'http://localhost']); $this->be($this->user()); @@ -286,15 +248,10 @@ class EditControllerTest extends TestCase 'return_to_edit' => '1', ]; - $euro = $this->getEuro(); - Amount::shouldReceive('getDefaultCurrency')->atLeast()->once()->andReturn($euro); Preferences::shouldReceive('mark')->atLeast()->once(); - // mock calls to Preferences: - $this->mockDefaultPreferences(); - - // mock calls to Configuration: - $this->mockDefaultConfiguration(); + // mock default session stuff + $this->mockDefaultSession(); $response = $this->post(route('accounts.update', [1]), $data); $response->assertStatus(302); diff --git a/tests/Feature/Controllers/Account/IndexControllerTest.php b/tests/Feature/Controllers/Account/IndexControllerTest.php index f2192d6453..1d59a8a49a 100644 --- a/tests/Feature/Controllers/Account/IndexControllerTest.php +++ b/tests/Feature/Controllers/Account/IndexControllerTest.php @@ -67,7 +67,6 @@ class IndexControllerTest extends TestCase // mock stuff $account = $this->getRandomAsset(); $repository = $this->mock(AccountRepositoryInterface::class); - $journalRepos = $this->mock(JournalRepositoryInterface::class); $currencyRepos = $this->mock(CurrencyRepositoryInterface::class); $userRepos = $this->mock(UserRepositoryInterface::class); $euro = $this->getEuro(); @@ -76,17 +75,12 @@ class IndexControllerTest extends TestCase $repository->shouldReceive('getAccountsByType')->andReturn(new Collection([$account])); $repository->shouldReceive('getMetaValue')->withArgs([Mockery::any(), 'currency_id'])->andReturn('1'); - $journalRepos->shouldReceive('firstNull')->once()->andReturn(new TransactionJournal); $currencyRepos->shouldReceive('findNull')->withArgs([1])->andReturn($euro); Steam::shouldReceive('balancesByAccounts')->andReturn([$account->id => '100']); Steam::shouldReceive('getLastActivities')->andReturn([]); - - // mock calls to Preferences: - $this->mockDefaultPreferences(); - - // mock calls to Configuration: - $this->mockDefaultConfiguration(); + // mock default session stuff + $this->mockDefaultSession(); // list size $pref = new Preference; @@ -94,7 +88,6 @@ class IndexControllerTest extends TestCase Preferences::shouldReceive('get')->withArgs(['listPageSize', 50])->atLeast()->once()->andReturn($pref); Amount::shouldReceive('formatAnything')->andReturn('123'); - Amount::shouldReceive('getDefaultCurrency')->atLeast()->once()->andReturn($euro); $repository->shouldReceive('getMetaValue')->withArgs([Mockery::any(), 'interest'])->andReturn('1'); $repository->shouldReceive('getMetaValue')->withArgs([Mockery::any(), 'interest_period'])->andReturn('monthly'); diff --git a/tests/Feature/Controllers/Account/ReconcileControllerTest.php b/tests/Feature/Controllers/Account/ReconcileControllerTest.php index cf8d547681..bdd534bb55 100644 --- a/tests/Feature/Controllers/Account/ReconcileControllerTest.php +++ b/tests/Feature/Controllers/Account/ReconcileControllerTest.php @@ -23,16 +23,13 @@ declare(strict_types=1); namespace Tests\Feature\Controllers\Account; -use Amount; use Carbon\Carbon; use FireflyIII\Exceptions\FireflyException; use FireflyIII\Factory\TransactionGroupFactory; use FireflyIII\Helpers\Collector\GroupCollectorInterface; use FireflyIII\Helpers\Fiscal\FiscalHelperInterface; -use FireflyIII\Models\TransactionJournal; use FireflyIII\Repositories\Account\AccountRepositoryInterface; use FireflyIII\Repositories\Currency\CurrencyRepositoryInterface; -use FireflyIII\Repositories\Journal\JournalRepositoryInterface; use FireflyIII\Repositories\User\UserRepositoryInterface; use Log; use Mockery; @@ -67,24 +64,21 @@ class ReconcileControllerTest extends TestCase $accountRepos = $this->mock(AccountRepositoryInterface::class); $fiscalHelper = $this->mock(FiscalHelperInterface::class); $this->mock(GroupCollectorInterface::class); - $journalRepos = $this->mock(JournalRepositoryInterface::class); - $euro = $this->getEuro(); - $asset = $this->getRandomAsset(); - $date = new Carbon; + $euro = $this->getEuro(); + $asset = $this->getRandomAsset(); + $date = new Carbon; - // used for session range. - $journalRepos->shouldReceive('firstNull')->once()->andReturn(new TransactionJournal); $userRepos->shouldReceive('hasRole')->atLeast()->once()->withArgs([Mockery::any(), 'owner'])->andReturnTrue(); $fiscalHelper->shouldReceive('endOfFiscalYear')->atLeast()->once()->andReturn($date); $fiscalHelper->shouldReceive('startOfFiscalYear')->atLeast()->once()->andReturn($date); - $this->mockDefaultConfiguration(); - $this->mockDefaultPreferences(); - Amount::shouldReceive('getDefaultCurrency')->atLeast()->once()->andReturn($euro); Steam::shouldReceive('balance')->atLeast()->once()->andReturn('100'); $accountRepos->shouldReceive('getAccountCurrency')->atLeast()->once()->andReturn($euro); + // mock default session stuff + $this->mockDefaultSession(); + $this->be($this->user()); $response = $this->get(route('accounts.reconcile', [$asset->id, '20170101', '20170131'])); $response->assertStatus(200); @@ -103,7 +97,7 @@ class ReconcileControllerTest extends TestCase { $repository = $this->mock(AccountRepositoryInterface::class); $fiscalHelper = $this->mock(FiscalHelperInterface::class); - $journalRepos = $this->mock(JournalRepositoryInterface::class); + $journalRepos = $this->mockDefaultSession(); $asset = $this->getRandomAsset(); $euro = $this->getEuro(); $date = new Carbon; @@ -112,16 +106,9 @@ class ReconcileControllerTest extends TestCase $this->mock(CurrencyRepositoryInterface::class); $this->mock(GroupCollectorInterface::class); - - // used for session range. - $journalRepos->shouldReceive('firstNull')->once()->andReturn(new TransactionJournal); - Amount::shouldReceive('getDefaultCurrency')->atLeast()->once()->andReturn($euro); - - $this->mockDefaultPreferences(); - $this->mockDefaultConfiguration(); - Preferences::shouldReceive('mark')->atLeast()->once(); + $fiscalHelper->shouldReceive('endOfFiscalYear')->atLeast()->once()->andReturn($date); $fiscalHelper->shouldReceive('startOfFiscalYear')->atLeast()->once()->andReturn($date); $journalRepos->shouldReceive('reconcileById')->times(3); @@ -130,6 +117,7 @@ class ReconcileControllerTest extends TestCase $factory->shouldReceive('setUser')->atLeast()->once(); $factory->shouldReceive('create')->andReturn($group); + $data = [ 'journals' => [1, 2, 3], 'reconcile' => 'create', @@ -154,23 +142,14 @@ class ReconcileControllerTest extends TestCase { $repository = $this->mock(AccountRepositoryInterface::class); $fiscalHelper = $this->mock(FiscalHelperInterface::class); - $journalRepos = $this->mock(JournalRepositoryInterface::class); + $journalRepos = $this->mockDefaultSession(); $asset = $this->getRandomAsset(); $euro = $this->getEuro(); $date = new Carbon; $factory = $this->mock(TransactionGroupFactory::class); - $group = $this->getRandomWithdrawalGroup(); $this->mock(CurrencyRepositoryInterface::class); $this->mock(GroupCollectorInterface::class); - - // used for session range. - $journalRepos->shouldReceive('firstNull')->once()->andReturn(new TransactionJournal); - Amount::shouldReceive('getDefaultCurrency')->atLeast()->once()->andReturn($euro); - - $this->mockDefaultPreferences(); - $this->mockDefaultConfiguration(); - Preferences::shouldReceive('mark')->atLeast()->once(); $fiscalHelper->shouldReceive('endOfFiscalYear')->atLeast()->once()->andReturn($date); diff --git a/tests/Feature/Controllers/Account/ShowControllerTest.php b/tests/Feature/Controllers/Account/ShowControllerTest.php index d783e984f5..4a825ca4ab 100644 --- a/tests/Feature/Controllers/Account/ShowControllerTest.php +++ b/tests/Feature/Controllers/Account/ShowControllerTest.php @@ -27,11 +27,9 @@ use Amount; use Carbon\Carbon; use FireflyIII\Helpers\Collector\GroupCollectorInterface; use FireflyIII\Models\Preference; -use FireflyIII\Models\TransactionJournal; use FireflyIII\Repositories\Account\AccountRepositoryInterface; use FireflyIII\Repositories\Account\AccountTaskerInterface; use FireflyIII\Repositories\Currency\CurrencyRepositoryInterface; -use FireflyIII\Repositories\Journal\JournalRepositoryInterface; use FireflyIII\Repositories\User\UserRepositoryInterface; use Illuminate\Pagination\LengthAwarePaginator; use Log; @@ -68,12 +66,10 @@ class ShowControllerTest extends TestCase $this->session(['start' => $date, 'end' => clone $date]); // mock stuff: - - $journalRepos = $this->mock(JournalRepositoryInterface::class); - $tasker = $this->mock(AccountTaskerInterface::class); + //$tasker = $this->mock(AccountTaskerInterface::class); $userRepos = $this->mock(UserRepositoryInterface::class); - $currencyRepos = $this->mock(CurrencyRepositoryInterface::class); - $accountRepos = $this->mock(AccountRepositoryInterface::class); + $this->mock(CurrencyRepositoryInterface::class); + //$accountRepos = $this->mock(AccountRepositoryInterface::class); $collector = $this->mock(GroupCollectorInterface::class); $repository = $this->mock(AccountRepositoryInterface::class); $journal = $this->getRandomWithdrawalAsArray(); @@ -81,26 +77,19 @@ class ShowControllerTest extends TestCase $asset = $this->getRandomAsset(); $euro = $this->getEuro(); - // mock stuff - $this->mockDefaultConfiguration(); - $this->mockDefaultPreferences(); + $this->mockDefaultSession(); // amount mocks: - Amount::shouldReceive('getDefaultCurrency')->atLeast()->once()->andReturn($euro); Amount::shouldReceive('formatAnything')->atLeast()->once()->andReturn('-100'); $repository->shouldReceive('getAccountCurrency')->andReturn($euro)->atLeast()->once(); $repository->shouldReceive('oldestJournalDate')->andReturn(clone $date)->once(); - - // used for session range. - $journalRepos->shouldReceive('firstNull')->once()->andReturn(new TransactionJournal); - // list size $pref = new Preference; $pref->data = 50; Preferences::shouldReceive('get')->withArgs(['listPageSize', 50])->atLeast()->once()->andReturn($pref); - Preferences::shouldReceive('lastActivity')->atLeast()->once(); + $this->mockLastActivity(); // mock hasRole for user repository: $userRepos->shouldReceive('hasRole')->withArgs([Mockery::any(), 'owner'])->andReturn(true)->atLeast()->once(); @@ -132,8 +121,6 @@ class ShowControllerTest extends TestCase $date = new Carbon; $this->session(['start' => $date, 'end' => clone $date]); // mock stuff: - - $journalRepos = $this->mock(JournalRepositoryInterface::class); $tasker = $this->mock(AccountTaskerInterface::class); $userRepos = $this->mock(UserRepositoryInterface::class); $currencyRepos = $this->mock(CurrencyRepositoryInterface::class); @@ -145,22 +132,12 @@ class ShowControllerTest extends TestCase $euro = $this->getEuro(); $asset = $this->getRandomAsset(); - // mock stuff - $this->mockDefaultConfiguration(); - $this->mockDefaultPreferences(); - - // amount mocks: - Amount::shouldReceive('getDefaultCurrency')->atLeast()->once()->andReturn($euro); -// Amount::shouldReceive('formatAnything')->atLeast()->once()->andReturn('-100'); + $this->mockDefaultSession(); $repository->shouldReceive('isLiability')->andReturn(false)->atLeast()->once(); $repository->shouldReceive('getAccountCurrency')->andReturn($euro)->atLeast()->once(); $repository->shouldReceive('oldestJournalDate')->andReturn(clone $date)->once(); - - // used for session range. - $journalRepos->shouldReceive('firstNull')->once()->andReturn(new TransactionJournal); - // list size $pref = new Preference; $pref->data = 50; diff --git a/tests/Feature/Controllers/Admin/ConfigurationControllerTest.php b/tests/Feature/Controllers/Admin/ConfigurationControllerTest.php index 96ec936849..84138bb231 100644 --- a/tests/Feature/Controllers/Admin/ConfigurationControllerTest.php +++ b/tests/Feature/Controllers/Admin/ConfigurationControllerTest.php @@ -22,11 +22,15 @@ declare(strict_types=1); namespace Tests\Feature\Controllers\Admin; +use Amount; use FireflyConfig; use FireflyIII\Models\Configuration; +use FireflyIII\Models\TransactionJournal; +use FireflyIII\Repositories\Journal\JournalRepositoryInterface; use FireflyIII\Repositories\User\UserRepositoryInterface; use Log; use Mockery; +use Preferences; use Tests\TestCase; /** @@ -44,14 +48,19 @@ class ConfigurationControllerTest extends TestCase } /** - * @covers \FireflyIII\Http\Controllers\Admin\ConfigurationController * @covers \FireflyIII\Http\Controllers\Admin\ConfigurationController */ public function testIndex(): void { - $userRepos = $this->mock(UserRepositoryInterface::class); + $userRepos = $this->mock(UserRepositoryInterface::class); + $journalRepos = $this->mock(JournalRepositoryInterface::class); + $euro = $this->getEuro(); + // for session + $journalRepos->shouldReceive('firstNull')->once()->andReturn(new TransactionJournal); $userRepos->shouldReceive('hasRole')->withArgs([Mockery::any(), 'owner'])->andReturn(true)->atLeast()->once(); + Amount::shouldReceive('getDefaultCurrency')->atLeast()->once()->andReturn($euro); + $this->mockDefaultPreferences(); $this->be($this->user()); $falseConfig = new Configuration; @@ -72,10 +81,19 @@ class ConfigurationControllerTest extends TestCase /** * @covers \FireflyIII\Http\Controllers\Admin\ConfigurationController + * @covers \FireflyIII\Http\Requests\ConfigurationRequest */ public function testPostIndex(): void { $userRepos = $this->mock(UserRepositoryInterface::class); + $journalRepos = $this->mock(JournalRepositoryInterface::class); + $euro = $this->getEuro(); + + // for session + $journalRepos->shouldReceive('firstNull')->once()->andReturn(new TransactionJournal); + + Amount::shouldReceive('getDefaultCurrency')->atLeast()->once()->andReturn($euro); + $this->mockDefaultPreferences(); $userRepos->shouldReceive('hasRole')->withArgs([Mockery::any(), 'owner'])->andReturn(true)->atLeast()->once(); $userRepos->shouldReceive('hasRole')->withArgs([Mockery::any(), 'demo'])->andReturn(false)->atLeast()->once(); @@ -86,6 +104,7 @@ class ConfigurationControllerTest extends TestCase FireflyConfig::shouldReceive('get')->withArgs(['is_demo_site', false])->once()->andReturn($falseConfig); FireflyConfig::shouldReceive('set')->withArgs(['single_user_mode', false])->once(); FireflyConfig::shouldReceive('set')->withArgs(['is_demo_site', false])->once(); + Preferences::shouldReceive('mark')->atLeast()->once(); $this->be($this->user()); $response = $this->post(route('admin.configuration.index.post')); diff --git a/tests/Feature/Controllers/Admin/HomeControllerTest.php b/tests/Feature/Controllers/Admin/HomeControllerTest.php index dc8ebdbc90..5ddf058768 100644 --- a/tests/Feature/Controllers/Admin/HomeControllerTest.php +++ b/tests/Feature/Controllers/Admin/HomeControllerTest.php @@ -22,8 +22,11 @@ declare(strict_types=1); namespace Tests\Feature\Controllers\Admin; +use Amount; use Event; use FireflyIII\Events\AdminRequestedTestMessage; +use FireflyIII\Models\TransactionJournal; +use FireflyIII\Repositories\Journal\JournalRepositoryInterface; use FireflyIII\Repositories\User\UserRepositoryInterface; use Log; use Mockery; @@ -49,6 +52,14 @@ class HomeControllerTest extends TestCase public function testIndex(): void { $userRepos = $this->mock(UserRepositoryInterface::class); + $journalRepos = $this->mock(JournalRepositoryInterface::class); + $euro = $this->getEuro(); + + // default for session + $this->mockDefaultPreferences(); + $this->mockDefaultConfiguration(); + $journalRepos->shouldReceive('firstNull')->once()->andReturn(new TransactionJournal); + Amount::shouldReceive('getDefaultCurrency')->atLeast()->once()->andReturn($euro); $userRepos->shouldReceive('hasRole')->withArgs([Mockery::any(), 'owner'])->andReturn(true)->atLeast()->once(); @@ -65,6 +76,13 @@ class HomeControllerTest extends TestCase public function testTestMessage(): void { $userRepos = $this->mock(UserRepositoryInterface::class); + $journalRepos = $this->mock(JournalRepositoryInterface::class); + $euro = $this->getEuro(); + + $journalRepos->shouldReceive('firstNull')->once()->andReturn(new TransactionJournal); + Amount::shouldReceive('getDefaultCurrency')->atLeast()->once()->andReturn($euro); + $this->mockDefaultPreferences(); + $this->mockDefaultConfiguration(); $userRepos->shouldReceive('hasRole')->withArgs([Mockery::any(), 'owner'])->andReturn(true)->atLeast()->once(); $userRepos->shouldReceive('hasRole')->withArgs([Mockery::any(), 'demo'])->andReturn(false)->atLeast()->once(); diff --git a/tests/Feature/Controllers/Admin/LinkControllerTest.php b/tests/Feature/Controllers/Admin/LinkControllerTest.php index 6ab3db5b46..f7b75104de 100644 --- a/tests/Feature/Controllers/Admin/LinkControllerTest.php +++ b/tests/Feature/Controllers/Admin/LinkControllerTest.php @@ -29,6 +29,7 @@ use Illuminate\Support\Collection; use Log; use Mockery; use Tests\TestCase; +use Preferences; /** * Class LinkControllerTest @@ -50,6 +51,11 @@ class LinkControllerTest extends TestCase public function testCreate(): void { $userRepos = $this->mock(UserRepositoryInterface::class); + $repository = $this->mock(LinkTypeRepositoryInterface::class); + + // mock default session stuff + $this->mockDefaultSession(); + $userRepos->shouldReceive('hasRole')->withArgs([Mockery::any(), 'owner'])->andReturn(true)->atLeast()->once(); $userRepos->shouldReceive('hasRole')->withArgs([Mockery::any(), 'demo'])->andReturn(false)->atLeast()->once(); @@ -66,17 +72,23 @@ class LinkControllerTest extends TestCase $userRepos = $this->mock(UserRepositoryInterface::class); $repository = $this->mock(LinkTypeRepositoryInterface::class); // create editable link type just in case: - LinkType::create(['editable' => 1, 'inward' => 'hello', 'outward' => 'bye', 'name' => 'Test type']); + $newType = LinkType::create(['editable' => 1, 'inward' => 'hello', 'outward' => 'bye', 'name' => 'Test type']); + + // mock default session stuff + $this->mockDefaultSession(); $userRepos->shouldReceive('hasRole')->withArgs([Mockery::any(), 'owner'])->andReturn(true)->atLeast()->once(); $userRepos->shouldReceive('hasRole')->withArgs([Mockery::any(), 'demo'])->andReturn(false)->atLeast()->once(); $linkType = LinkType::where('editable', 1)->first(); - $repository->shouldReceive('get')->once()->andReturn(new Collection([$linkType])); + $another= LinkType::where('editable', 0)->first(); + $repository->shouldReceive('get')->once()->andReturn(new Collection([$linkType, $another])); $repository->shouldReceive('countJournals')->andReturn(2); $this->be($this->user()); $response = $this->get(route('admin.links.delete', [$linkType->id])); $response->assertStatus(200); + + $newType->forceDelete(); } /** @@ -88,6 +100,9 @@ class LinkControllerTest extends TestCase $repository = $this->mock(LinkTypeRepositoryInterface::class); $linkType = LinkType::where('editable', 0)->first(); + // mock default session stuff + $this->mockDefaultSession(); + $userRepos->shouldReceive('hasRole')->withArgs([Mockery::any(), 'owner'])->andReturn(true)->atLeast()->once(); $userRepos->shouldReceive('hasRole')->withArgs([Mockery::any(), 'demo'])->andReturn(false)->atLeast()->once(); $this->be($this->user()); @@ -107,6 +122,10 @@ class LinkControllerTest extends TestCase $userRepos->shouldReceive('hasRole')->withArgs([Mockery::any(), 'owner'])->andReturn(true)->atLeast()->once(); $userRepos->shouldReceive('hasRole')->withArgs([Mockery::any(), 'demo'])->andReturn(false)->atLeast()->once(); + // mock default session stuff + $this->mockDefaultSession(); + Preferences::shouldReceive('mark')->atLeast()->once(); + // create editable link type just in case: LinkType::create(['editable' => 1, 'inward' => 'hellox', 'outward' => 'byex', 'name' => 'Test typeX']); @@ -126,10 +145,14 @@ class LinkControllerTest extends TestCase public function testEditEditable(): void { $userRepos = $this->mock(UserRepositoryInterface::class); + $repository = $this->mock(LinkTypeRepositoryInterface::class); $userRepos->shouldReceive('hasRole')->withArgs([Mockery::any(), 'owner'])->andReturn(true)->atLeast()->once(); $userRepos->shouldReceive('hasRole')->withArgs([Mockery::any(), 'demo'])->andReturn(false)->atLeast()->once(); + // mock default session stuff + $this->mockDefaultSession(); + // create editable link type just in case: LinkType::create(['editable' => 1, 'inward' => 'hello Y', 'outward' => 'bye Y', 'name' => 'Test type Y']); @@ -145,10 +168,15 @@ class LinkControllerTest extends TestCase public function testEditNonEditable(): void { $userRepos = $this->mock(UserRepositoryInterface::class); + $repository = $this->mock(LinkTypeRepositoryInterface::class); $userRepos->shouldReceive('hasRole')->withArgs([Mockery::any(), 'owner'])->andReturn(true)->atLeast()->once(); $userRepos->shouldReceive('hasRole')->withArgs([Mockery::any(), 'demo'])->andReturn(false)->atLeast()->once(); + // mock default session stuff + $this->mockDefaultSession(); + + $linkType = LinkType::where('editable', 0)->first(); $this->be($this->user()); $response = $this->get(route('admin.links.edit', [$linkType->id])); @@ -162,9 +190,13 @@ class LinkControllerTest extends TestCase public function testIndex(): void { $userRepos = $this->mock(UserRepositoryInterface::class); + $repository = $this->mock(LinkTypeRepositoryInterface::class); $userRepos->shouldReceive('hasRole')->withArgs([Mockery::any(), 'owner'])->andReturn(true)->atLeast()->once(); + // mock default session stuff + $this->mockDefaultSession(); + //Preferences::shouldReceive('mark')->atLeast()->once(); $linkTypes = LinkType::inRandomOrder()->take(3)->get(); $repository = $this->mock(LinkTypeRepositoryInterface::class); @@ -181,8 +213,11 @@ class LinkControllerTest extends TestCase public function testShow(): void { $userRepos = $this->mock(UserRepositoryInterface::class); + $repository = $this->mock(LinkTypeRepositoryInterface::class); $userRepos->shouldReceive('hasRole')->withArgs([Mockery::any(), 'owner'])->andReturn(true)->atLeast()->once(); + $repository->shouldReceive('getJournalLinks')->andReturn(new Collection); + $this->mockDefaultSession(); $linkType = LinkType::first(); @@ -203,10 +238,13 @@ class LinkControllerTest extends TestCase $userRepos->shouldReceive('hasRole')->withArgs([Mockery::any(), 'owner'])->andReturn(true)->atLeast()->once(); $userRepos->shouldReceive('hasRole')->withArgs([Mockery::any(), 'demo'])->andReturn(false)->atLeast()->once(); + // mock default session stuff + $this->mockDefaultSession(); + $data = [ - 'name' => 'test ' . random_int(1, 10000), - 'inward' => 'test inward' . random_int(1, 10000), - 'outward' => 'test outward' . random_int(1, 10000), + 'name' => sprintf('test %d', $this->randomInt()), + 'inward' => sprintf('test inward %d', $this->randomInt()), + 'outward' => sprintf('test outward %d', $this->randomInt()), ]; $repository->shouldReceive('store')->once()->andReturn(LinkType::first()); $repository->shouldReceive('findNull')->andReturn(LinkType::first()); @@ -230,10 +268,13 @@ class LinkControllerTest extends TestCase $userRepos->shouldReceive('hasRole')->withArgs([Mockery::any(), 'owner'])->andReturn(true)->atLeast()->once(); $userRepos->shouldReceive('hasRole')->withArgs([Mockery::any(), 'demo'])->andReturn(false)->atLeast()->once(); + // mock default session stuff + $this->mockDefaultSession(); + $data = [ - 'name' => 'test ' . random_int(1, 10000), - 'inward' => 'test inward' . random_int(1, 10000), - 'outward' => 'test outward' . random_int(1, 10000), + 'name' => sprintf('test %d', $this->randomInt()), + 'inward' => sprintf('test inward %d', $this->randomInt()), + 'outward' => sprintf('test outward %d', $this->randomInt()), 'create_another' => '1', ]; $repository->shouldReceive('store')->once()->andReturn(new LinkType); @@ -260,10 +301,14 @@ class LinkControllerTest extends TestCase $linkType = LinkType::create(['editable' => 1, 'inward' => 'helloxz', 'outward' => 'bzyex', 'name' => 'Test tyzpeX']); $repository->shouldReceive('update')->once()->andReturn(new $linkType); + // mock default session stuff + $this->mockDefaultSession(); + Preferences::shouldReceive('mark')->atLeast()->once(); + $data = [ - 'name' => 'test ' . random_int(1, 10000), - 'inward' => 'test inward' . random_int(1, 10000), - 'outward' => 'test outward' . random_int(1, 10000), + 'name' => sprintf('test %d', $this->randomInt()), + 'inward' => sprintf('test inward %d', $this->randomInt()), + 'outward' => sprintf('test outward %d', $this->randomInt()), ]; $this->session(['link_types.edit.uri' => 'http://localhost']); $this->be($this->user()); @@ -284,12 +329,14 @@ class LinkControllerTest extends TestCase $userRepos->shouldReceive('hasRole')->withArgs([Mockery::any(), 'owner'])->andReturn(true)->atLeast()->once(); $userRepos->shouldReceive('hasRole')->withArgs([Mockery::any(), 'demo'])->andReturn(false)->atLeast()->once(); + // mock default session stuff + $this->mockDefaultSession(); $linkType = LinkType::where('editable', 0)->first(); $data = [ - 'name' => 'test ' . random_int(1, 10000), - 'inward' => 'test inward' . random_int(1, 10000), - 'outward' => 'test outward' . random_int(1, 10000), + 'name' => sprintf('test %d', $this->randomInt()), + 'inward' => sprintf('test inward %d', $this->randomInt()), + 'outward' => sprintf('test outward %d', $this->randomInt()), 'return_to_edit' => '1', ]; $this->session(['link_types.edit.uri' => 'http://localhost']); @@ -314,10 +361,14 @@ class LinkControllerTest extends TestCase // create editable link type just in case: $linkType = LinkType::create(['editable' => 1, 'inward' => 'healox', 'outward' => 'byaex', 'name' => 'Test tyapeX']); + // mock default session stuff + $this->mockDefaultSession(); + Preferences::shouldReceive('mark')->atLeast()->once(); + $data = [ - 'name' => 'test ' . random_int(1, 10000), - 'inward' => 'test inward' . random_int(1, 10000), - 'outward' => 'test outward' . random_int(1, 10000), + 'name' => sprintf('test %d', $this->randomInt()), + 'inward' => sprintf('test inward %d', $this->randomInt()), + 'outward' => sprintf('test outward %d', $this->randomInt()), 'return_to_edit' => '1', ]; $repository->shouldReceive('update')->once()->andReturn(new $linkType); diff --git a/tests/Feature/Controllers/Admin/UpdateControllerTest.php b/tests/Feature/Controllers/Admin/UpdateControllerTest.php index 08692fe0c0..3c9518490c 100644 --- a/tests/Feature/Controllers/Admin/UpdateControllerTest.php +++ b/tests/Feature/Controllers/Admin/UpdateControllerTest.php @@ -52,25 +52,22 @@ class UpdateControllerTest extends TestCase */ public function testIndex(): void { + // mock stuff $userRepos = $this->mock(UserRepositoryInterface::class); + // mock calls $userRepos->shouldReceive('hasRole')->withArgs([Mockery::any(), 'owner'])->andReturn(true)->atLeast()->once(); + $this->mockDefaultSession(); - $this->be($this->user()); - - $config = new Configuration; - $config->data = -1; - - $falseConfig = new Configuration; - $falseConfig->data = false; - + // mock update calls. + $config = new Configuration; + $config->data = -1; FireflyConfig::shouldReceive('get')->withArgs(['permission_update_check', -1])->once()->andReturn($config); - FireflyConfig::shouldReceive('get')->withArgs(['is_demo_site', false])->once()->andReturn($falseConfig); + // call service + $this->be($this->user()); $response = $this->get(route('admin.update-check')); $response->assertStatus(200); - - // has bread crumb $response->assertSee('