diff --git a/app/Http/Controllers/Transaction/MassController.php b/app/Http/Controllers/Transaction/MassController.php index 2bb0a44d27..aea0bf9d9d 100644 --- a/app/Http/Controllers/Transaction/MassController.php +++ b/app/Http/Controllers/Transaction/MassController.php @@ -26,6 +26,7 @@ use Carbon\Carbon; use FireflyIII\Http\Controllers\Controller; use FireflyIII\Http\Requests\MassDeleteJournalRequest; use FireflyIII\Http\Requests\MassEditJournalRequest; +use FireflyIII\Http\Requests\MassEditBulkJournalRequest; use FireflyIII\Models\AccountType; use FireflyIII\Models\TransactionJournal; use FireflyIII\Models\TransactionType; @@ -131,7 +132,7 @@ class MassController extends Controller // skip transactions that have multiple destinations, multiple sources or are an opening balance. $filtered = new Collection; $messages = []; - // @var TransactionJournal + /** @var TransactionJournal $journal */ foreach ($journals as $journal) { $sources = $journal->sourceAccountList(); $destinations = $journal->destinationAccountList(); @@ -200,6 +201,70 @@ class MassController extends Controller return view('transactions.mass.edit', compact('journals', 'subTitle', 'accounts', 'budgets')); } + /** + * @param Collection $journals + * + * @return View + */ + public function editBulk(Collection $journals) + { + $subTitle = trans('firefly.mass_edit_bulk_journals'); + + // skip transactions that have multiple destinations, multiple sources or are an opening balance. + $filtered = new Collection; + $messages = []; + /** @var TransactionJournal $journal */ + foreach ($journals as $journal) { + $sources = $journal->sourceAccountList(); + $destinations = $journal->destinationAccountList(); + if ($sources->count() > 1) { + $messages[] = trans('firefly.cannot_edit_multiple_source', ['description' => $journal->description, 'id' => $journal->id]); + continue; + } + + if ($destinations->count() > 1) { + $messages[] = trans('firefly.cannot_edit_multiple_dest', ['description' => $journal->description, 'id' => $journal->id]); + continue; + } + if (TransactionType::OPENING_BALANCE === $journal->transactionType->type) { + $messages[] = trans('firefly.cannot_edit_opening_balance'); + continue; + } + + // cannot edit reconciled transactions / journals: + if ($journal->transactions->first()->reconciled) { + $messages[] = trans('firefly.cannot_edit_reconciled', ['description' => $journal->description, 'id' => $journal->id]); + continue; + } + + $filtered->push($journal); + } + + if (count($messages) > 0) { + Session::flash('info', $messages); + } + + // put previous url in session + $this->rememberPreviousUri('transactions.mass-edit-bulk.uri'); + Session::flash('gaEventCategory', 'transactions'); + Session::flash('gaEventAction', 'mass-edit-bulk'); + + // collect some useful meta data for the mass edit: + $filtered->each( + function (TransactionJournal $journal) { + $journal->transaction_count = $journal->transactions()->count(); + } + ); + + if (0 === $filtered->count()) { + Session::flash('error', trans('firefly.no_edit_multiple_left')); + } + + $journals = $filtered; + + return view('transactions.mass.edit-bulk', compact('journals', 'subTitle')); + } + /** * @param MassEditJournalRequest $request * @param JournalRepositoryInterface $repository @@ -264,4 +329,24 @@ class MassController extends Controller // redirect to previous URL: return redirect($this->getPreviousUri('transactions.mass-edit.uri')); } + + /** + * @param MassEditBulkJournalRequest $request + * @param JournalRepositoryInterface $repository + * + * @return mixed + */ + public function updateBulk(MassEditBulkJournalRequest $request, JournalRepositoryInterface $repository) + { + $journalIds = $request->get('journals'); + $count = 0; + if (is_array($journalIds)) { + $repository->updateBulk($journalIds, $request->get('category'), $request->get('tags')); + } + Preferences::mark(); + Session::flash('success', trans('firefly.mass_edited_transactions_success', ['amount' => $count])); + + // redirect to previous URL: + return redirect($this->getPreviousUri('transactions.mass-edit-bulk.uri')); + } } diff --git a/app/Http/Requests/MassEditBulkJournalRequest.php b/app/Http/Requests/MassEditBulkJournalRequest.php new file mode 100644 index 0000000000..c3024e6729 --- /dev/null +++ b/app/Http/Requests/MassEditBulkJournalRequest.php @@ -0,0 +1,48 @@ +. + */ +declare(strict_types=1); + +namespace FireflyIII\Http\Requests; + +/** + * Class MassEditBulkJournalRequest. + */ +class MassEditBulkJournalRequest extends Request +{ + /** + * @return bool + */ + public function authorize() + { + // Only allow logged in users + return auth()->check(); + } + + /** + * @return array + */ + public function rules() + { + // fixed + + return []; + } +} diff --git a/app/Repositories/Journal/JournalRepository.php b/app/Repositories/Journal/JournalRepository.php index c71afd2e20..43b66715fd 100644 --- a/app/Repositories/Journal/JournalRepository.php +++ b/app/Repositories/Journal/JournalRepository.php @@ -24,7 +24,9 @@ namespace FireflyIII\Repositories\Journal; use FireflyIII\Models\Account; use FireflyIII\Models\AccountType; +use FireflyIII\Models\Category; use FireflyIII\Models\Note; +use FireflyIII\Models\Tag; use FireflyIII\Models\Transaction; use FireflyIII\Models\TransactionJournal; use FireflyIII\Models\TransactionType; @@ -432,6 +434,47 @@ class JournalRepository implements JournalRepositoryInterface return $journal; } + /** + * @param array $journals + * @param var $category + * @param var $tags + * + * @return int + */ + public function updateBulk(array $journals, $category, $tags): int + { + $count = 0; + foreach ($journals as $journalId) { + $journal = $this->find(intval($journalId)); + if ($journal) { + // update category: + if (isset($category)) { + $categoryToReplace = Category::firstOrCreateEncrypted(['name' => strval($category), 'user_id' => $journal->user->id]); + $journal->categories()->sync([$categoryToReplace->id]); + /** @var Transaction $transaction */ + foreach ($journal->transactions()->getResults() as $transaction) { + $transaction->categories()->sync([$categoryToReplace->id]); + $transaction->touch(); + } + } + + // update tags: + if (isset($tags)) { + $tagsToReplace = []; + foreach (explode(',', strval($tags)) as $tag) { + array_push($tagsToReplace, Tag::firstOrCreateEncrypted(['tag' => $tag, 'user_id' => $journal->user->id])->id); + } + $journal->tags()->sync($tagsToReplace); + } + + $journal->touch(); + ++$count; + } + } + + return $count; + } + /** * Same as above but for transaction journal with multiple transactions. * diff --git a/app/Repositories/Journal/JournalRepositoryInterface.php b/app/Repositories/Journal/JournalRepositoryInterface.php index a136ed1784..a895e03833 100644 --- a/app/Repositories/Journal/JournalRepositoryInterface.php +++ b/app/Repositories/Journal/JournalRepositoryInterface.php @@ -161,6 +161,15 @@ interface JournalRepositoryInterface */ public function update(TransactionJournal $journal, array $data): TransactionJournal; + /** + * @param array $journals + * @param var $category + * @param var $tags + * + * @return int + */ + public function updateBulk(array $journals, $category, $tags): int; + /** * @param TransactionJournal $journal * @param array $data diff --git a/public/js/ff/transactions/list.js b/public/js/ff/transactions/list.js index 1a9b5d1230..4f013541ba 100644 --- a/public/js/ff/transactions/list.js +++ b/public/js/ff/transactions/list.js @@ -18,7 +18,7 @@ * along with Firefly III. If not, see . */ -/** global: edit_selected_txt, delete_selected_txt */ +/** global: edit_selected_txt, edit_bulk_selected_txt, delete_selected_txt */ /** * @@ -45,6 +45,8 @@ $(document).ready(function () { // click the edit button: $('.mass_edit').click(goToMassEdit); + // click the edit button: + $('.mass_edit_bulk').click(goToMassBulkEdit); // click the delete button: $('.mass_delete').click(goToMassDelete); // click reconcile button @@ -100,6 +102,26 @@ function goToMassEdit() { return false; } +/** + * + * @returns {boolean} + */ +function goToMassBulkEdit() { + "use strict"; + var checkedArray = getCheckboxes(); + + // go to specially crafted URL: + var bases = document.getElementsByTagName('base'); + var baseHref = null; + + if (bases.length > 0) { + baseHref = bases[0].href; + } + + window.location.href = baseHref + '/transactions/mass/edit/bulk/' + checkedArray; + return false; +} + /** * * @returns {boolean} @@ -144,6 +166,7 @@ function countChecked() { var checked = $('.select_all_single:checked').length; if (checked > 0) { $('.mass_edit span').text(edit_selected_txt + ' (' + checked + ')'); + $('.mass_edit_bulk span').text(edit_bulk_selected_txt + ' (' + checked + ')'); $('.mass_delete span').text(delete_selected_txt + ' (' + checked + ')'); // get amount for the transactions: diff --git a/public/js/ff/transactions/mass/edit-bulk.js b/public/js/ff/transactions/mass/edit-bulk.js new file mode 100644 index 0000000000..0aa1f01a3c --- /dev/null +++ b/public/js/ff/transactions/mass/edit-bulk.js @@ -0,0 +1,43 @@ +/* + * edit.js + * Copyright (c) 2017 thegrumpydictator@gmail.com + * + * This file is part of Firefly III. + * + * Firefly III is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Firefly III is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Firefly III. If not, see . + */ + +/** global: what */ + +$(document).ready(function () { + "use strict"; + + $.getJSON('json/categories').done(function (data) { + $('input[name="category"]').typeahead({source: data}); + }); + + $.getJSON('json/tags').done(function (data) { + var opt = { + typeahead: { + source: data, + afterSelect: function () { + this.$element.val(""); + } + } + }; + $('input[name="tags"]').tagsinput( + opt + ); + }); +}); \ No newline at end of file diff --git a/resources/lang/de_DE/firefly.php b/resources/lang/de_DE/firefly.php index 33a6260351..c6e298e9d9 100644 --- a/resources/lang/de_DE/firefly.php +++ b/resources/lang/de_DE/firefly.php @@ -713,6 +713,7 @@ Sollen zusätzlich Ihre Girokonten angezeigt werden?', 'reconcile_selected' => 'Ausgleichen', 'mass_delete_journals' => 'Löschen Sie eine Reihe von Überweisungen', 'mass_edit_journals' => 'Bearbeiten Sie eine Reihe von Überweisungen', + 'mass_edit_bulk_journals' => 'Bulk-Bearbeitung', 'cannot_edit_other_fields' => 'You cannot mass-edit other fields than the ones here, because there is no room to show them. Please follow the link and edit them by one-by-one, if you need to edit these fields.', 'no_budget' => '(kein Budget)', 'no_budget_squared' => '(kein Budget)', @@ -724,6 +725,7 @@ Sollen zusätzlich Ihre Girokonten angezeigt werden?', 'opt_group_savingAsset' => 'Sparkonten', 'opt_group_sharedAsset' => 'Shared asset accounts', 'opt_group_ccAsset' => 'Kreditkarten', + 'mass_edit_bulk' => 'Bulk-Bearbeitung', // new user: 'welcome' => 'Willkommen bei Firefly!', diff --git a/resources/lang/de_DE/list.php b/resources/lang/de_DE/list.php index eb4980e563..2cdeffbc9a 100644 --- a/resources/lang/de_DE/list.php +++ b/resources/lang/de_DE/list.php @@ -89,6 +89,7 @@ return [ 'budget_count' => 'Anzahl Budgets', 'rule_and_groups_count' => 'Anzahl Regeln und Regelgruppen', 'tags_count' => 'Anzahl Tags', + 'tags' => 'Tags', 'inward' => 'Inward description', 'outward' => 'Outward description', 'number_of_transactions' => 'Anzahl der Zahlungsvorgänge', diff --git a/resources/lang/en_US/firefly.php b/resources/lang/en_US/firefly.php index 74ea4fea3f..888950eaa6 100644 --- a/resources/lang/en_US/firefly.php +++ b/resources/lang/en_US/firefly.php @@ -728,6 +728,7 @@ return [ 'reconcile_selected' => 'Reconcile', 'mass_delete_journals' => 'Delete a number of transactions', 'mass_edit_journals' => 'Edit a number of transactions', + 'mass_edit_bulk_journals' => 'Bulk edit', 'cannot_edit_other_fields' => 'You cannot mass-edit other fields than the ones here, because there is no room to show them. Please follow the link and edit them by one-by-one, if you need to edit these fields.', 'no_budget' => 'none', 'no_budget_squared' => '(no budget)', @@ -739,6 +740,7 @@ return [ 'opt_group_savingAsset' => 'Savings accounts', 'opt_group_sharedAsset' => 'Shared asset accounts', 'opt_group_ccAsset' => 'Credit cards', + 'mass_edit_bulk' => 'Bulk edit', // new user: 'welcome' => 'Welcome to Firefly!', diff --git a/resources/lang/en_US/list.php b/resources/lang/en_US/list.php index f7f6d0c8fa..a09af7d39a 100644 --- a/resources/lang/en_US/list.php +++ b/resources/lang/en_US/list.php @@ -89,6 +89,7 @@ return [ 'budget_count' => 'Number of budgets', 'rule_and_groups_count' => 'Number of rules and rule groups', 'tags_count' => 'Number of tags', + 'tags' => 'Tags', 'inward' => 'Inward description', 'outward' => 'Outward description', 'number_of_transactions' => 'Number of transactions', diff --git a/resources/views/list/journals.twig b/resources/views/list/journals.twig index 0e3f4ff036..a0b30a4d9b 100644 --- a/resources/views/list/journals.twig +++ b/resources/views/list/journals.twig @@ -36,6 +36,7 @@ diff --git a/resources/views/transactions/mass/edit-bulk.twig b/resources/views/transactions/mass/edit-bulk.twig new file mode 100644 index 0000000000..fdff24348f --- /dev/null +++ b/resources/views/transactions/mass/edit-bulk.twig @@ -0,0 +1,65 @@ +{% extends "./layout/default" %} + +{% block breadcrumbs %} + {{ Breadcrumbs.renderIfExists(Route.getCurrentRoute.getName, journals) }} +{% endblock %} + +{% block content %} +
+ + {% for journal in journals %} + {% if journal.transaction_count == 2 %} + + {% endif %} + {% endfor %} + +
+
+
+
+

{{ 'mass_edit_bulk_journals'|_ }}

+
+
+

+ {{ 'cannot_edit_other_fields'|_ }} +

+ + + + + + + {# category #} + + {# tags #} + + +
{{ trans('list.category') }}{{ trans('list.tags') }}
+ + + +
+
+ +
+
+
+
+{% endblock %} +{% block scripts %} + + + + +{% endblock %} +{% block styles %} + +{% endblock %} diff --git a/resources/views/transactions/mass/edit.twig b/resources/views/transactions/mass/edit.twig index 9f834d26e5..5f46ef6e47 100644 --- a/resources/views/transactions/mass/edit.twig +++ b/resources/views/transactions/mass/edit.twig @@ -19,7 +19,6 @@ {{ 'cannot_edit_other_fields'|_ }}

- diff --git a/routes/web.php b/routes/web.php index e368b4fc71..03c1c4caeb 100755 --- a/routes/web.php +++ b/routes/web.php @@ -784,8 +784,10 @@ Route::group( Route::group( ['middleware' => 'user-full-auth', 'namespace' => 'Transaction', 'prefix' => 'transactions/mass', 'as' => 'transactions.mass.'], function () { Route::get('edit/{journalList}', ['uses' => 'MassController@edit', 'as' => 'edit']); + Route::get('edit/bulk/{journalList}', ['uses' => 'MassController@editBulk', 'as' => 'edit-bulk']); Route::get('delete/{journalList}', ['uses' => 'MassController@delete', 'as' => 'delete']); Route::post('update', ['uses' => 'MassController@update', 'as' => 'update']); + Route::post('update/bulk', ['uses' => 'MassController@updateBulk', 'as' => 'update-bulk']); Route::post('destroy', ['uses' => 'MassController@destroy', 'as' => 'destroy']); } );
  {{ trans('list.description') }}