diff --git a/app/Http/Controllers/Rule/CreateController.php b/app/Http/Controllers/Rule/CreateController.php index a655c17508..5ca08cfcd9 100644 --- a/app/Http/Controllers/Rule/CreateController.php +++ b/app/Http/Controllers/Rule/CreateController.php @@ -28,6 +28,7 @@ use FireflyIII\Http\Controllers\Controller; use FireflyIII\Http\Requests\RuleFormRequest; use FireflyIII\Models\Bill; use FireflyIII\Models\RuleGroup; +use FireflyIII\Models\TransactionJournal; use FireflyIII\Repositories\Rule\RuleRepositoryInterface; use FireflyIII\Support\Http\Controllers\ModelInformation; use FireflyIII\Support\Http\Controllers\RuleManagement; @@ -45,6 +46,7 @@ class CreateController extends Controller /** * RuleController constructor. + * * @codeCoverageIgnore */ public function __construct() @@ -158,6 +160,48 @@ class CreateController extends Controller ); } + /** + * @param Request $request + * @param TransactionJournal $journal + */ + public function createFromJournal(Request $request, TransactionJournal $journal) + { + $request->session()->flash('info', (string)trans('firefly.instructions_rule_from_journal', ['name' => e($journal->name)])); + + $subTitleIcon = 'fa-clone'; + $subTitle = (string)trans('firefly.make_new_rule_no_group'); + + // get triggers and actions for journal. + $oldTriggers = $this->getTriggersForJournal($journal); + $oldActions = []; + $triggerCount = count($oldTriggers); + $actionCount = count($oldActions); + + $this->createDefaultRuleGroup(); + $this->createDefaultRule(); + + // collect pre-filled information: + $preFilled = [ + 'strict' => true, + 'title' => (string)trans('firefly.new_rule_for_journal_title', ['description' => $journal->description]), + 'description' => (string)trans('firefly.new_rule_for_journal_description', ['description' => $journal->description]), + ]; + + // flash old data + $request->session()->flash('preFilled', $preFilled); + + // put previous url in session if not redirect from store (not "create another"). + if (true !== session('rules.create.fromStore')) { + $this->rememberPreviousUri('rules.create.uri'); + } + session()->forget('rules.create.fromStore'); + + return view( + 'rules.rule.create', compact('subTitleIcon', 'oldTriggers', 'preFilled', 'oldActions', 'triggerCount', 'actionCount', 'subTitle') + ); + + } + /** * Store the new rule. * diff --git a/app/Support/Http/Controllers/ModelInformation.php b/app/Support/Http/Controllers/ModelInformation.php index 597cbaff16..82b4a09031 100644 --- a/app/Support/Http/Controllers/ModelInformation.php +++ b/app/Support/Http/Controllers/ModelInformation.php @@ -23,14 +23,12 @@ declare(strict_types=1); namespace FireflyIII\Support\Http\Controllers; -use FireflyIII\Exceptions\FireflyException; -use FireflyIII\Models\Account; use FireflyIII\Models\AccountType; use FireflyIII\Models\Bill; +use FireflyIII\Models\Tag; +use FireflyIII\Models\Transaction; use FireflyIII\Models\TransactionJournal; -use FireflyIII\Models\TransactionType; use FireflyIII\Repositories\Account\AccountRepositoryInterface; -use FireflyIII\Repositories\Journal\JournalRepositoryInterface; use Log; use Throwable; @@ -71,6 +69,43 @@ trait ModelInformation return [$result]; } + /** + * @codeCoverageIgnore + * @return array + */ + protected function getLiabilityTypes(): array + { + /** @var AccountRepositoryInterface $repository */ + $repository = app(AccountRepositoryInterface::class); + // types of liability: + $debt = $repository->getAccountTypeByType(AccountType::DEBT); + $loan = $repository->getAccountTypeByType(AccountType::LOAN); + $mortgage = $repository->getAccountTypeByType(AccountType::MORTGAGE); + /** @noinspection NullPointerExceptionInspection */ + $liabilityTypes = [ + $debt->id => (string)trans(sprintf('firefly.account_type_%s', AccountType::DEBT)), + $loan->id => (string)trans(sprintf('firefly.account_type_%s', AccountType::LOAN)), + $mortgage->id => (string)trans(sprintf('firefly.account_type_%s', AccountType::MORTGAGE)), + ]; + asort($liabilityTypes); + + return $liabilityTypes; + } + + /** + * @codeCoverageIgnore + * @return array + */ + protected function getRoles(): array + { + $roles = []; + foreach (config('firefly.accountRoles') as $role) { + $roles[$role] = (string)trans(sprintf('firefly.account_role_%s', $role)); + } + + return $roles; + } + /** * Create fake triggers to match the bill's properties * @@ -116,39 +151,109 @@ trait ModelInformation } /** - * @codeCoverageIgnore + * @param TransactionJournal $journal + * * @return array */ - protected function getRoles(): array + private function getTriggersForJournal(TransactionJournal $journal): array { - $roles = []; - foreach (config('firefly.accountRoles') as $role) { - $roles[$role] = (string)trans(sprintf('firefly.account_role_%s', $role)); + $result = []; + $triggers = []; + $values = []; + $index = 0; + // amount, description, category, budget, tags, source, destination, notes, currency type + //,type + /** @var Transaction $source */ + $source = $journal->transactions()->where('amount', '<', 0)->first(); + /** @var Transaction $destination */ + $destination = $journal->transactions()->where('amount', '>', 0)->first(); + if (null === $destination || null === $source) { + return $result; + } + // type + $triggers[$index] = 'transaction_type'; + $values[$index] = $journal->transactionType->type; + $index++; + + // currency + $triggers[$index] = 'currency_is'; + $values[$index] = sprintf('%s (%s)', $journal->transactionCurrency->name, $journal->transactionCurrency->code); + $index++; + + // amount_exactly: + $triggers[$index] = 'amount_exactly'; + $values[$index] = $destination->amount; + $index++; + + // description_is: + $triggers[$index] = 'description_is'; + $values[$index] = $journal->description; + $index++; + + // from_account_is + $triggers[$index] = 'from_account_is'; + $values[$index] = $source->account->name; + $index++; + + // to_account_is + $triggers[$index] = 'to_account_is'; + $values[$index] = $destination->account->name; + $index++; + + // category (if) + $category = $journal->categories()->first(); + if (null !== $category) { + $triggers[$index] = 'category_is'; + $values[$index] = $category->name; + $index++; + } + // budget (if) + $budget = $journal->budgets()->first(); + if (null !== $budget) { + $triggers[$index] = 'budget_is'; + $values[$index] = $budget->name; + $index++; + } + // tags (if) + $tags = $journal->tags()->get(); + /** @var Tag $tag */ + foreach ($tags as $tag) { + $triggers[$index] = 'tag_is'; + $values[$index] = $tag->tag; + $index++; + } + // notes (if) + $notes = $journal->notes()->first(); + if (null !== $notes) { + $triggers[$index] = 'notes_are'; + $values[$index] = $notes->text; + $index++; } - return $roles; - } + foreach ($triggers as $index => $trigger) { + try { + $string = view( + 'rules.partials.trigger', + [ + 'oldTrigger' => $trigger, + 'oldValue' => $values[$index], + 'oldChecked' => false, + 'count' => $index + 1, + ] + )->render(); + // @codeCoverageIgnoreStart + } catch (Throwable $e) { - /** - * @codeCoverageIgnore - * @return array - */ - protected function getLiabilityTypes(): array - { - /** @var AccountRepositoryInterface $repository */ - $repository = app(AccountRepositoryInterface::class); - // types of liability: - $debt = $repository->getAccountTypeByType(AccountType::DEBT); - $loan = $repository->getAccountTypeByType(AccountType::LOAN); - $mortgage = $repository->getAccountTypeByType(AccountType::MORTGAGE); - /** @noinspection NullPointerExceptionInspection */ - $liabilityTypes = [ - $debt->id => (string)trans(sprintf('firefly.account_type_%s', AccountType::DEBT)), - $loan->id => (string)trans(sprintf('firefly.account_type_%s', AccountType::LOAN)), - $mortgage->id => (string)trans(sprintf('firefly.account_type_%s', AccountType::MORTGAGE)), - ]; - asort($liabilityTypes); + Log::debug(sprintf('Throwable was thrown in getTriggersForJournal(): %s', $e->getMessage())); + Log::debug($e->getTraceAsString()); + $string = ''; + // @codeCoverageIgnoreEnd + } + if ('' !== $string) { + $result[] = $string; + } + } - return $liabilityTypes; + return $result; } } diff --git a/app/Support/Http/Controllers/RuleManagement.php b/app/Support/Http/Controllers/RuleManagement.php index 8964248f7b..b31ee93aa6 100644 --- a/app/Support/Http/Controllers/RuleManagement.php +++ b/app/Support/Http/Controllers/RuleManagement.php @@ -23,6 +23,7 @@ declare(strict_types=1); namespace FireflyIII\Support\Http\Controllers; +use FireflyIII\Models\TransactionJournal; use FireflyIII\Repositories\Rule\RuleRepositoryInterface; use FireflyIII\Repositories\RuleGroup\RuleGroupRepositoryInterface; use Illuminate\Http\Request; diff --git a/resources/lang/en_US/firefly.php b/resources/lang/en_US/firefly.php index 7acb166d26..919904f8b9 100644 --- a/resources/lang/en_US/firefly.php +++ b/resources/lang/en_US/firefly.php @@ -512,6 +512,7 @@ return [ 'delete_all_selected_tags' => 'Delete all selected tags', 'select_tags_to_delete' => 'Don\'t forget to select some tags.', 'deleted_x_tags' => 'Deleted :count tag(s).', + 'create_rule_from_transaction' => 'Create rule based on transaction', // preferences 'pref_home_screen_accounts' => 'Home screen accounts', diff --git a/resources/views/v1/transactions/show.twig b/resources/views/v1/transactions/show.twig index bbfb9d6637..b9ebd56c09 100644 --- a/resources/views/v1/transactions/show.twig +++ b/resources/views/v1/transactions/show.twig @@ -276,6 +276,10 @@ {{ 'link_transaction'|_ }} + + + {{ 'create_rule_from_transaction'|_ }} + diff --git a/routes/breadcrumbs.php b/routes/breadcrumbs.php index c9ecac8eb5..5dcd657148 100644 --- a/routes/breadcrumbs.php +++ b/routes/breadcrumbs.php @@ -887,6 +887,15 @@ try { $breadcrumbs->push(trans('firefly.make_new_rule_no_group'), route('rules.create')); } ); + + Breadcrumbs::register( + 'rules.create-from-journal', + function (BreadcrumbsGenerator $breadcrumbs) { + $breadcrumbs->parent('rules.index'); + $breadcrumbs->push(trans('firefly.make_new_rule_no_group'), route('rules.create')); + } + ); + Breadcrumbs::register( 'rules.edit', function (BreadcrumbsGenerator $breadcrumbs, Rule $rule) { diff --git a/routes/web.php b/routes/web.php index 68e875f38f..babf1c9752 100644 --- a/routes/web.php +++ b/routes/web.php @@ -863,6 +863,7 @@ Route::group( // create controller Route::get('create/{ruleGroup?}', ['uses' => 'Rule\CreateController@create', 'as' => 'create']); Route::get('create-from-bill/{bill}', ['uses' => 'Rule\CreateController@createFromBill', 'as' => 'create-from-bill']); + Route::get('create-from-journal/{tj}', ['uses' => 'Rule\CreateController@createFromJournal', 'as' => 'create-from-journal']); Route::post('store', ['uses' => 'Rule\CreateController@store', 'as' => 'store']); // delete controller