diff --git a/app/Api/V1/Requests/RecurrenceRequest.php b/app/Api/V1/Requests/RecurrenceRequest.php index 5e4d646aa9..fd348c733d 100644 --- a/app/Api/V1/Requests/RecurrenceRequest.php +++ b/app/Api/V1/Requests/RecurrenceRequest.php @@ -84,8 +84,7 @@ class RecurrenceRequest extends Request */ public function rules(): array { - $today = new Carbon; - $today->addDay(); + $today = Carbon::create()->addDay(); return [ 'type' => 'required|in:withdrawal,transfer,deposit', diff --git a/app/Generator/Report/Account/MonthReportGenerator.php b/app/Generator/Report/Account/MonthReportGenerator.php index 4693e71c0d..49f0cbfbd7 100644 --- a/app/Generator/Report/Account/MonthReportGenerator.php +++ b/app/Generator/Report/Account/MonthReportGenerator.php @@ -44,7 +44,7 @@ class MonthReportGenerator implements ReportGeneratorInterface * Generate the report. * * @return string - + * @throws \Throwable */ public function generate(): string { diff --git a/app/Generator/Report/Audit/MonthReportGenerator.php b/app/Generator/Report/Audit/MonthReportGenerator.php index 666738d73a..386f27ded2 100644 --- a/app/Generator/Report/Audit/MonthReportGenerator.php +++ b/app/Generator/Report/Audit/MonthReportGenerator.php @@ -51,7 +51,8 @@ class MonthReportGenerator implements ReportGeneratorInterface * Generates the report. * * @return string - + * @throws FireflyException + * @throws \Throwable */ public function generate(): string { diff --git a/app/Generator/Report/Budget/MonthReportGenerator.php b/app/Generator/Report/Budget/MonthReportGenerator.php index dc9d47c244..ff4229ab26 100644 --- a/app/Generator/Report/Budget/MonthReportGenerator.php +++ b/app/Generator/Report/Budget/MonthReportGenerator.php @@ -64,7 +64,7 @@ class MonthReportGenerator extends Support implements ReportGeneratorInterface * Generates the report. * * @return string - + * @throws \Throwable */ public function generate(): string { diff --git a/app/Generator/Report/Category/MonthReportGenerator.php b/app/Generator/Report/Category/MonthReportGenerator.php index 8957ca3020..ef187a575b 100644 --- a/app/Generator/Report/Category/MonthReportGenerator.php +++ b/app/Generator/Report/Category/MonthReportGenerator.php @@ -68,7 +68,7 @@ class MonthReportGenerator extends Support implements ReportGeneratorInterface * Generates the report. * * @return string - + * @throws \Throwable */ public function generate(): string { diff --git a/app/Generator/Report/Standard/MonthReportGenerator.php b/app/Generator/Report/Standard/MonthReportGenerator.php index 987b0ec304..e27f4d79ed 100644 --- a/app/Generator/Report/Standard/MonthReportGenerator.php +++ b/app/Generator/Report/Standard/MonthReportGenerator.php @@ -43,7 +43,7 @@ class MonthReportGenerator implements ReportGeneratorInterface * Generates the report. * * @return string - + * @throws \Throwable */ public function generate(): string { diff --git a/app/Generator/Report/Standard/MultiYearReportGenerator.php b/app/Generator/Report/Standard/MultiYearReportGenerator.php index 69174d06b8..ec507b9386 100644 --- a/app/Generator/Report/Standard/MultiYearReportGenerator.php +++ b/app/Generator/Report/Standard/MultiYearReportGenerator.php @@ -42,7 +42,7 @@ class MultiYearReportGenerator implements ReportGeneratorInterface * Generates the report. * * @return string - + * @throws \Throwable */ public function generate(): string { diff --git a/app/Generator/Report/Standard/YearReportGenerator.php b/app/Generator/Report/Standard/YearReportGenerator.php index ef844a4a85..47f92f47ad 100644 --- a/app/Generator/Report/Standard/YearReportGenerator.php +++ b/app/Generator/Report/Standard/YearReportGenerator.php @@ -42,7 +42,7 @@ class YearReportGenerator implements ReportGeneratorInterface * Generates the report. * * @return string - + * @throws \Throwable */ public function generate(): string { diff --git a/app/Generator/Report/Tag/MonthReportGenerator.php b/app/Generator/Report/Tag/MonthReportGenerator.php index 2242381c2d..e367283624 100644 --- a/app/Generator/Report/Tag/MonthReportGenerator.php +++ b/app/Generator/Report/Tag/MonthReportGenerator.php @@ -70,8 +70,7 @@ class MonthReportGenerator extends Support implements ReportGeneratorInterface * Generate the report. * * @return string - - + * @throws \Throwable */ public function generate(): string { diff --git a/app/Handlers/Events/VersionCheckEventHandler.php b/app/Handlers/Events/VersionCheckEventHandler.php index b7e7a14ced..3955de9098 100644 --- a/app/Handlers/Events/VersionCheckEventHandler.php +++ b/app/Handlers/Events/VersionCheckEventHandler.php @@ -80,13 +80,6 @@ class VersionCheckEventHandler // last check time was more than a week ago. Log::debug('Have not checked for a new version in a week!'); - // have actual permission? - if ($permission->data === -1) { - // never asked before. - //session()->flash('info', (string)trans('firefly.check_for_updates_permission', ['link' => route('admin.update-check')])); - //return; - } - $latestRelease = $this->getLatestRelease(); $versionCheck = $this->versionCheck($latestRelease); $resultString = $this->parseResult($latestRelease, $versionCheck); diff --git a/app/Http/Controllers/Chart/BudgetController.php b/app/Http/Controllers/Chart/BudgetController.php index 90e647a768..8ca96aa5d9 100644 --- a/app/Http/Controllers/Chart/BudgetController.php +++ b/app/Http/Controllers/Chart/BudgetController.php @@ -83,7 +83,8 @@ class BudgetController extends Controller */ public function budget(Budget $budget): JsonResponse { - $start = $this->repository->firstUseDate($budget); + /** @var Carbon $start */ + $start = $this->repository->firstUseDate($budget) ?? session('start', new Carbon); /** @var Carbon $end */ $end = session('end', new Carbon); $cache = new CacheProperties(); diff --git a/app/Http/Controllers/Popup/ReportController.php b/app/Http/Controllers/Popup/ReportController.php index a9633c1826..1bdb211b1f 100644 --- a/app/Http/Controllers/Popup/ReportController.php +++ b/app/Http/Controllers/Popup/ReportController.php @@ -274,8 +274,7 @@ class ReportController extends Controller $attributes['startDate'] = Carbon::createFromFormat('Ymd', $attributes['startDate']); } catch (InvalidArgumentException $e) { Log::debug(sprintf('Not important error message: %s', $e->getMessage())); - $date = new Carbon; - $date->startOfMonth(); + $date = Carbon::create()->startOfMonth(); $attributes['startDate'] = $date; } @@ -283,8 +282,7 @@ class ReportController extends Controller $attributes['endDate'] = Carbon::createFromFormat('Ymd', $attributes['endDate']); } catch (InvalidArgumentException $e) { Log::debug('Not important error message: %s', $e->getMessage()); - $date = new Carbon; - $date->startOfMonth(); + $date = Carbon::create()->startOfMonth(); $attributes['endDate'] = $date; } diff --git a/app/Http/Controllers/TransactionController.php b/app/Http/Controllers/TransactionController.php index 815114325b..c9685012a6 100644 --- a/app/Http/Controllers/TransactionController.php +++ b/app/Http/Controllers/TransactionController.php @@ -262,8 +262,7 @@ class TransactionController extends Controller { $range = app('preferences')->get('viewRange', '1M')->data; $first = $this->repository->firstNull(); - $start = new Carbon; - $start->subYear(); + $start = Carbon::create()->subYear(); $types = config('firefly.transactionTypesByWhat.' . $what); $entries = new Collection; if (null !== $first) { diff --git a/app/Http/Middleware/Range.php b/app/Http/Middleware/Range.php index 9ff1f89e1d..70acc493f0 100644 --- a/app/Http/Middleware/Range.php +++ b/app/Http/Middleware/Range.php @@ -124,8 +124,7 @@ class Range // ignore preference. set the range to be the current month: if (!app('session')->has('start') && !app('session')->has('end')) { $viewRange = app('preferences')->get('viewRange', '1M')->data; - $start = new Carbon; - $start = app('navigation')->updateStartDate($viewRange, $start); + $start = app('navigation')->updateStartDate($viewRange, new Carbon); $end = app('navigation')->updateEndDate($viewRange, $start); app('session')->put('start', $start); diff --git a/app/Http/Requests/RecurrenceFormRequest.php b/app/Http/Requests/RecurrenceFormRequest.php index 59b62874bf..0ddd7bb8c2 100644 --- a/app/Http/Requests/RecurrenceFormRequest.php +++ b/app/Http/Requests/RecurrenceFormRequest.php @@ -149,8 +149,7 @@ class RecurrenceFormRequest extends Request public function rules(): array { $today = new Carbon; - $tomorrow = clone $today; - $tomorrow->addDay(); + $tomorrow = Carbon::create()->addDay(); $rules = [ // mandatory info for recurrence. 'title' => 'required|between:1,255|uniqueObjectForUser:recurrences,title', diff --git a/app/Providers/BroadcastServiceProvider.php b/app/Providers/BroadcastServiceProvider.php index 2b64d5d036..845be09666 100644 --- a/app/Providers/BroadcastServiceProvider.php +++ b/app/Providers/BroadcastServiceProvider.php @@ -38,6 +38,7 @@ class BroadcastServiceProvider extends ServiceProvider { Broadcast::routes(); + /** @noinspection PhpIncludeInspection */ require base_path('routes/channels.php'); } } diff --git a/app/Repositories/Account/AccountRepository.php b/app/Repositories/Account/AccountRepository.php index f1074de2bf..56d2b8289c 100644 --- a/app/Repositories/Account/AccountRepository.php +++ b/app/Repositories/Account/AccountRepository.php @@ -23,23 +23,24 @@ declare(strict_types=1); namespace FireflyIII\Repositories\Account; use Carbon\Carbon; +use FireflyIII\Exceptions\FireflyException; use FireflyIII\Factory\AccountFactory; use FireflyIII\Models\Account; use FireflyIII\Models\AccountType; -use FireflyIII\Models\Note; use FireflyIII\Models\TransactionJournal; use FireflyIII\Models\TransactionType; use FireflyIII\Services\Internal\Destroy\AccountDestroyService; use FireflyIII\Services\Internal\Update\AccountUpdateService; -use FireflyIII\Services\Internal\Update\JournalUpdateService; use FireflyIII\User; +use Illuminate\Support\Collection; +use Log; /** * Class AccountRepository. */ class AccountRepository implements AccountRepositoryInterface { - use FindAccountsTrait; + /** @var User */ private $user; @@ -72,6 +73,89 @@ class AccountRepository implements AccountRepositoryInterface return true; } + /** + * @param string $number + * @param array $types + * + * @return Account|null + */ + public function findByAccountNumber(string $number, array $types): ?Account + { + $query = $this->user->accounts() + ->leftJoin('account_meta', 'account_meta.account_id', '=', 'accounts.id') + ->where('account_meta.name', 'accountNumber') + ->where('account_meta.data', json_encode($number)); + + if (\count($types) > 0) { + $query->leftJoin('account_types', 'accounts.account_type_id', '=', 'account_types.id'); + $query->whereIn('account_types.type', $types); + } + + /** @var Collection $accounts */ + $accounts = $query->get(['accounts.*']); + if ($accounts->count() > 0) { + return $accounts->first(); + } + + return null; + } + + /** + * @param string $iban + * @param array $types + * + * @return Account|null + */ + public function findByIbanNull(string $iban, array $types): ?Account + { + $query = $this->user->accounts()->where('iban', '!=', '')->whereNotNull('iban'); + + if (\count($types) > 0) { + $query->leftJoin('account_types', 'accounts.account_type_id', '=', 'account_types.id'); + $query->whereIn('account_types.type', $types); + } + + $accounts = $query->get(['accounts.*']); + /** @var Account $account */ + foreach ($accounts as $account) { + if ($account->iban === $iban) { + return $account; + } + } + + return null; + } + + /** + * @param string $name + * @param array $types + * + * @return Account|null + */ + public function findByName(string $name, array $types): ?Account + { + $query = $this->user->accounts(); + + if (\count($types) > 0) { + $query->leftJoin('account_types', 'accounts.account_type_id', '=', 'account_types.id'); + $query->whereIn('account_types.type', $types); + } + Log::debug(sprintf('Searching for account named "%s" (of user #%d) of the following type(s)', $name, $this->user->id), ['types' => $types]); + + $accounts = $query->get(['accounts.*']); + /** @var Account $account */ + foreach ($accounts as $account) { + if ($account->name === $name) { + Log::debug(sprintf('Found #%d (%s) with type id %d', $account->id, $account->name, $account->account_type_id)); + + return $account; + } + } + Log::debug(sprintf('There is no account with name "%s" of types', $name), $types); + + return null; + } + /** * @param int $accountId * @@ -82,6 +166,96 @@ class AccountRepository implements AccountRepositoryInterface return $this->user->accounts()->find($accountId); } + /** + * @param array $accountIds + * + * @return Collection + */ + public function getAccountsById(array $accountIds): Collection + { + /** @var Collection $result */ + $query = $this->user->accounts(); + + if (\count($accountIds) > 0) { + $query->whereIn('accounts.id', $accountIds); + } + + $result = $query->get(['accounts.*']); + $result = $result->sortBy( + function (Account $account) { + return strtolower($account->name); + } + ); + + return $result; + } + + /** + * @param array $types + * + * @return Collection + */ + public function getAccountsByType(array $types): Collection + { + /** @var Collection $result */ + $query = $this->user->accounts(); + if (\count($types) > 0) { + $query->accountTypeIn($types); + } + + $result = $query->get(['accounts.*']); + $result = $result->sortBy( + function (Account $account) { + return strtolower($account->name); + } + ); + + return $result; + } + + /** + * @param array $types + * + * @return Collection + */ + public function getActiveAccountsByType(array $types): Collection + { + /** @var Collection $result */ + $query = $this->user->accounts()->with( + ['accountmeta' => function (HasMany $query) { + $query->where('name', 'accountRole'); + }] + ); + if (\count($types) > 0) { + $query->accountTypeIn($types); + } + $query->where('active', 1); + $result = $query->get(['accounts.*']); + $result = $result->sortBy( + function (Account $account) { + return strtolower($account->name); + } + ); + + return $result; + } + + /** + * @return Account + * + * @throws FireflyException + */ + public function getCashAccount(): Account + { + /** @var AccountType $type */ + $type = AccountType::where('type', AccountType::CASH)->first(); + /** @var AccountFactory $factory */ + $factory = app(AccountFactory::class); + $factory->setUser($this->user); + + return $factory->findOrCreate('Cash account', $type->type); + } + /** * Return meta value for account. Null if not found. * @@ -163,11 +337,41 @@ class AccountRepository implements AccountRepositoryInterface return $journal->date->format('Y-m-d'); } + /** + * @param Account $account + * + * @return Account|null + * + * @throws FireflyException + */ + public function getReconciliation(Account $account): ?Account + { + if (AccountType::ASSET !== $account->accountType->type) { + throw new FireflyException(sprintf('%s is not an asset account.', $account->name)); + } + $name = $account->name . ' reconciliation'; + /** @var AccountType $type */ + $type = AccountType::where('type', AccountType::RECONCILIATION)->first(); + $accounts = $this->user->accounts()->where('account_type_id', $type->id)->get(); + /** @var Account $current */ + foreach ($accounts as $current) { + if ($current->name === $name) { + return $current; + } + } + /** @var AccountFactory $factory */ + $factory = app(AccountFactory::class); + $factory->setUser($account->user); + $account = $factory->findOrCreate($name, $type->type); + + return $account; + } + /** * Returns the date of the very first transaction in this account. * * @param Account $account - * + * @deprecated * @return TransactionJournal */ public function oldestJournal(Account $account): TransactionJournal diff --git a/app/Repositories/Account/AccountRepositoryInterface.php b/app/Repositories/Account/AccountRepositoryInterface.php index e7399060a6..3ea3c1be42 100644 --- a/app/Repositories/Account/AccountRepositoryInterface.php +++ b/app/Repositories/Account/AccountRepositoryInterface.php @@ -164,7 +164,7 @@ interface AccountRepositoryInterface * Returns the date of the very first transaction in this account. * * @param Account $account - * + * @deprecated * @return TransactionJournal */ public function oldestJournal(Account $account): TransactionJournal; diff --git a/app/Repositories/Account/FindAccountsTrait.php b/app/Repositories/Account/FindAccountsTrait.php deleted file mode 100644 index fa4254039b..0000000000 --- a/app/Repositories/Account/FindAccountsTrait.php +++ /dev/null @@ -1,248 +0,0 @@ -. - */ -declare(strict_types=1); - -namespace FireflyIII\Repositories\Account; - -use FireflyIII\Exceptions\FireflyException; -use FireflyIII\Factory\AccountFactory; -use FireflyIII\Models\Account; -use FireflyIII\Models\AccountType; -use FireflyIII\User; -use Illuminate\Database\Eloquent\Relations\HasMany; -use Illuminate\Support\Collection; -use Log; - -/** - * @property User $user - * - * Trait FindAccountsTrait - */ -trait FindAccountsTrait -{ - - /** - * @param string $number - * @param array $types - * - * @return Account|null - */ - public function findByAccountNumber(string $number, array $types): ?Account - { - $query = $this->user->accounts() - ->leftJoin('account_meta', 'account_meta.account_id', '=', 'accounts.id') - ->where('account_meta.name', 'accountNumber') - ->where('account_meta.data', json_encode($number)); - - if (\count($types) > 0) { - $query->leftJoin('account_types', 'accounts.account_type_id', '=', 'account_types.id'); - $query->whereIn('account_types.type', $types); - } - - /** @var Collection $accounts */ - $accounts = $query->get(['accounts.*']); - if ($accounts->count() > 0) { - return $accounts->first(); - } - - return null; - } - - /** - * @param string $iban - * @param array $types - * - * @return Account|null - */ - public function findByIbanNull(string $iban, array $types): ?Account - { - $query = $this->user->accounts()->where('iban', '!=', '')->whereNotNull('iban'); - - if (\count($types) > 0) { - $query->leftJoin('account_types', 'accounts.account_type_id', '=', 'account_types.id'); - $query->whereIn('account_types.type', $types); - } - - $accounts = $query->get(['accounts.*']); - /** @var Account $account */ - foreach ($accounts as $account) { - if ($account->iban === $iban) { - return $account; - } - } - - return null; - } - - /** - * @param string $name - * @param array $types - * - * @return Account|null - */ - public function findByName(string $name, array $types): ?Account - { - $query = $this->user->accounts(); - - if (\count($types) > 0) { - $query->leftJoin('account_types', 'accounts.account_type_id', '=', 'account_types.id'); - $query->whereIn('account_types.type', $types); - } - Log::debug(sprintf('Searching for account named "%s" (of user #%d) of the following type(s)', $name, $this->user->id), ['types' => $types]); - - $accounts = $query->get(['accounts.*']); - /** @var Account $account */ - foreach ($accounts as $account) { - if ($account->name === $name) { - Log::debug(sprintf('Found #%d (%s) with type id %d', $account->id, $account->name, $account->account_type_id)); - - return $account; - } - if ($account->name !== $name) { - Log::debug(sprintf('"%s" does not equal "%s"', $account->name, $name)); - } - } - Log::debug(sprintf('There is no account with name "%s" of types', $name), $types); - - return null; - } - - /** - * @param array $accountIds - * - * @return Collection - */ - public function getAccountsById(array $accountIds): Collection - { - /** @var Collection $result */ - $query = $this->user->accounts(); - - if (\count($accountIds) > 0) { - $query->whereIn('accounts.id', $accountIds); - } - - $result = $query->get(['accounts.*']); - $result = $result->sortBy( - function (Account $account) { - return strtolower($account->name); - } - ); - - return $result; - } - - /** - * @param array $types - * - * @return Collection - */ - public function getAccountsByType(array $types): Collection - { - /** @var Collection $result */ - $query = $this->user->accounts(); - if (\count($types) > 0) { - $query->accountTypeIn($types); - } - - $result = $query->get(['accounts.*']); - $result = $result->sortBy( - function (Account $account) { - return strtolower($account->name); - } - ); - - return $result; - } - - /** - * @param array $types - * - * @return Collection - */ - public function getActiveAccountsByType(array $types): Collection - { - /** @var Collection $result */ - $query = $this->user->accounts()->with( - ['accountmeta' => function (HasMany $query) { - $query->where('name', 'accountRole'); - }] - ); - if (\count($types) > 0) { - $query->accountTypeIn($types); - } - $query->where('active', 1); - $result = $query->get(['accounts.*']); - $result = $result->sortBy( - function (Account $account) { - return strtolower($account->name); - } - ); - - return $result; - } - - /** - * @return Account - * - * @throws FireflyException - */ - public function getCashAccount(): Account - { - /** @var AccountType $type */ - $type = AccountType::where('type', AccountType::CASH)->first(); - /** @var AccountFactory $factory */ - $factory = app(AccountFactory::class); - $factory->setUser($this->user); - - return $factory->findOrCreate('Cash account', $type->type); - } - - /** - * @param Account $account - * - * @return Account|null - * - * @throws FireflyException - */ - public function getReconciliation(Account $account): ?Account - { - if (AccountType::ASSET !== $account->accountType->type) { - throw new FireflyException(sprintf('%s is not an asset account.', $account->name)); - } - $name = $account->name . ' reconciliation'; - /** @var AccountType $type */ - $type = AccountType::where('type', AccountType::RECONCILIATION)->first(); - $accounts = $this->user->accounts()->where('account_type_id', $type->id)->get(); - /** @var Account $current */ - foreach ($accounts as $current) { - if ($current->name === $name) { - return $current; - } - } - /** @var AccountFactory $factory */ - $factory = app(AccountFactory::class); - $factory->setUser($account->user); - $account = $factory->findOrCreate($name, $type->type); - - return $account; - } - -} diff --git a/app/Repositories/Attachment/AttachmentRepository.php b/app/Repositories/Attachment/AttachmentRepository.php index 6d23f64480..cf723f56bb 100644 --- a/app/Repositories/Attachment/AttachmentRepository.php +++ b/app/Repositories/Attachment/AttachmentRepository.php @@ -80,14 +80,14 @@ class AttachmentRepository implements AttachmentRepositoryInterface } /** - * @param int $id - * + * @param int $attachmentId + * @deprecated * @return Attachment */ - public function findWithoutUser(int $id): Attachment + public function findWithoutUser(int $attachmentId): Attachment { - $attachment = Attachment::find($id); + $attachment = Attachment::find($attachmentId); if (null === $attachment) { return new Attachment; } diff --git a/app/Repositories/Attachment/AttachmentRepositoryInterface.php b/app/Repositories/Attachment/AttachmentRepositoryInterface.php index a0a0d44a72..2f25bf81a7 100644 --- a/app/Repositories/Attachment/AttachmentRepositoryInterface.php +++ b/app/Repositories/Attachment/AttachmentRepositoryInterface.php @@ -49,11 +49,11 @@ interface AttachmentRepositoryInterface public function exists(Attachment $attachment): bool; /** - * @param int $id - * + * @param int $attachmentId + * @deprecated * @return Attachment */ - public function findWithoutUser(int $id): Attachment; + public function findWithoutUser(int $attachmentId): Attachment; /** * @return Collection diff --git a/app/Repositories/Bill/BillRepository.php b/app/Repositories/Bill/BillRepository.php index d8861266a4..a855d305ab 100644 --- a/app/Repositories/Bill/BillRepository.php +++ b/app/Repositories/Bill/BillRepository.php @@ -136,21 +136,8 @@ class BillRepository implements BillRepositoryInterface */ public function getBillsForAccounts(Collection $accounts): Collection { - $fields = ['bills.id', - 'bills.created_at', - 'bills.updated_at', - 'bills.deleted_at', - 'bills.user_id', - 'bills.name', - 'bills.match', - 'bills.amount_min', - 'bills.amount_max', - 'bills.date', - 'bills.repeat_freq', - 'bills.skip', - 'bills.automatch', - 'bills.active', - 'bills.name_encrypted', + $fields = ['bills.id', 'bills.created_at', 'bills.updated_at', 'bills.deleted_at', 'bills.user_id', 'bills.name', 'bills.match', 'bills.amount_min', + 'bills.amount_max', 'bills.date', 'bills.repeat_freq', 'bills.skip', 'bills.automatch', 'bills.active', 'bills.name_encrypted', 'bills.match_encrypted',]; $ids = $accounts->pluck('id')->toArray(); $set = $this->user->bills() @@ -336,28 +323,22 @@ class BillRepository implements BillRepositoryInterface public function getPayDatesInRange(Bill $bill, Carbon $start, Carbon $end): Collection { $set = new Collection; - Log::debug(sprintf('Now at bill "%s" (%s)', $bill->name, $bill->repeat_freq)); - - // Start at 2016-10-01, see when we expect the bill to hit: $currentStart = clone $start; + Log::debug(sprintf('Now at bill "%s" (%s)', $bill->name, $bill->repeat_freq)); Log::debug(sprintf('First currentstart is %s', $currentStart->format('Y-m-d'))); while ($currentStart <= $end) { Log::debug(sprintf('Currentstart is now %s.', $currentStart->format('Y-m-d'))); $nextExpectedMatch = $this->nextDateMatch($bill, $currentStart); Log::debug(sprintf('Next Date match after %s is %s', $currentStart->format('Y-m-d'), $nextExpectedMatch->format('Y-m-d'))); - // If nextExpectedMatch is after end, we continue: - if ($nextExpectedMatch > $end) { + if ($nextExpectedMatch > $end) {// If nextExpectedMatch is after end, we continue Log::debug( sprintf('nextExpectedMatch %s is after %s, so we skip this bill now.', $nextExpectedMatch->format('Y-m-d'), $end->format('Y-m-d')) ); break; } - // add to set $set->push(clone $nextExpectedMatch); Log::debug(sprintf('Now %d dates in set.', $set->count())); - - // add day if necessary. $nextExpectedMatch->addDay(); Log::debug(sprintf('Currentstart (%s) has become %s.', $currentStart->format('Y-m-d'), $nextExpectedMatch->format('Y-m-d'))); diff --git a/app/Repositories/Budget/BudgetRepository.php b/app/Repositories/Budget/BudgetRepository.php index b48bb98157..f71ec844b3 100644 --- a/app/Repositories/Budget/BudgetRepository.php +++ b/app/Repositories/Budget/BudgetRepository.php @@ -85,6 +85,7 @@ class BudgetRepository implements BudgetRepositoryInterface /** * @return bool + * @SuppressWarnings(PHPMD.CyclomaticComplexity) // it's 5. */ public function cleanupBudgets(): bool { @@ -123,6 +124,8 @@ class BudgetRepository implements BudgetRepositoryInterface * @param Carbon $end * * @return array + * + * @SuppressWarnings(PHPMD.CyclomaticComplexity) */ public function collectBudgetInformation(Collection $budgets, Carbon $start, Carbon $end): array { @@ -138,7 +141,6 @@ class BudgetRepository implements BudgetRepositoryInterface $return[$budgetId] = [ 'spent' => $this->spentInPeriod(new Collection([$budget]), $accounts, $start, $end), 'budgeted' => '0', - 'currentRep' => false, ]; $budgetLimits = $this->getBudgetLimits($budget, $start, $end); $otherLimits = new Collection; @@ -244,12 +246,11 @@ class BudgetRepository implements BudgetRepositoryInterface * Will cache result. * * @param Budget $budget - * * @return Carbon */ - public function firstUseDate(Budget $budget): Carbon + public function firstUseDate(Budget $budget): ?Carbon { - $oldest = Carbon::create()->startOfYear(); + $oldest = null; $journal = $budget->transactionJournals()->orderBy('date', 'ASC')->first(); if (null !== $journal) { $oldest = $journal->date < $oldest ? $journal->date : $oldest; diff --git a/app/Repositories/Budget/BudgetRepositoryInterface.php b/app/Repositories/Budget/BudgetRepositoryInterface.php index 56a3ca82a6..d6df2f54c6 100644 --- a/app/Repositories/Budget/BudgetRepositoryInterface.php +++ b/app/Repositories/Budget/BudgetRepositoryInterface.php @@ -105,7 +105,7 @@ interface BudgetRepositoryInterface * * @return Carbon */ - public function firstUseDate(Budget $budget): Carbon; + public function firstUseDate(Budget $budget): ?Carbon; /** * @return Collection diff --git a/app/Repositories/ExportJob/ExportJobRepository.php b/app/Repositories/ExportJob/ExportJobRepository.php index 1745d1a14f..cb377a383b 100644 --- a/app/Repositories/ExportJob/ExportJobRepository.php +++ b/app/Repositories/ExportJob/ExportJobRepository.php @@ -81,6 +81,7 @@ class ExportJobRepository implements ExportJobRepositoryInterface /** * @return ExportJob + * @deprecated */ public function create(): ExportJob { @@ -120,6 +121,7 @@ class ExportJobRepository implements ExportJobRepositoryInterface /** * @param string $key + * * @deprecated * @return ExportJob */ diff --git a/app/Repositories/ExportJob/ExportJobRepositoryInterface.php b/app/Repositories/ExportJob/ExportJobRepositoryInterface.php index 21ea419de4..3a9bd5c4fd 100644 --- a/app/Repositories/ExportJob/ExportJobRepositoryInterface.php +++ b/app/Repositories/ExportJob/ExportJobRepositoryInterface.php @@ -45,6 +45,7 @@ interface ExportJobRepositoryInterface /** * @return ExportJob + * @deprecated */ public function create(): ExportJob; @@ -57,6 +58,7 @@ interface ExportJobRepositoryInterface /** * @param string $key + * * @deprecated * @return ExportJob */ diff --git a/app/Repositories/ImportJob/ImportJobRepository.php b/app/Repositories/ImportJob/ImportJobRepository.php index a722871f60..24b7703719 100644 --- a/app/Repositories/ImportJob/ImportJobRepository.php +++ b/app/Repositories/ImportJob/ImportJobRepository.php @@ -27,14 +27,11 @@ use FireflyIII\Exceptions\FireflyException; use FireflyIII\Models\Attachment; use FireflyIII\Models\ImportJob; use FireflyIII\Models\Tag; -use FireflyIII\Models\TransactionJournalMeta; -use FireflyIII\Repositories\User\UserRepositoryInterface; use FireflyIII\User; use Illuminate\Support\Collection; use Illuminate\Support\MessageBag; use Illuminate\Support\Str; use Log; -use SplFileObject; use Storage; use Symfony\Component\HttpFoundation\File\UploadedFile; @@ -118,6 +115,7 @@ class ImportJobRepository implements ImportJobRepositoryInterface * @param string $key * * @return ImportJob + * @deprecated */ public function findByKey(string $key): ImportJob { diff --git a/app/Repositories/ImportJob/ImportJobRepositoryInterface.php b/app/Repositories/ImportJob/ImportJobRepositoryInterface.php index 3e8e6a7de9..0789741fc5 100644 --- a/app/Repositories/ImportJob/ImportJobRepositoryInterface.php +++ b/app/Repositories/ImportJob/ImportJobRepositoryInterface.php @@ -56,6 +56,7 @@ interface ImportJobRepositoryInterface * @param string $key * * @return ImportJob + * @deprecated */ public function findByKey(string $key): ImportJob; diff --git a/app/Repositories/Recurring/RecurringRepository.php b/app/Repositories/Recurring/RecurringRepository.php index 3dd4db2028..d147cbd676 100644 --- a/app/Repositories/Recurring/RecurringRepository.php +++ b/app/Repositories/Recurring/RecurringRepository.php @@ -193,122 +193,34 @@ class RecurringRepository implements RecurringRepositoryInterface */ public function getOccurrencesInRange(RecurrenceRepetition $repetition, Carbon $start, Carbon $end): array { - $return = []; - $mutator = clone $start; + $occurrences = []; + $mutator = clone $start; $mutator->startOfDay(); - $skipMod = $repetition->repetition_skip + 1; - $attempts = 0; + $skipMod = $repetition->repetition_skip + 1; Log::debug(sprintf('Calculating occurrences for rep type "%s"', $repetition->repetition_type)); Log::debug(sprintf('Mutator is now: %s', $mutator->format('Y-m-d'))); - switch ($repetition->repetition_type) { - default: - throw new FireflyException( - sprintf('Cannot calculate occurrences for recurring transaction repetition type "%s"', $repetition->repetition_type) - ); - case 'daily': - Log::debug('Rep is daily. Start of loop.'); - while ($mutator <= $end) { - Log::debug(sprintf('Mutator is now: %s', $mutator->format('Y-m-d'))); - if (0 === $attempts % $skipMod) { - Log::debug(sprintf('Attempts modulo skipmod is zero, include %s', $mutator->format('Y-m-d'))); - $return[] = clone $mutator; - } - $mutator->addDay(); - $attempts++; - } - break; - case 'weekly': - Log::debug('Rep is weekly.'); - // monday = 1 - // sunday = 7 - $dayOfWeek = (int)$repetition->repetition_moment; - Log::debug(sprintf('DoW in repetition is %d, in mutator is %d', $dayOfWeek, $mutator->dayOfWeekIso)); - if ($mutator->dayOfWeekIso > $dayOfWeek) { - // day has already passed this week, add one week: - $mutator->addWeek(); - Log::debug(sprintf('Jump to next week, so mutator is now: %s', $mutator->format('Y-m-d'))); - } - // today is wednesday (3), expected is friday (5): add two days. - // today is friday (5), expected is monday (1), subtract four days. - Log::debug(sprintf('Mutator is now: %s', $mutator->format('Y-m-d'))); - $dayDifference = $dayOfWeek - $mutator->dayOfWeekIso; - $mutator->addDays($dayDifference); - Log::debug(sprintf('Mutator is now: %s', $mutator->format('Y-m-d'))); - while ($mutator <= $end) { - if (0 === $attempts % $skipMod && $start->lte($mutator) && $end->gte($mutator)) { - Log::debug('Date is in range of start+end, add to set.'); - $return[] = clone $mutator; - } - $attempts++; - $mutator->addWeek(); - Log::debug(sprintf('Mutator is now (end of loop): %s', $mutator->format('Y-m-d'))); - } - break; - case 'monthly': - $dayOfMonth = (int)$repetition->repetition_moment; - Log::debug(sprintf('Day of month in repetition is %d', $dayOfMonth)); - Log::debug(sprintf('Start is %s.', $start->format('Y-m-d'))); - Log::debug(sprintf('End is %s.', $end->format('Y-m-d'))); - if ($mutator->day > $dayOfMonth) { - Log::debug('Add a month.'); - // day has passed already, add a month. - $mutator->addMonth(); - } - Log::debug(sprintf('Start is now %s.', $mutator->format('Y-m-d'))); - Log::debug('Start loop.'); - while ($mutator < $end) { - Log::debug(sprintf('Mutator is now %s.', $mutator->format('Y-m-d'))); - $domCorrected = min($dayOfMonth, $mutator->daysInMonth); - Log::debug(sprintf('DoM corrected is %d', $domCorrected)); - $mutator->day = $domCorrected; - Log::debug(sprintf('Mutator is now %s.', $mutator->format('Y-m-d'))); - Log::debug(sprintf('$attempts %% $skipMod === 0 is %s', var_export(0 === $attempts % $skipMod, true))); - Log::debug(sprintf('$start->lte($mutator) is %s', var_export($start->lte($mutator), true))); - Log::debug(sprintf('$end->gte($mutator) is %s', var_export($end->gte($mutator), true))); - if (0 === $attempts % $skipMod && $start->lte($mutator) && $end->gte($mutator)) { - Log::debug(sprintf('ADD %s to return!', $mutator->format('Y-m-d'))); - $return[] = clone $mutator; - } - $attempts++; - $mutator->endOfMonth()->startOfDay()->addDay(); - } - break; - case 'ndom': - $mutator->startOfMonth(); - // this feels a bit like a cop out but why reinvent the wheel? - $counters = [1 => 'first', 2 => 'second', 3 => 'third', 4 => 'fourth', 5 => 'fifth',]; - $daysOfWeek = [1 => 'Monday', 2 => 'Tuesday', 3 => 'Wednesday', 4 => 'Thursday', 5 => 'Friday', 6 => 'Saturday', 7 => 'Sunday',]; - $parts = explode(',', $repetition->repetition_moment); - while ($mutator <= $end) { - $string = sprintf('%s %s of %s %s', $counters[$parts[0]], $daysOfWeek[$parts[1]], $mutator->format('F'), $mutator->format('Y')); - $newCarbon = new Carbon($string); - $return[] = clone $newCarbon; - $mutator->endOfMonth()->addDay(); - } - break; - case 'yearly': - $date = new Carbon($repetition->repetition_moment); - $date->year = $mutator->year; - if ($mutator > $date) { - $date->addYear(); - } - - // is $date between $start and $end? - $obj = clone $date; - $count = 0; - while ($obj <= $end && $obj >= $mutator && $count < 10) { - - $return[] = clone $obj; - $obj->addYears(1); - $count++; - } - break; + if ('daily' === $repetition->repetition_type) { + $occurrences = $this->getDailyInRange($mutator, $end, $skipMod); + } + if ('weekly' === $repetition->repetition_type) { + $occurrences = $this->getWeeklyInRange($mutator, $end, $skipMod, $repetition->repetition_moment); + } + if ('monthly' === $repetition->repetition_type) { + $occurrences = $this->getMonthlyInRange($mutator, $end, $skipMod, $repetition->repetition_moment); + } + if ('ndom' === $repetition->repetition_type) { + $occurrences = $this->getNdomInRange($mutator, $end, $skipMod, $repetition->repetition_moment); + } + if ('yearly' === $repetition->repetition_type) { + $occurrences = $this->getYearlyInRange($mutator, $end, $skipMod, $repetition->repetition_moment); } - // filter out all the weekend days: - $return = $this->filterWeekends($repetition, $return); - return $return; + + // filter out all the weekend days: + $occurrences = $this->filterWeekends($repetition, $occurrences); + + return $occurrences; } /** @@ -399,112 +311,31 @@ class RecurringRepository implements RecurringRepositoryInterface * @param int $count * * @return array - * @throws FireflyException */ public function getXOccurrences(RecurrenceRepetition $repetition, Carbon $date, int $count): array { - $return = []; - $mutator = clone $date; - $skipMod = $repetition->repetition_skip + 1; - $total = 0; - $attempts = 0; - switch ($repetition->repetition_type) { - default: - throw new FireflyException( - sprintf('Cannot calculate occurrences for recurring transaction repetition type "%s"', $repetition->repetition_type) - ); - case 'daily': - while ($total < $count) { - $mutator->addDay(); - if (0 === $attempts % $skipMod) { - $return[] = clone $mutator; - $total++; - } - $attempts++; - } - break; - case 'weekly': - // monday = 1 - // sunday = 7 - $mutator->addDay(); // always assume today has passed. - $dayOfWeek = (int)$repetition->repetition_moment; - if ($mutator->dayOfWeekIso > $dayOfWeek) { - // day has already passed this week, add one week: - $mutator->addWeek(); - } - // today is wednesday (3), expected is friday (5): add two days. - // today is friday (5), expected is monday (1), subtract four days. - $dayDifference = $dayOfWeek - $mutator->dayOfWeekIso; - $mutator->addDays($dayDifference); - - while ($total < $count) { - if (0 === $attempts % $skipMod) { - $return[] = clone $mutator; - $total++; - } - $attempts++; - $mutator->addWeek(); - } - break; - case 'monthly': - $mutator->addDay(); // always assume today has passed. - $dayOfMonth = (int)$repetition->repetition_moment; - if ($mutator->day > $dayOfMonth) { - // day has passed already, add a month. - $mutator->addMonth(); - } - - while ($total < $count) { - $domCorrected = min($dayOfMonth, $mutator->daysInMonth); - $mutator->day = $domCorrected; - if (0 === $attempts % $skipMod) { - $return[] = clone $mutator; - $total++; - } - $attempts++; - $mutator->endOfMonth()->addDay(); - } - break; - case 'ndom': - $mutator->addDay(); // always assume today has passed. - $mutator->startOfMonth(); - // this feels a bit like a cop out but why reinvent the wheel? - $counters = [1 => 'first', 2 => 'second', 3 => 'third', 4 => 'fourth', 5 => 'fifth',]; - $daysOfWeek = [1 => 'Monday', 2 => 'Tuesday', 3 => 'Wednesday', 4 => 'Thursday', 5 => 'Friday', 6 => 'Saturday', 7 => 'Sunday',]; - $parts = explode(',', $repetition->repetition_moment); - - while ($total < $count) { - $string = sprintf('%s %s of %s %s', $counters[$parts[0]], $daysOfWeek[$parts[1]], $mutator->format('F'), $mutator->format('Y')); - $newCarbon = new Carbon($string); - if (0 === $attempts % $skipMod) { - $return[] = clone $newCarbon; - $total++; - } - $attempts++; - $mutator->endOfMonth()->addDay(); - } - break; - case 'yearly': - $date = new Carbon($repetition->repetition_moment); - $date->year = $mutator->year; - if ($mutator > $date) { - $date->addYear(); - } - $obj = clone $date; - while ($total < $count) { - if (0 === $attempts % $skipMod) { - $return[] = clone $obj; - $total++; - } - $obj->addYears(1); - $attempts++; - } - break; + $skipMod = $repetition->repetition_skip + 1; + $occurrences = []; + if ('daily' === $repetition->repetition_type) { + $occurrences = $this->getXDailyOccurrences($date, $count, $skipMod); + } + if ('weekly' === $repetition->repetition_type) { + $occurrences = $this->getXWeeklyOccurrences($date, $count, $skipMod, $repetition->repetition_moment); + } + if ('monthly' === $repetition->repetition_type) { + $occurrences = $this->getXMonthlyOccurrences($date, $count, $skipMod, $repetition->repetition_moment); + } + if ('ndom' === $repetition->repetition_type) { + $occurrences = $this->getXNDomOccurrences($date, $count, $skipMod, $repetition->repetition_moment); + } + if ('yearly' === $repetition->repetition_type) { + $occurrences = $this->getXYearlyOccurrences($date, $count, $skipMod, $repetition->repetition_moment); } - // filter out all the weekend days: - $return = $this->filterWeekends($repetition, $return); - return $return; + // filter out all the weekend days: + $occurrences = $this->filterWeekends($repetition, $occurrences); + + return $occurrences; } /** @@ -545,8 +376,7 @@ class RecurringRepository implements RecurringRepositoryInterface break; case 'yearly': // - $today = new Carbon; - $today->endOfYear(); + $today = Carbon::create()->endOfYear(); $repDate = Carbon::createFromFormat('Y-m-d', $repetition->repetition_moment); $diffInYears = $today->diffInYears($repDate); $repDate->addYears($diffInYears); // technically not necessary. @@ -658,4 +488,378 @@ class RecurringRepository implements RecurringRepositoryInterface return $return; } + + /** + * Get the number of daily occurrences for a recurring transaction until date $end is reached. Will skip every $skipMod-1 occurrences. + * + * @param Carbon $start + * @param Carbon $end + * @param int $skipMod + * + * @return array + */ + private function getDailyInRange(Carbon $start, Carbon $end, int $skipMod): array + { + $return = []; + $attempts = 0; + Log::debug('Rep is daily. Start of loop.'); + while ($start <= $end) { + Log::debug(sprintf('Mutator is now: %s', $start->format('Y-m-d'))); + if (0 === $attempts % $skipMod) { + Log::debug(sprintf('Attempts modulo skipmod is zero, include %s', $start->format('Y-m-d'))); + $return[] = clone $start; + } + $start->addDay(); + $attempts++; + } + + return $return; + } + + /** @noinspection MoreThanThreeArgumentsInspection */ + /** + * Get the number of daily occurrences for a recurring transaction until date $end is reached. Will skip every $skipMod-1 occurrences. + * + * @param Carbon $start + * @param Carbon $end + * @param int $skipMod + * @param string $moment + * + * @return array + */ + private function getMonthlyInRange(Carbon $start, Carbon $end, int $skipMod, string $moment): array + { + $return = []; + $attempts = 0; + $dayOfMonth = (int)$moment; + Log::debug(sprintf('Day of month in repetition is %d', $dayOfMonth)); + Log::debug(sprintf('Start is %s.', $start->format('Y-m-d'))); + Log::debug(sprintf('End is %s.', $end->format('Y-m-d'))); + if ($start->day > $dayOfMonth) { + Log::debug('Add a month.'); + // day has passed already, add a month. + $start->addMonth(); + } + Log::debug(sprintf('Start is now %s.', $start->format('Y-m-d'))); + Log::debug('Start loop.'); + while ($start < $end) { + Log::debug(sprintf('Mutator is now %s.', $start->format('Y-m-d'))); + $domCorrected = min($dayOfMonth, $start->daysInMonth); + Log::debug(sprintf('DoM corrected is %d', $domCorrected)); + $start->day = $domCorrected; + Log::debug(sprintf('Mutator is now %s.', $start->format('Y-m-d'))); + Log::debug(sprintf('$attempts %% $skipMod === 0 is %s', var_export(0 === $attempts % $skipMod, true))); + Log::debug(sprintf('$start->lte($mutator) is %s', var_export($start->lte($start), true))); + Log::debug(sprintf('$end->gte($mutator) is %s', var_export($end->gte($start), true))); + if (0 === $attempts % $skipMod && $start->lte($start) && $end->gte($start)) { + Log::debug(sprintf('ADD %s to return!', $start->format('Y-m-d'))); + $return[] = clone $start; + } + $attempts++; + $start->endOfMonth()->startOfDay()->addDay(); + } + + return $return; + } + + /** @noinspection MoreThanThreeArgumentsInspection */ + /** + * Get the number of daily occurrences for a recurring transaction until date $end is reached. Will skip every $skipMod-1 occurrences. + * + * @param Carbon $start + * @param Carbon $end + * @param int $skipMod + * @param string $moment + * + * @return array + */ + private function getNdomInRange(Carbon $start, Carbon $end, int $skipMod, string $moment): array + { + $return = []; + $attempts = 0; + $start->startOfMonth(); + // this feels a bit like a cop out but why reinvent the wheel? + $counters = [1 => 'first', 2 => 'second', 3 => 'third', 4 => 'fourth', 5 => 'fifth',]; + $daysOfWeek = [1 => 'Monday', 2 => 'Tuesday', 3 => 'Wednesday', 4 => 'Thursday', 5 => 'Friday', 6 => 'Saturday', 7 => 'Sunday',]; + $parts = explode(',', $moment); + while ($start <= $end) { + $string = sprintf('%s %s of %s %s', $counters[$parts[0]], $daysOfWeek[$parts[1]], $start->format('F'), $start->format('Y')); + $newCarbon = new Carbon($string); + if (0 === $attempts % $skipMod) { + $return[] = clone $newCarbon; + } + $attempts++; + $start->endOfMonth()->addDay(); + } + + return $return; + } + + /** @noinspection MoreThanThreeArgumentsInspection */ + /** + * Get the number of daily occurrences for a recurring transaction until date $end is reached. Will skip every $skipMod-1 occurrences. + * + * @param Carbon $start + * @param Carbon $end + * @param int $skipMod + * @param string $moment + * + * @return array + */ + private function getWeeklyInRange(Carbon $start, Carbon $end, int $skipMod, string $moment): array + { + $return = []; + $attempts = 0; + Log::debug('Rep is weekly.'); + // monday = 1 + // sunday = 7 + $dayOfWeek = (int)$moment; + Log::debug(sprintf('DoW in repetition is %d, in mutator is %d', $dayOfWeek, $start->dayOfWeekIso)); + if ($start->dayOfWeekIso > $dayOfWeek) { + // day has already passed this week, add one week: + $start->addWeek(); + Log::debug(sprintf('Jump to next week, so mutator is now: %s', $start->format('Y-m-d'))); + } + // today is wednesday (3), expected is friday (5): add two days. + // today is friday (5), expected is monday (1), subtract four days. + Log::debug(sprintf('Mutator is now: %s', $start->format('Y-m-d'))); + $dayDifference = $dayOfWeek - $start->dayOfWeekIso; + $start->addDays($dayDifference); + Log::debug(sprintf('Mutator is now: %s', $start->format('Y-m-d'))); + while ($start <= $end) { + if (0 === $attempts % $skipMod && $start->lte($start) && $end->gte($start)) { + Log::debug('Date is in range of start+end, add to set.'); + $return[] = clone $start; + } + $attempts++; + $start->addWeek(); + Log::debug(sprintf('Mutator is now (end of loop): %s', $start->format('Y-m-d'))); + } + + return $return; + } + + /** + * Calculates the number of daily occurrences for a recurring transaction, starting at the date, until $count is reached. It will skip + * over $skipMod -1 recurrences. + * + * @param Carbon $date + * @param int $count + * @param int $skipMod + * + * @return array + */ + private function getXDailyOccurrences(Carbon $date, int $count, int $skipMod): array + { + $return = []; + $mutator = clone $date; + $total = 0; + $attempts = 0; + while ($total < $count) { + $mutator->addDay(); + if (0 === $attempts % $skipMod) { + $return[] = clone $mutator; + $total++; + } + $attempts++; + } + + return $return; + } + + /** @noinspection MoreThanThreeArgumentsInspection */ + /** + * Calculates the number of monthly occurrences for a recurring transaction, starting at the date, until $count is reached. It will skip + * over $skipMod -1 recurrences. + * + * @param Carbon $date + * @param int $count + * @param int $skipMod + * @param string $moment + * + * @return array + */ + private function getXMonthlyOccurrences(Carbon $date, int $count, int $skipMod, string $moment): array + { + $return = []; + $mutator = clone $date; + $total = 0; + $attempts = 0; + $mutator->addDay(); // always assume today has passed. + $dayOfMonth = (int)$moment; + if ($mutator->day > $dayOfMonth) { + // day has passed already, add a month. + $mutator->addMonth(); + } + + while ($total < $count) { + $domCorrected = min($dayOfMonth, $mutator->daysInMonth); + $mutator->day = $domCorrected; + if (0 === $attempts % $skipMod) { + $return[] = clone $mutator; + $total++; + } + $attempts++; + $mutator->endOfMonth()->addDay(); + } + + return $return; + } + + /** @noinspection MoreThanThreeArgumentsInspection */ + /** + * Calculates the number of NDOM occurrences for a recurring transaction, starting at the date, until $count is reached. It will skip + * over $skipMod -1 recurrences. + * + * @param Carbon $date + * @param int $count + * @param int $skipMod + * @param string $moment + * + * @return array + */ + private function getXNDomOccurrences(Carbon $date, int $count, int $skipMod, string $moment): array + { + $return = []; + $total = 0; + $attempts = 0; + $mutator = clone $date; + $mutator->addDay(); // always assume today has passed. + $mutator->startOfMonth(); + // this feels a bit like a cop out but why reinvent the wheel? + $counters = [1 => 'first', 2 => 'second', 3 => 'third', 4 => 'fourth', 5 => 'fifth',]; + $daysOfWeek = [1 => 'Monday', 2 => 'Tuesday', 3 => 'Wednesday', 4 => 'Thursday', 5 => 'Friday', 6 => 'Saturday', 7 => 'Sunday',]; + $parts = explode(',', $moment); + + while ($total < $count) { + $string = sprintf('%s %s of %s %s', $counters[$parts[0]], $daysOfWeek[$parts[1]], $mutator->format('F'), $mutator->format('Y')); + $newCarbon = new Carbon($string); + if (0 === $attempts % $skipMod) { + $return[] = clone $newCarbon; + $total++; + } + $attempts++; + $mutator->endOfMonth()->addDay(); + } + + return $return; + } + + /** @noinspection MoreThanThreeArgumentsInspection */ + /** + * Calculates the number of weekly occurrences for a recurring transaction, starting at the date, until $count is reached. It will skip + * over $skipMod -1 recurrences. + * + * @param Carbon $date + * @param int $count + * @param int $skipMod + * @param string $moment + * + * @return array + */ + private function getXWeeklyOccurrences(Carbon $date, int $count, int $skipMod, string $moment): array + { + $return = []; + $total = 0; + $attempts = 0; + $mutator = clone $date; + // monday = 1 + // sunday = 7 + $mutator->addDay(); // always assume today has passed. + $dayOfWeek = (int)$moment; + if ($mutator->dayOfWeekIso > $dayOfWeek) { + // day has already passed this week, add one week: + $mutator->addWeek(); + } + // today is wednesday (3), expected is friday (5): add two days. + // today is friday (5), expected is monday (1), subtract four days. + $dayDifference = $dayOfWeek - $mutator->dayOfWeekIso; + $mutator->addDays($dayDifference); + + while ($total < $count) { + if (0 === $attempts % $skipMod) { + $return[] = clone $mutator; + $total++; + } + $attempts++; + $mutator->addWeek(); + } + + return $return; + } + + /** @noinspection MoreThanThreeArgumentsInspection */ + /** + * Calculates the number of yearly occurrences for a recurring transaction, starting at the date, until $count is reached. It will skip + * over $skipMod -1 recurrences. + * + * @param Carbon $date + * @param int $count + * @param int $skipMod + * @param string $moment + * + * @return array + */ + private function getXYearlyOccurrences(Carbon $date, int $count, int $skipMod, string $moment): array + { + $return = []; + $mutator = clone $date; + $total = 0; + $attempts = 0; + $date = new Carbon($moment); + $date->year = $mutator->year; + if ($mutator > $date) { + $date->addYear(); + } + $obj = clone $date; + while ($total < $count) { + if (0 === $attempts % $skipMod) { + $return[] = clone $obj; + $total++; + } + $obj->addYears(1); + $attempts++; + } + + return $return; + + } + + /** @noinspection MoreThanThreeArgumentsInspection */ + /** + * Get the number of daily occurrences for a recurring transaction until date $end is reached. Will skip every $skipMod-1 occurrences. + * + * @param Carbon $start + * @param Carbon $end + * @param int $skipMod + * @param string $moment + * + * @return array + */ + private function getYearlyInRange(Carbon $start, Carbon $end, int $skipMod, string $moment): array + { + $attempts = 0; + $date = new Carbon($moment); + $date->year = $start->year; + $return = []; + if ($start > $date) { + $date->addYear(); + + } + + // is $date between $start and $end? + $obj = clone $date; + $count = 0; + while ($obj <= $end && $obj >= $start && $count < 10) { + if (0 === $attempts % $skipMod) { + $return[] = clone $obj; + } + $obj->addYears(1); + $count++; + $attempts++; + } + + return $return; + + } } diff --git a/app/Repositories/Tag/TagRepository.php b/app/Repositories/Tag/TagRepository.php index d029ca559c..83787ab59c 100644 --- a/app/Repositories/Tag/TagRepository.php +++ b/app/Repositories/Tag/TagRepository.php @@ -27,7 +27,6 @@ use DB; use FireflyIII\Helpers\Collector\JournalCollectorInterface; use FireflyIII\Helpers\Filter\InternalTransferFilter; use FireflyIII\Models\Tag; -use FireflyIII\Models\TransactionJournal; use FireflyIII\Models\TransactionType; use FireflyIII\User; use Illuminate\Database\Eloquent\Builder; @@ -101,6 +100,7 @@ class TagRepository implements TagRepositoryInterface * @param string $tag * * @return Tag + * @deprecated */ public function findByTag(string $tag): Tag { @@ -129,6 +129,7 @@ class TagRepository implements TagRepositoryInterface * @param Tag $tag * * @return Carbon + * @deprecated */ public function firstUseDate(Tag $tag): Carbon { @@ -160,6 +161,7 @@ class TagRepository implements TagRepositoryInterface * @param Tag $tag * * @return Carbon + * @deprecated */ public function lastUseDate(Tag $tag): Carbon { @@ -306,9 +308,7 @@ class TagRepository implements TagRepositoryInterface } if (null !== $year) { Log::debug(sprintf('Get tags with year %s.', $year)); - $start = $year . '-01-01 00:00:00'; - $end = $year . '-12-31 23:59:59'; - $tagQuery->where('tags.date', '>=', $start)->where('tags.date', '<=', $end); + $tagQuery->where('tags.date', '>=', $year . '-01-01 00:00:00')->where('tags.date', '<=', $year . '-12-31 23:59:59'); } $result = $tagQuery->get(['tags.id', 'tags.tag', DB::raw('SUM(transactions.amount) as amount_sum')]); diff --git a/app/Repositories/Tag/TagRepositoryInterface.php b/app/Repositories/Tag/TagRepositoryInterface.php index 07fd40f2e8..15e30f9517 100644 --- a/app/Repositories/Tag/TagRepositoryInterface.php +++ b/app/Repositories/Tag/TagRepositoryInterface.php @@ -24,7 +24,6 @@ namespace FireflyIII\Repositories\Tag; use Carbon\Carbon; use FireflyIII\Models\Tag; -use FireflyIII\Models\TransactionJournal; use FireflyIII\User; use Illuminate\Support\Collection; @@ -68,6 +67,7 @@ interface TagRepositoryInterface * @param string $tag * * @return Tag + * @deprecated */ public function findByTag(string $tag): Tag; @@ -82,6 +82,7 @@ interface TagRepositoryInterface * @param Tag $tag * * @return Carbon + * @deprecated */ public function firstUseDate(Tag $tag): Carbon; @@ -96,6 +97,7 @@ interface TagRepositoryInterface * @param Tag $tag * * @return Carbon + * @deprecated */ public function lastUseDate(Tag $tag): Carbon; diff --git a/app/Support/ExpandedForm.php b/app/Support/ExpandedForm.php index de66d82467..340c78daa5 100644 --- a/app/Support/ExpandedForm.php +++ b/app/Support/ExpandedForm.php @@ -49,12 +49,14 @@ class ExpandedForm { /** * @param string $name - * @param null $options + * @param mixed $value + * @param array $options * * @return string */ - public function activeAssetAccountList(string $name, $value = null, array $options = []): string + public function activeAssetAccountList(string $name, $value = null, array $options = null): string { + $options = $options ?? []; // make repositories /** @var AccountRepositoryInterface $repository */ $repository = app(AccountRepositoryInterface::class); @@ -87,26 +89,28 @@ class ExpandedForm /** * @param string $name - * @param null $value + * @param mixed $value * @param array $options * * @return string * @throws \FireflyIII\Exceptions\FireflyException */ - public function amount(string $name, $value = null, array $options = []): string + public function amount(string $name, $value = null, array $options = null): string { return $this->currencyField($name, 'amount', $value, $options); } /** * @param string $name - * @param null $value + * @param mixed $value * @param array $options * * @return string + * @throws \Throwable */ - public function amountNoCurrency(string $name, $value = null, array $options = []): string + public function amountNoCurrency(string $name, $value = null, array $options = null): string { + $options = $options ?? []; $label = $this->label($name, $options); $options = $this->expandOptionArray($name, $label, $options); $classes = $this->getHolderClasses($name); @@ -126,24 +130,25 @@ class ExpandedForm /** * @param string $name - * @param null $value + * @param mixed $value * @param array $options * * @return string * @throws \FireflyIII\Exceptions\FireflyException */ - public function amountSmall(string $name, $value = null, array $options = []): string + public function amountSmall(string $name, $value = null, array $options = null): string { return $this->currencyField($name, 'amount-small', $value, $options); } /** * @param string $name - * @param null $options + * @param array $options * * @return string + * @throws \Throwable */ - public function assetAccountCheckList(string $name, $options = null): string + public function assetAccountCheckList(string $name, array $options = null): string { $options = $options ?? []; $label = $this->label($name, $options); @@ -175,13 +180,14 @@ class ExpandedForm /** * @param string $name - * @param null $value + * @param mixed $value * @param array $options * * @return string */ - public function assetAccountList(string $name, $value = null, array $options = []): string + public function assetAccountList(string $name, $value = null, array $options = null): string { + $options = $options ?? []; // make repositories /** @var AccountRepositoryInterface $repository */ $repository = app(AccountRepositoryInterface::class); @@ -195,9 +201,9 @@ class ExpandedForm /** @var Account $account */ foreach ($assetAccounts as $account) { $balance = app('steam')->balance($account, new Carbon); - $currencyId = (int)$repository->getMetaValue($account,'currency_id'); + $currencyId = (int)$repository->getMetaValue($account, 'currency_id'); $currency = $currencyRepos->findNull($currencyId); - $role = $repository->getMetaValue($account,'accountRole'); + $role = $repository->getMetaValue($account, 'accountRole'); if (0 === \strlen($role)) { $role = 'no_account_type'; // @codeCoverageIgnore } @@ -215,27 +221,31 @@ class ExpandedForm /** * @param string $name - * @param null $value + * @param mixed $value * @param array $options * * @return string * @throws \FireflyIII\Exceptions\FireflyException */ - public function balance(string $name, $value = null, array $options = []): string + public function balance(string $name, $value = null, array $options = null): string { return $this->currencyField($name, 'balance', $value, $options); } + /** @noinspection MoreThanThreeArgumentsInspection */ /** * @param string $name * @param int $value - * @param null $checked + * @param mixed $checked * @param array $options * * @return string + * @throws \Throwable */ - public function checkbox(string $name, $value = 1, $checked = null, $options = []): string + public function checkbox(string $name, int $value = null, $checked = null, array $options = null): string { + $options = $options ?? []; + $value = $value ?? 1; $options['checked'] = true === $checked ? true : false; if (Session::has('preFilled')) { @@ -257,13 +267,14 @@ class ExpandedForm /** * @param string $name - * @param null $value + * @param mixed $value * @param array $options * * @return string */ - public function currencyList(string $name, $value = null, array $options = []): string + public function currencyList(string $name, $value = null, array $options = null): string { + $options = $options ?? []; /** @var CurrencyRepositoryInterface $currencyRepos */ $currencyRepos = app(CurrencyRepositoryInterface::class); @@ -274,20 +285,20 @@ class ExpandedForm foreach ($list as $currency) { $array[$currency->id] = $currency->name . ' (' . $currency->symbol . ')'; } - $res = $this->select($name, $array, $value, $options); - return $res; + return $this->select($name, $array, $value, $options); } /** * @param string $name - * @param null $value + * @param mixed $value * @param array $options * * @return string */ - public function currencyListEmpty(string $name, $value = null, array $options = []): string + public function currencyListEmpty(string $name, $value = null, array $options = null): string { + $options = $options ?? []; /** @var CurrencyRepositoryInterface $currencyRepos */ $currencyRepos = app(CurrencyRepositoryInterface::class); @@ -307,13 +318,15 @@ class ExpandedForm /** * @param string $name - * @param null $value + * @param mixed $value * @param array $options * * @return string + * @throws \Throwable */ - public function date(string $name, $value = null, array $options = []): string + public function date(string $name, $value = null, array $options = null): string { + $options = $options ?? []; $label = $this->label($name, $options); $options = $this->expandOptionArray($name, $label, $options); $classes = $this->getHolderClasses($name); @@ -329,9 +342,11 @@ class ExpandedForm * @param array $options * * @return string + * @throws \Throwable */ - public function file(string $name, array $options = []): string + public function file(string $name, array $options = null): string { + $options = $options ?? []; $label = $this->label($name, $options); $options = $this->expandOptionArray($name, $label, $options); $classes = $this->getHolderClasses($name); @@ -342,13 +357,15 @@ class ExpandedForm /** * @param string $name - * @param null $value + * @param mixed $value * @param array $options * * @return string + * @throws \Throwable */ - public function integer(string $name, $value = null, array $options = []): string + public function integer(string $name, $value = null, array $options = null): string { + $options = $options ?? []; $label = $this->label($name, $options); $options = $this->expandOptionArray($name, $label, $options); $classes = $this->getHolderClasses($name); @@ -361,13 +378,15 @@ class ExpandedForm /** * @param string $name - * @param null $value + * @param mixed $value * @param array $options * * @return string + * @throws \Throwable */ - public function location(string $name, $value = null, array $options = []): string + public function location(string $name, $value = null, array $options = null): string { + $options = $options ?? []; $label = $this->label($name, $options); $options = $this->expandOptionArray($name, $label, $options); $classes = $this->getHolderClasses($name); @@ -430,16 +449,21 @@ class ExpandedForm return $selectList; } + /** @noinspection MoreThanThreeArgumentsInspection */ + /** * @param string $name * @param array $list - * @param null $selected + * @param mixed $selected * @param array $options * * @return string + * @throws \Throwable */ - public function multiRadio(string $name, array $list = [], $selected = null, array $options = []): string + public function multiRadio(string $name, array $list = null, $selected = null, array $options = null): string { + $options = $options ?? []; + $list = $list ?? []; $label = $this->label($name, $options); $options = $this->expandOptionArray($name, $label, $options); $classes = $this->getHolderClasses($name); @@ -453,14 +477,16 @@ class ExpandedForm /** * @param string $name - * @param null $value + * @param mixed $value * @param array $options * * @return string * @throws \FireflyIII\Exceptions\FireflyException + * @throws \Throwable */ - public function nonSelectableAmount(string $name, $value = null, array $options = []): string + public function nonSelectableAmount(string $name, $value = null, array $options = null): string { + $options = $options ?? []; $label = $this->label($name, $options); $options = $this->expandOptionArray($name, $label, $options); $classes = $this->getHolderClasses($name); @@ -481,14 +507,16 @@ class ExpandedForm /** * @param string $name - * @param null $value + * @param mixed $value * @param array $options * * @return string * @throws \FireflyIII\Exceptions\FireflyException + * @throws \Throwable */ - public function nonSelectableBalance(string $name, $value = null, array $options = []): string + public function nonSelectableBalance(string $name, $value = null, array $options = null): string { + $options = $options ?? []; $label = $this->label($name, $options); $options = $this->expandOptionArray($name, $label, $options); $classes = $this->getHolderClasses($name); @@ -510,13 +538,15 @@ class ExpandedForm /** * @param string $name - * @param null $value + * @param mixed $value * @param array $options * * @return string + * @throws \Throwable */ - public function number(string $name, $value = null, array $options = []): string + public function number(string $name, $value = null, array $options = null): string { + $options = $options ?? []; $label = $this->label($name, $options); $options = $this->expandOptionArray($name, $label, $options); $classes = $this->getHolderClasses($name); @@ -534,12 +564,11 @@ class ExpandedForm * @param string $name * * @return string + * @throws \Throwable */ public function optionsList(string $type, string $name): string { - $html = view('form.options', compact('type', 'name'))->render(); - - return $html; + return view('form.options', compact('type', 'name'))->render(); } /** @@ -547,9 +576,11 @@ class ExpandedForm * @param array $options * * @return string + * @throws \Throwable */ public function password(string $name, array $options = null): string { + $options = $options ?? []; $label = $this->label($name, $options); $options = $this->expandOptionArray($name, $label, $options); @@ -561,7 +592,7 @@ class ExpandedForm /** * @param string $name - * @param null $value + * @param mixed $value * @param array $options * * @return string @@ -586,13 +617,14 @@ class ExpandedForm /** * @param string $name - * @param null $value + * @param mixed $value * @param array $options * * @return string */ - public function ruleGroupList(string $name, $value = null, array $options = []): string + public function ruleGroupList(string $name, $value = null, array $options = null): string { + $options = $options ?? []; /** @var RuleGroupRepositoryInterface $groupRepos */ $groupRepos = app(RuleGroupRepositoryInterface::class); @@ -609,12 +641,12 @@ class ExpandedForm /** * @param string $name - * @param null $value - * @param null $options + * @param mixed $value + * @param array $options * * @return \Illuminate\Support\HtmlString */ - public function ruleGroupListWithEmpty(string $name, $value = null, $options = null) + public function ruleGroupListWithEmpty(string $name, $value = null, array $options = null) { $options = $options ?? []; $options['class'] = 'form-control'; @@ -636,16 +668,20 @@ class ExpandedForm return Form::select($name, $array, $value, $options); } + /** @noinspection MoreThanThreeArgumentsInspection */ /** * @param string $name * @param array $list - * @param null $selected + * @param mixed $selected * @param array $options * * @return string + * @throws \Throwable */ - public function select(string $name, array $list = [], $selected = null, array $options = []): string + public function select(string $name, array $list = null, $selected = null, array $options = null): string { + $list = $list ?? []; + $options = $options ?? []; $label = $this->label($name, $options); $options = $this->expandOptionArray($name, $label, $options); $classes = $this->getHolderClasses($name); @@ -658,13 +694,15 @@ class ExpandedForm /** * @param string $name - * @param null $value + * @param mixed $value * @param array $options * * @return string + * @throws \Throwable */ - public function staticText(string $name, $value, array $options = []): string + public function staticText(string $name, $value, array $options = null): string { + $options = $options ?? []; $label = $this->label($name, $options); $options = $this->expandOptionArray($name, $label, $options); $classes = $this->getHolderClasses($name); @@ -675,13 +713,15 @@ class ExpandedForm /** * @param string $name - * @param null $value + * @param mixed $value * @param array $options * * @return string + * @throws \Throwable */ - public function tags(string $name, $value = null, array $options = []): string + public function tags(string $name, $value = null, array $options = null): string { + $options = $options ?? []; $label = $this->label($name, $options); $options = $this->expandOptionArray($name, $label, $options); $classes = $this->getHolderClasses($name); @@ -694,13 +734,15 @@ class ExpandedForm /** * @param string $name - * @param null $value + * @param mixed $value * @param array $options * * @return string + * @throws \Throwable */ - public function text(string $name, $value = null, array $options = []): string + public function text(string $name, $value = null, array $options = null): string { + $options = $options ?? []; $label = $this->label($name, $options); $options = $this->expandOptionArray($name, $label, $options); $classes = $this->getHolderClasses($name); @@ -712,13 +754,15 @@ class ExpandedForm /** * @param string $name - * @param null $value + * @param mixed $value * @param array $options * * @return string + * @throws \Throwable */ - public function textarea(string $name, $value = null, array $options = []): string + public function textarea(string $name, $value = null, array $options = null): string { + $options = $options ?? []; $label = $this->label($name, $options); $options = $this->expandOptionArray($name, $label, $options); $classes = $this->getHolderClasses($name); @@ -736,8 +780,9 @@ class ExpandedForm * * @return array */ - protected function expandOptionArray(string $name, $label, array $options): array + protected function expandOptionArray(string $name, $label, array $options = null): array { + $options = $options ?? []; $name = str_replace('[]', '', $name); $options['class'] = 'form-control'; $options['id'] = 'ffInput_' . $name; @@ -808,18 +853,21 @@ class ExpandedForm return (string)trans('form.' . $name); } + /** @noinspection MoreThanThreeArgumentsInspection */ /** * @param string $name * @param string $view - * @param null $value + * @param mixed $value * @param array $options * * @return string * * @throws \FireflyIII\Exceptions\FireflyException + * @throws \Throwable */ - private function currencyField(string $name, string $view, $value = null, array $options = []): string + private function currencyField(string $name, string $view, $value = null, array $options = null): string { + $options = $options ?? []; $label = $this->label($name, $options); $options = $this->expandOptionArray($name, $label, $options); $classes = $this->getHolderClasses($name); diff --git a/tests/Feature/Controllers/Transaction/SingleControllerTest.php b/tests/Feature/Controllers/Transaction/SingleControllerTest.php index 836ae75cf3..2fc9ef1c1f 100644 --- a/tests/Feature/Controllers/Transaction/SingleControllerTest.php +++ b/tests/Feature/Controllers/Transaction/SingleControllerTest.php @@ -87,10 +87,7 @@ class SingleControllerTest extends TestCase $journalRepos->shouldReceive('getMetaField')->andReturnNull(); - $note = new Note(); - $note->id = 5; - $note->text = 'I see you...'; - $journalRepos->shouldReceive('getNote')->andReturn($note)->once(); + $journalRepos->shouldReceive('getNoteText')->andReturn('I see you...')->once(); $this->be($this->user());