diff --git a/app/Http/Controllers/Recurring/DeleteController.php b/app/Http/Controllers/Recurring/DeleteController.php new file mode 100644 index 0000000000..d0d995822d --- /dev/null +++ b/app/Http/Controllers/Recurring/DeleteController.php @@ -0,0 +1,70 @@ +. + */ + +declare(strict_types=1); + +namespace FireflyIII\Http\Controllers\Recurring; + + +use FireflyIII\Http\Controllers\Controller; +use FireflyIII\Models\Recurrence; +use FireflyIII\Repositories\Recurring\RecurringRepositoryInterface; +use Illuminate\Http\Request; + +/** + * Class DeleteController + */ +class DeleteController extends Controller +{ + /** + * @param Recurrence $recurrence + * + * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View + */ + public function delete(Recurrence $recurrence) + { + $subTitle = trans('firefly.delete_recurring', ['title' => $recurrence->title]); + // put previous url in session + $this->rememberPreviousUri('recurrences.delete.uri'); + + // todo actual number. + $journalsCreated = 5; + + return view('recurring.delete', compact('recurrence', 'subTitle','journalsCreated')); + } + + /** + * @param RecurringRepositoryInterface $repository + * @param Request $request + * @param Recurrence $recurrence + * + * @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector + */ + public function destroy(RecurringRepositoryInterface $repository, Request $request, Recurrence $recurrence) + { + $repository->destroy($recurrence); + $request->session()->flash('success', (string)trans('firefly.' . 'recurrence_deleted', ['title' => $recurrence->title])); + app('preferences')->mark(); + + return redirect($this->getPreviousUri('recurrences.delete.uri')); + } + +} \ No newline at end of file diff --git a/app/Import/Routine/SpectreRoutine.php b/app/Import/Routine/SpectreRoutine.php index 83aea2664a..41d2a2a80e 100644 --- a/app/Import/Routine/SpectreRoutine.php +++ b/app/Import/Routine/SpectreRoutine.php @@ -101,6 +101,7 @@ class SpectreRoutine implements RoutineInterface $handler = app(StageImportDataHandler::class); $handler->setImportJob($this->importJob); $handler->run(); + // todo apply rules. $this->repository->setStatus($this->importJob, 'provider_finished'); $this->repository->setStage($this->importJob, 'final'); } diff --git a/app/Jobs/CreateRecurringTransactions.php b/app/Jobs/CreateRecurringTransactions.php index c40ca144b0..af2f210ebe 100644 --- a/app/Jobs/CreateRecurringTransactions.php +++ b/app/Jobs/CreateRecurringTransactions.php @@ -56,6 +56,8 @@ class CreateRecurringTransactions implements ShouldQueue $recurrences = $this->repository->getAll(); Log::debug(sprintf('Count of collection is %d', $recurrences->count())); + $result = []; + /** @var Collection $filtered */ $filtered = $recurrences->filter( function (Recurrence $recurrence) { @@ -66,12 +68,24 @@ class CreateRecurringTransactions implements ShouldQueue Log::debug(sprintf('Left after filtering is %d', $filtered->count())); /** @var Recurrence $recurrence */ foreach ($filtered as $recurrence) { + if (!isset($result[$recurrence->user_id])) { + $result[$recurrence->user_id] = new Collection; + } + $this->repository->setUser($recurrence->user); $this->journalRepository->setUser($recurrence->user); Log::debug(sprintf('Now at recurrence #%d', $recurrence->id)); - $this->handleRepetitions($recurrence); + $created = $this->handleRepetitions($recurrence); Log::debug(sprintf('Done with recurrence #%c', $recurrence->id)); + + $result[$recurrence->user_id] = $result[$recurrence->user_id]->merge($created); } + + // will now send email to users. + foreach($result as $userId => $journals) { + $this->sendReport($userId, $journals); + } + Log::debug('Done with handle()'); } @@ -160,10 +174,12 @@ class CreateRecurringTransactions implements ShouldQueue * @param Recurrence $recurrence * @param array $occurrences * + * @return Collection * @throws \FireflyIII\Exceptions\FireflyException */ - private function handleOccurrences(Recurrence $recurrence, array $occurrences): void + private function handleOccurrences(Recurrence $recurrence, array $occurrences): Collection { + $collection = new Collection; /** @var Carbon $date */ foreach ($occurrences as $date) { Log::debug(sprintf('Now at date %s.', $date->format('Y-m-d'))); @@ -195,21 +211,29 @@ class CreateRecurringTransactions implements ShouldQueue ]; $journal = $this->journalRepository->store($array); Log::info(sprintf('Created new journal #%d', $journal->id)); + // todo fire rules + $collection->push($journal); // update recurring thing: $recurrence->latest_date = $date; $recurrence->save(); } + + return $collection; } /** - * Separate method that will loop all repetitions and do something with it: + * Separate method that will loop all repetitions and do something with it. Will return + * all created transaction journals. * * @param Recurrence $recurrence * + * @return Collection + * * @throws \FireflyIII\Exceptions\FireflyException */ - private function handleRepetitions(Recurrence $recurrence): void + private function handleRepetitions(Recurrence $recurrence): Collection { + $collection = new Collection; /** @var RecurrenceRepetition $repetition */ foreach ($recurrence->recurrenceRepetitions as $repetition) { Log::debug( @@ -227,8 +251,11 @@ class CreateRecurringTransactions implements ShouldQueue ), $this->debugArray($occurrences) ); - $this->handleOccurrences($recurrence, $occurrences); + $result = $this->handleOccurrences($recurrence, $occurrences); + $collection = $collection->merge($result); } + + return $collection; } /** diff --git a/app/Repositories/Recurring/RecurringRepository.php b/app/Repositories/Recurring/RecurringRepository.php index 01aa7ca230..18418c9034 100644 --- a/app/Repositories/Recurring/RecurringRepository.php +++ b/app/Repositories/Recurring/RecurringRepository.php @@ -33,6 +33,7 @@ use FireflyIII\Models\RecurrenceMeta; use FireflyIII\Models\RecurrenceRepetition; use FireflyIII\Models\RecurrenceTransaction; use FireflyIII\Models\RecurrenceTransactionMeta; +use FireflyIII\Services\Internal\Destroy\RecurrenceDestroyService; use FireflyIII\Services\Internal\Update\RecurrenceUpdateService; use FireflyIII\User; use Illuminate\Support\Collection; @@ -47,6 +48,18 @@ class RecurringRepository implements RecurringRepositoryInterface /** @var User */ private $user; + /** + * Destroy a recurring transaction. + * + * @param Recurrence $recurrence + */ + public function destroy(Recurrence $recurrence): void + { + /** @var RecurrenceDestroyService $service */ + $service = app(RecurrenceDestroyService::class); + $service->destroy($recurrence); + } + /** * Returns all of the user's recurring transactions. * diff --git a/app/Repositories/Recurring/RecurringRepositoryInterface.php b/app/Repositories/Recurring/RecurringRepositoryInterface.php index 0f1776a085..6f6963e1b6 100644 --- a/app/Repositories/Recurring/RecurringRepositoryInterface.php +++ b/app/Repositories/Recurring/RecurringRepositoryInterface.php @@ -39,6 +39,13 @@ use Illuminate\Support\Collection; */ interface RecurringRepositoryInterface { + /** + * Destroy a recurring transaction. + * + * @param Recurrence $recurrence + */ + public function destroy(Recurrence $recurrence): void; + /** * Returns all of the user's recurring transactions. * @@ -48,19 +55,11 @@ interface RecurringRepositoryInterface /** * Get ALL recurring transactions. + * * @return Collection */ public function getAll(): Collection; - /** - * Get the category from a recurring transaction transaction. - * - * @param RecurrenceTransaction $recurrenceTransaction - * - * @return null|string - */ - public function getCategory(RecurrenceTransaction $recurrenceTransaction): ?string; - /** * Get the budget ID from a recurring transaction transaction. * @@ -70,6 +69,15 @@ interface RecurringRepositoryInterface */ public function getBudget(RecurrenceTransaction $recurrenceTransaction): ?int; + /** + * Get the category from a recurring transaction transaction. + * + * @param RecurrenceTransaction $recurrenceTransaction + * + * @return null|string + */ + public function getCategory(RecurrenceTransaction $recurrenceTransaction): ?string; + /** * Get the notes. * diff --git a/app/Services/Internal/Destroy/RecurrenceDestroyService.php b/app/Services/Internal/Destroy/RecurrenceDestroyService.php new file mode 100644 index 0000000000..968f249235 --- /dev/null +++ b/app/Services/Internal/Destroy/RecurrenceDestroyService.php @@ -0,0 +1,48 @@ +. + */ + +declare(strict_types=1); + +namespace FireflyIII\Services\Internal\Destroy; + +use Exception; +use FireflyIII\Models\Recurrence; +use Log; + +/** + * @codeCoverageIgnore + * Class RecurrenceDestroyService + */ +class RecurrenceDestroyService +{ + /** + * @param Recurrence $recurrence + */ + public function destroy(Recurrence $recurrence): void + { + try { + $recurrence->delete(); + } catch (Exception $e) { // @codeCoverageIgnore + Log::error(sprintf('Could not delete recurrence: %s', $e->getMessage())); // @codeCoverageIgnore + } + } + +} diff --git a/resources/lang/en_US/firefly.php b/resources/lang/en_US/firefly.php index f64d00cd18..e3513773a9 100644 --- a/resources/lang/en_US/firefly.php +++ b/resources/lang/en_US/firefly.php @@ -1260,4 +1260,6 @@ return [ 'update_recurrence' => 'Update recurring transaction', 'updated_recurrence' => 'Updated recurring transaction ":title"', 'recurrence_is_inactive' => 'This recurring transaction is not active and will not generate new transactions.', + 'delete_recurring' => 'Delete recurring transaction ":title"', + 'recurrence_deleted' => 'Recurring transaction ":title" deleted', ]; diff --git a/resources/lang/en_US/form.php b/resources/lang/en_US/form.php index 9445534e2a..a54447545a 100644 --- a/resources/lang/en_US/form.php +++ b/resources/lang/en_US/form.php @@ -94,90 +94,93 @@ return [ 'convert_Deposit' => 'Convert deposit', 'convert_Transfer' => 'Convert transfer', - 'amount' => 'Amount', - 'foreign_amount' => 'Foreign amount', - 'existing_attachments' => 'Existing attachments', - 'date' => 'Date', - 'interest_date' => 'Interest date', - 'book_date' => 'Book date', - 'process_date' => 'Processing date', - 'category' => 'Category', - 'tags' => 'Tags', - 'deletePermanently' => 'Delete permanently', - 'cancel' => 'Cancel', - 'targetdate' => 'Target date', - 'startdate' => 'Start date', - 'tag' => 'Tag', - 'under' => 'Under', - 'symbol' => 'Symbol', - 'code' => 'Code', - 'iban' => 'IBAN', - 'accountNumber' => 'Account number', - 'creditCardNumber' => 'Credit card number', - 'has_headers' => 'Headers', - 'date_format' => 'Date format', - 'specifix' => 'Bank- or file specific fixes', - 'attachments[]' => 'Attachments', - 'store_new_withdrawal' => 'Store new withdrawal', - 'store_new_deposit' => 'Store new deposit', - 'store_new_transfer' => 'Store new transfer', - 'add_new_withdrawal' => 'Add a new withdrawal', - 'add_new_deposit' => 'Add a new deposit', - 'add_new_transfer' => 'Add a new transfer', - 'title' => 'Title', - 'notes' => 'Notes', - 'filename' => 'File name', - 'mime' => 'Mime type', - 'size' => 'Size', - 'trigger' => 'Trigger', - 'stop_processing' => 'Stop processing', - 'start_date' => 'Start of range', - 'end_date' => 'End of range', - 'export_start_range' => 'Start of export range', - 'export_end_range' => 'End of export range', - 'export_format' => 'File format', - 'include_attachments' => 'Include uploaded attachments', - 'include_old_uploads' => 'Include imported data', - 'accounts' => 'Export transactions from these accounts', - 'delete_account' => 'Delete account ":name"', - 'delete_bill' => 'Delete bill ":name"', - 'delete_budget' => 'Delete budget ":name"', - 'delete_category' => 'Delete category ":name"', - 'delete_currency' => 'Delete currency ":name"', - 'delete_journal' => 'Delete transaction with description ":description"', - 'delete_attachment' => 'Delete attachment ":name"', - 'delete_rule' => 'Delete rule ":title"', - 'delete_rule_group' => 'Delete rule group ":title"', - 'delete_link_type' => 'Delete link type ":name"', - 'delete_user' => 'Delete user ":email"', - 'user_areYouSure' => 'If you delete user ":email", everything will be gone. There is no undo, undelete or anything. If you delete yourself, you will lose access to this instance of Firefly III.', - 'attachment_areYouSure' => 'Are you sure you want to delete the attachment named ":name"?', - 'account_areYouSure' => 'Are you sure you want to delete the account named ":name"?', - 'bill_areYouSure' => 'Are you sure you want to delete the bill named ":name"?', - 'rule_areYouSure' => 'Are you sure you want to delete the rule titled ":title"?', - 'ruleGroup_areYouSure' => 'Are you sure you want to delete the rule group titled ":title"?', - 'budget_areYouSure' => 'Are you sure you want to delete the budget named ":name"?', - 'category_areYouSure' => 'Are you sure you want to delete the category named ":name"?', - 'currency_areYouSure' => 'Are you sure you want to delete the currency named ":name"?', - 'piggyBank_areYouSure' => 'Are you sure you want to delete the piggy bank named ":name"?', - 'journal_areYouSure' => 'Are you sure you want to delete the transaction described ":description"?', - 'mass_journal_are_you_sure' => 'Are you sure you want to delete these transactions?', - 'tag_areYouSure' => 'Are you sure you want to delete the tag ":tag"?', - 'journal_link_areYouSure' => 'Are you sure you want to delete the link between :source and :destination?', - 'linkType_areYouSure' => 'Are you sure you want to delete the link type ":name" (":inward" / ":outward")?', - 'permDeleteWarning' => 'Deleting stuff from Firefly III is permanent and cannot be undone.', - 'mass_make_selection' => 'You can still prevent items from being deleted by removing the checkbox.', - 'delete_all_permanently' => 'Delete selected permanently', - 'update_all_journals' => 'Update these transactions', - 'also_delete_transactions' => 'The only transaction connected to this account will be deleted as well.|All :count transactions connected to this account will be deleted as well.', - 'also_delete_connections' => 'The only transaction linked with this link type will lose this connection.|All :count transactions linked with this link type will lose their connection.', - 'also_delete_rules' => 'The only rule connected to this rule group will be deleted as well.|All :count rules connected to this rule group will be deleted as well.', - 'also_delete_piggyBanks' => 'The only piggy bank connected to this account will be deleted as well.|All :count piggy bank connected to this account will be deleted as well.', - 'bill_keep_transactions' => 'The only transaction connected to this bill will not be deleted.|All :count transactions connected to this bill will spared deletion.', - 'budget_keep_transactions' => 'The only transaction connected to this budget will not be deleted.|All :count transactions connected to this budget will spared deletion.', - 'category_keep_transactions' => 'The only transaction connected to this category will not be deleted.|All :count transactions connected to this category will spared deletion.', - 'tag_keep_transactions' => 'The only transaction connected to this tag will not be deleted.|All :count transactions connected to this tag will spared deletion.', - 'check_for_updates' => 'Check for updates', + 'amount' => 'Amount', + 'foreign_amount' => 'Foreign amount', + 'existing_attachments' => 'Existing attachments', + 'date' => 'Date', + 'interest_date' => 'Interest date', + 'book_date' => 'Book date', + 'process_date' => 'Processing date', + 'category' => 'Category', + 'tags' => 'Tags', + 'deletePermanently' => 'Delete permanently', + 'cancel' => 'Cancel', + 'targetdate' => 'Target date', + 'startdate' => 'Start date', + 'tag' => 'Tag', + 'under' => 'Under', + 'symbol' => 'Symbol', + 'code' => 'Code', + 'iban' => 'IBAN', + 'accountNumber' => 'Account number', + 'creditCardNumber' => 'Credit card number', + 'has_headers' => 'Headers', + 'date_format' => 'Date format', + 'specifix' => 'Bank- or file specific fixes', + 'attachments[]' => 'Attachments', + 'store_new_withdrawal' => 'Store new withdrawal', + 'store_new_deposit' => 'Store new deposit', + 'store_new_transfer' => 'Store new transfer', + 'add_new_withdrawal' => 'Add a new withdrawal', + 'add_new_deposit' => 'Add a new deposit', + 'add_new_transfer' => 'Add a new transfer', + 'title' => 'Title', + 'notes' => 'Notes', + 'filename' => 'File name', + 'mime' => 'Mime type', + 'size' => 'Size', + 'trigger' => 'Trigger', + 'stop_processing' => 'Stop processing', + 'start_date' => 'Start of range', + 'end_date' => 'End of range', + 'export_start_range' => 'Start of export range', + 'export_end_range' => 'End of export range', + 'export_format' => 'File format', + 'include_attachments' => 'Include uploaded attachments', + 'include_old_uploads' => 'Include imported data', + 'accounts' => 'Export transactions from these accounts', + 'delete_account' => 'Delete account ":name"', + 'delete_bill' => 'Delete bill ":name"', + 'delete_budget' => 'Delete budget ":name"', + 'delete_category' => 'Delete category ":name"', + 'delete_currency' => 'Delete currency ":name"', + 'delete_journal' => 'Delete transaction with description ":description"', + 'delete_attachment' => 'Delete attachment ":name"', + 'delete_rule' => 'Delete rule ":title"', + 'delete_rule_group' => 'Delete rule group ":title"', + 'delete_link_type' => 'Delete link type ":name"', + 'delete_user' => 'Delete user ":email"', + 'delete_recurring' => 'Delete recurring transaction ":title"', + 'user_areYouSure' => 'If you delete user ":email", everything will be gone. There is no undo, undelete or anything. If you delete yourself, you will lose access to this instance of Firefly III.', + 'attachment_areYouSure' => 'Are you sure you want to delete the attachment named ":name"?', + 'account_areYouSure' => 'Are you sure you want to delete the account named ":name"?', + 'bill_areYouSure' => 'Are you sure you want to delete the bill named ":name"?', + 'rule_areYouSure' => 'Are you sure you want to delete the rule titled ":title"?', + 'ruleGroup_areYouSure' => 'Are you sure you want to delete the rule group titled ":title"?', + 'budget_areYouSure' => 'Are you sure you want to delete the budget named ":name"?', + 'category_areYouSure' => 'Are you sure you want to delete the category named ":name"?', + 'recurring_areYouSure' => 'Are you sure you want to delete the recurring transaction titled ":title"?', + 'currency_areYouSure' => 'Are you sure you want to delete the currency named ":name"?', + 'piggyBank_areYouSure' => 'Are you sure you want to delete the piggy bank named ":name"?', + 'journal_areYouSure' => 'Are you sure you want to delete the transaction described ":description"?', + 'mass_journal_are_you_sure' => 'Are you sure you want to delete these transactions?', + 'tag_areYouSure' => 'Are you sure you want to delete the tag ":tag"?', + 'journal_link_areYouSure' => 'Are you sure you want to delete the link between :source and :destination?', + 'linkType_areYouSure' => 'Are you sure you want to delete the link type ":name" (":inward" / ":outward")?', + 'permDeleteWarning' => 'Deleting stuff from Firefly III is permanent and cannot be undone.', + 'mass_make_selection' => 'You can still prevent items from being deleted by removing the checkbox.', + 'delete_all_permanently' => 'Delete selected permanently', + 'update_all_journals' => 'Update these transactions', + 'also_delete_transactions' => 'The only transaction connected to this account will be deleted as well.|All :count transactions connected to this account will be deleted as well.', + 'also_delete_connections' => 'The only transaction linked with this link type will lose this connection.|All :count transactions linked with this link type will lose their connection.', + 'also_delete_rules' => 'The only rule connected to this rule group will be deleted as well.|All :count rules connected to this rule group will be deleted as well.', + 'also_delete_piggyBanks' => 'The only piggy bank connected to this account will be deleted as well.|All :count piggy bank connected to this account will be deleted as well.', + 'bill_keep_transactions' => 'The only transaction connected to this bill will not be deleted.|All :count transactions connected to this bill will be spared deletion.', + 'budget_keep_transactions' => 'The only transaction connected to this budget will not be deleted.|All :count transactions connected to this budget will be spared deletion.', + 'category_keep_transactions' => 'The only transaction connected to this category will not be deleted.|All :count transactions connected to this category will be spared deletion.', + 'recurring_keep_transactions' => 'The only transaction created by this recurring transaction will not be deleted.|All :count transactions created by this recurring transaction will be spared deletion.', + 'tag_keep_transactions' => 'The only transaction connected to this tag will not be deleted.|All :count transactions connected to this tag will be spared deletion.', + 'check_for_updates' => 'Check for updates', 'email' => 'Email address', 'password' => 'Password', diff --git a/resources/views/recurring/delete.twig b/resources/views/recurring/delete.twig new file mode 100644 index 0000000000..2843a5705e --- /dev/null +++ b/resources/views/recurring/delete.twig @@ -0,0 +1,41 @@ +{% extends "./layout/default" %} + +{% block breadcrumbs %} + {{ Breadcrumbs.render(Route.getCurrentRoute.getName, recurrence) }} +{% endblock %} + +{% block content %} + +
+ +
+
+
+
+

{{ trans('form.delete_recurring', {'title': recurrence.title}) }}

+
+
+

+ {{ trans('form.permDeleteWarning') }} +

+ +

+ {{ trans('form.recurring_areYouSure', {'title': recurrence.title}) }} +

+ +

+ {% if journalsCreated > 0 %} + {{ Lang.choice('form.recurring_keep_transactions', journalsCreated, {count: journalsCreated }) }} + {% endif %} +

+
+ +
+
+
+ +
+{% endblock %} diff --git a/routes/breadcrumbs.php b/routes/breadcrumbs.php index 1ffad9ff16..5a895da18c 100644 --- a/routes/breadcrumbs.php +++ b/routes/breadcrumbs.php @@ -778,6 +778,14 @@ try { } ); + Breadcrumbs::register( + 'recurring.delete', + function (BreadCrumbsGenerator $breadcrumbs, Recurrence $recurrence) { + $breadcrumbs->parent('recurring.index'); + $breadcrumbs->push(trans('firefly.delete_recurring', ['title' => $recurrence->title]), route('recurring.delete', [$recurrence->id])); + } + ); + Breadcrumbs::register( 'recurring.edit', function (BreadCrumbsGenerator $breadcrumbs, Recurrence $recurrence) { diff --git a/routes/web.php b/routes/web.php index fc5461766d..84dd57281a 100755 --- a/routes/web.php +++ b/routes/web.php @@ -626,6 +626,7 @@ Route::group( Route::post('store', ['uses' => 'CreateController@store', 'as' => 'store']); Route::post('update/{recurrence}', ['uses' => 'EditController@update', 'as' => 'update']); + Route::post('destroy/{recurrence}', ['uses' => 'DeleteController@destroy', 'as' => 'destroy']); } );