mirror of
https://github.com/firefly-iii/firefly-iii.git
synced 2024-12-28 09:51:21 -06:00
New mass delete form and options. #241
This commit is contained in:
parent
f43938726a
commit
3948cb8e6c
@ -7,8 +7,10 @@ use Config;
|
||||
use ExpandedForm;
|
||||
use FireflyIII\Events\TransactionJournalStored;
|
||||
use FireflyIII\Events\TransactionJournalUpdated;
|
||||
use FireflyIII\Exceptions\FireflyException;
|
||||
use FireflyIII\Helpers\Attachments\AttachmentHelperInterface;
|
||||
use FireflyIII\Http\Requests\JournalFormRequest;
|
||||
use FireflyIII\Http\Requests\MassJournalRequest;
|
||||
use FireflyIII\Models\PiggyBank;
|
||||
use FireflyIII\Models\PiggyBankEvent;
|
||||
use FireflyIII\Models\Transaction;
|
||||
@ -222,6 +224,76 @@ class TransactionController extends Controller
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Collection $journals
|
||||
*
|
||||
* @return View
|
||||
*/
|
||||
public function massDelete(Collection $journals)
|
||||
{
|
||||
$subTitle = trans('firefly.mass_delete_journals');
|
||||
|
||||
// put previous url in session
|
||||
Session::put('transactions.mass-delete.url', URL::previous());
|
||||
Session::flash('gaEventCategory', 'transactions');
|
||||
Session::flash('gaEventAction', 'mass-delete');
|
||||
|
||||
return view('transactions.mass-delete', compact('journals', 'subTitle'));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param MassJournalRequest $request
|
||||
* @param JournalRepositoryInterface $repository
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function massDestroy(MassJournalRequest $request, JournalRepositoryInterface $repository)
|
||||
{
|
||||
$ids = $request->get('confirm_mass_delete');
|
||||
$set = new Collection;
|
||||
if (is_array($ids)) {
|
||||
/** @var int $journalId */
|
||||
foreach ($ids as $journalId) {
|
||||
/** @var TransactionJournal $journal */
|
||||
$journal = $repository->find($journalId);
|
||||
if (!is_null($journal->id) && $journalId == $journal->id) {
|
||||
$set->push($journal);
|
||||
}
|
||||
}
|
||||
}
|
||||
unset($journal);
|
||||
/** @var TransactionJournal $journal */
|
||||
foreach ($set as $journal) {
|
||||
$repository->delete($journal);
|
||||
}
|
||||
|
||||
Preferences::mark();
|
||||
|
||||
Session::flash('success', trans('firefly.mass_deleted_transactions_success'));
|
||||
|
||||
// redirect to previous URL:
|
||||
return redirect(session('transactions.mass-delete.url'));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Collection $journals
|
||||
*/
|
||||
public function massEdit(Collection $journals)
|
||||
{
|
||||
throw new FireflyException('Mass editing of journals is not yet supported.');
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public function massUpdate()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param JournalRepositoryInterface $repository
|
||||
*
|
||||
|
49
app/Http/Requests/MassJournalRequest.php
Normal file
49
app/Http/Requests/MassJournalRequest.php
Normal file
@ -0,0 +1,49 @@
|
||||
<?php
|
||||
/**
|
||||
* MassJournalRequest.php
|
||||
* Copyright (C) 2016 thegrumpydictator@gmail.com
|
||||
*
|
||||
* This software may be modified and distributed under the terms
|
||||
* of the MIT license. See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
declare(strict_types = 1);
|
||||
/**
|
||||
* MassJournalRequest.php
|
||||
* Copyright (C) 2016 thegrumpydictator@gmail.com
|
||||
*
|
||||
* This software may be modified and distributed under the terms
|
||||
* of the MIT license. See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
namespace FireflyIII\Http\Requests;
|
||||
|
||||
use Auth;
|
||||
|
||||
/**
|
||||
* Class MassJournalRequest
|
||||
*
|
||||
*
|
||||
* @package FireflyIII\Http\Requests
|
||||
*/
|
||||
class MassJournalRequest extends Request
|
||||
{
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function authorize()
|
||||
{
|
||||
// Only allow logged in users
|
||||
return Auth::check();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function rules()
|
||||
{
|
||||
return [
|
||||
'confirm_mass_delete.*' => 'required|belongsToUser:transaction_journals,id',
|
||||
];
|
||||
}
|
||||
}
|
@ -377,6 +377,12 @@ Route::group(
|
||||
Route::post('/transaction/destroy/{tj}', ['uses' => 'TransactionController@destroy', 'as' => 'transactions.destroy']);
|
||||
Route::post('/transaction/reorder', ['uses' => 'TransactionController@reorder', 'as' => 'transactions.reorder']);
|
||||
|
||||
// mass edit and mass delete.
|
||||
Route::get('/transactions/mass-edit/{journalList}', ['uses' => 'TransactionController@massEdit', 'as' => 'transactions.mass-edit']);
|
||||
Route::get('/transactions/mass-delete/{journalList}', ['uses' => 'TransactionController@massDelete', 'as' => 'transactions.mass-delete']);
|
||||
Route::post('/transactions/mass-update/{journalList}', ['uses' => 'TransactionController@massUpdate', 'as' => 'transactions.mass-update']);
|
||||
Route::post('/transactions/mass-destroy', ['uses' => 'TransactionController@massDestroy', 'as' => 'transactions.mass-destroy']);
|
||||
|
||||
/**
|
||||
* POPUP Controllers
|
||||
*/
|
||||
|
@ -51,6 +51,21 @@ class JournalRepository implements JournalRepositoryInterface
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $journalId
|
||||
*
|
||||
* @return TransactionJournal
|
||||
*/
|
||||
public function find(int $journalId) : TransactionJournal
|
||||
{
|
||||
$journal = $this->user->transactionjournals()->where('id', $journalId)->first();
|
||||
if (is_null($journal)) {
|
||||
return new TransactionJournal;
|
||||
}
|
||||
|
||||
return $journal;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get users first transaction journal
|
||||
*
|
||||
|
@ -24,6 +24,13 @@ interface JournalRepositoryInterface
|
||||
*/
|
||||
public function delete(TransactionJournal $journal): bool;
|
||||
|
||||
/**
|
||||
* @param int $journalId
|
||||
*
|
||||
* @return TransactionJournal
|
||||
*/
|
||||
public function find(int $journalId) : TransactionJournal;
|
||||
|
||||
/**
|
||||
* Get users first transaction journal
|
||||
*
|
||||
|
@ -38,7 +38,7 @@ class CategoryList implements BinderInterface
|
||||
->where('user_id', Auth::user()->id)
|
||||
->get();
|
||||
|
||||
// add empty budget if applicable.
|
||||
// add empty category if applicable.
|
||||
if (in_array('0', $ids)) {
|
||||
$object->push(new Category);
|
||||
}
|
||||
|
48
app/Support/Binder/JournalList.php
Normal file
48
app/Support/Binder/JournalList.php
Normal file
@ -0,0 +1,48 @@
|
||||
<?php
|
||||
/**
|
||||
* JournalList.php
|
||||
* Copyright (C) 2016 thegrumpydictator@gmail.com
|
||||
*
|
||||
* This software may be modified and distributed under the terms
|
||||
* of the MIT license. See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
namespace FireflyIII\Support\Binder;
|
||||
|
||||
|
||||
use Auth;
|
||||
use FireflyIII\Models\TransactionJournal;
|
||||
use Illuminate\Support\Collection;
|
||||
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
||||
|
||||
/**
|
||||
* Class JournalList
|
||||
*
|
||||
* @package FireflyIII\Support\Binder
|
||||
*/
|
||||
class JournalList implements BinderInterface
|
||||
{
|
||||
|
||||
/**
|
||||
* @param $value
|
||||
* @param $route
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public static function routeBinder($value, $route): Collection
|
||||
{
|
||||
if (Auth::check()) {
|
||||
$ids = explode(',', $value);
|
||||
/** @var \Illuminate\Support\Collection $object */
|
||||
$object = TransactionJournal::whereIn('transaction_journals.id', $ids)
|
||||
->expanded()
|
||||
->where('transaction_journals.user_id', Auth::user()->id)
|
||||
->get(TransactionJournal::QUERYFIELDS);
|
||||
|
||||
if ($object->count() > 0) {
|
||||
return $object;
|
||||
}
|
||||
}
|
||||
throw new NotFoundHttpException;
|
||||
}
|
||||
}
|
@ -80,7 +80,7 @@ class FireflyValidator extends Validator
|
||||
|
||||
|
||||
$count = DB::table($parameters[0])->where('user_id', Auth::user()->id)->where($field, $value)->count();
|
||||
if ($count == 1) {
|
||||
if ($count === 1) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -173,6 +173,7 @@ return [
|
||||
// lists
|
||||
'accountList' => 'FireflyIII\Support\Binder\AccountList',
|
||||
'budgetList' => 'FireflyIII\Support\Binder\BudgetList',
|
||||
'journalList' => 'FireflyIII\Support\Binder\JournalList',
|
||||
'categoryList' => 'FireflyIII\Support\Binder\CategoryList',
|
||||
|
||||
// others
|
||||
|
@ -29,7 +29,6 @@ $(document).ready(function () {
|
||||
function goToMassEdit() {
|
||||
"use strict";
|
||||
var checkedArray = getCheckboxes();
|
||||
console.log('Journals: ' + checkedArray);
|
||||
|
||||
// go to specially crafted URL:
|
||||
window.location.href = 'transactions/mass-edit/' + checkedArray;
|
||||
@ -39,7 +38,6 @@ function goToMassEdit() {
|
||||
function goToMassDelete() {
|
||||
"use strict";
|
||||
var checkedArray = getCheckboxes();
|
||||
console.log('Journals: ' + checkedArray);
|
||||
|
||||
// go to specially crafted URL:
|
||||
window.location.href = 'transactions/mass-delete/' + checkedArray;
|
||||
@ -63,7 +61,6 @@ function getCheckboxes() {
|
||||
function countChecked() {
|
||||
"use strict";
|
||||
var checked = $('.select_all_single:checked').length;
|
||||
console.log("Now " + checked + " selected.");
|
||||
if (checked > 0) {
|
||||
$('.mass_edit span').text(edit_selected_txt + ' (' + checked + ')')
|
||||
$('.mass_delete span').text(delete_selected_txt + ' (' + checked + ')')
|
||||
@ -88,9 +85,11 @@ function stopMassSelect() {
|
||||
"use strict";
|
||||
|
||||
// uncheck all:
|
||||
$('input[name="select_all"]').prop('checked', false);
|
||||
uncheckAll();
|
||||
countChecked();
|
||||
|
||||
|
||||
// hide "select all" box in table header.
|
||||
$('.select_boxes').hide();
|
||||
|
||||
|
@ -560,6 +560,10 @@ return [
|
||||
'stop_selection' => 'Stop selecting transactions',
|
||||
'edit_selected' => 'Edit selected',
|
||||
'delete_selected' => 'Delete selected',
|
||||
'mass_delete_journals' => 'Delete a number of transactions',
|
||||
'perm-delete-many' => 'Deleting many items in one go can be very disruptive. Please be catious.',
|
||||
|
||||
|
||||
// new user:
|
||||
'welcome' => 'Welcome to Firefly!',
|
||||
'createNewAsset' => 'Create a new asset account to get started. ' .
|
||||
|
@ -112,8 +112,11 @@ return [
|
||||
'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"?',
|
||||
'permDeleteWarning' => 'Deleting stuff from Firely 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 all permanently',
|
||||
'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_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.',
|
||||
|
78
resources/views/transactions/mass-delete.twig
Normal file
78
resources/views/transactions/mass-delete.twig
Normal file
@ -0,0 +1,78 @@
|
||||
{% extends "./layout/default.twig" %}
|
||||
|
||||
{% block breadcrumbs %}
|
||||
{{ Breadcrumbs.renderIfExists(Route.getCurrentRoute.getName, journal) }}
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
{{ Form.open({'class' : 'form-horizontal','id' : 'destroy','url' : route('transactions.mass-destroy')}) }}
|
||||
|
||||
<div class="row">
|
||||
<div class="col-lg-8 col-lg-offset-2 col-md-8 coll-offset-md-2 col-sm-12">
|
||||
<div class="box box-danger">
|
||||
<div class="box-header with-border">
|
||||
<h3 class="box-title">{{ 'mass_delete_journals'|_ }}</h3>
|
||||
</div>
|
||||
<div class="box-body">
|
||||
<p class="text-danger">
|
||||
{{ trans('form.permDeleteWarning') }}
|
||||
{{ 'perm-delete-many'|_ }}
|
||||
</p>
|
||||
|
||||
<p>
|
||||
{{ trans('form.mass_journal_are_you_sure') }}
|
||||
{{ trans('form.mass_make_selection') }}
|
||||
</p>
|
||||
|
||||
<table class="table table-striped table-condensed">
|
||||
<tr>
|
||||
<th> </th>
|
||||
<th>{{ trans('list.description') }}</th>
|
||||
<th>{{ trans('list.amount') }}</th>
|
||||
<th class="hidden-sm hidden-xs">{{ trans('list.date') }}</th>
|
||||
<th class="hidden-xs">{{ trans('list.from') }}</th>
|
||||
<th class="hidden-xs">{{ trans('list.to') }}</th>
|
||||
</tr>
|
||||
{% for journal in journals %}
|
||||
<tr>
|
||||
<td>
|
||||
<input type="checkbox" name="confirm_mass_delete[]" value="{{ journal.id }}" checked />
|
||||
</td>
|
||||
<td>
|
||||
<a href="{{ route('transactions.show',journal.id) }}" title="{{ journal.description }}">{{ journal.description }}</a>
|
||||
</td>
|
||||
<td>
|
||||
{{ journal|formatJournal }}
|
||||
</td>
|
||||
<td>
|
||||
{{ journal.date.formatLocalized(monthAndDayFormat) }}
|
||||
</td>
|
||||
<td>
|
||||
{% if journal.source_account_type == 'Cash account' %}
|
||||
<span class="text-success">(cash)</span>
|
||||
{% else %}
|
||||
<a href="{{ route('accounts.show',journal.source_account_id) }}">{{ journal.source_account_name }}</a>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>
|
||||
{% if journal.destination_account_type == 'Cash account' %}
|
||||
<span class="text-success">(cash)</span>
|
||||
{% else %}
|
||||
<a href="{{ route('accounts.show',journal.destination_account_id) }}">{{ journal.destination_account_name }}</a>
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
|
||||
</div>
|
||||
<div class="box-footer">
|
||||
<input type="submit" name="submit" value="{{ trans('form.delete_all_permanently') }}" class="btn btn-danger pull-right"/>
|
||||
<a href="{{ route('index') }}" class="btn-default btn">{{ trans('form.cancel') }}</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{ Form.close|raw }}
|
||||
{% endblock %}
|
Loading…
Reference in New Issue
Block a user