This commit is contained in:
James Cole 2020-02-07 20:51:25 +01:00
parent 0c13ac2e93
commit ac931698d3
No known key found for this signature in database
GPG Key ID: C16961E655E74B5E
6 changed files with 178 additions and 15 deletions

View File

@ -25,7 +25,9 @@ namespace FireflyIII\Http\Controllers\Transaction;
use FireflyIII\Http\Controllers\Controller;
use FireflyIII\Models\TransactionGroup;
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use FireflyIII\Services\Internal\Update\GroupCloneService;
/**
* Class CreateController
@ -34,6 +36,7 @@ class CreateController extends Controller
{
/**
* CreateController constructor.
*
* @codeCoverageIgnore
*/
public function __construct()
@ -55,6 +58,21 @@ class CreateController extends Controller
);
}
/**
* @param TransactionGroup $group
*
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
*/
public function cloneGroup(TransactionGroup $group)
{
/** @var GroupCloneService $service */
$service = app(GroupCloneService::class);
$newGroup = $service->cloneGroup($group);
return redirect(route('transactions.show', [$newGroup->id]));
}
/**
* Create a new transaction group.
*

View File

@ -0,0 +1,146 @@
<?php
/**
* GroupCloneService.php
* Copyright (c) 2019 thegrumpydictator@gmail.com
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace FireflyIII\Services\Internal\Update;
use Carbon\Carbon;
use FireflyIII\Models\Budget;
use FireflyIII\Models\Category;
use FireflyIII\Models\Note;
use FireflyIII\Models\Tag;
use FireflyIII\Models\Transaction;
use FireflyIII\Models\TransactionGroup;
use FireflyIII\Models\TransactionJournal;
use FireflyIII\Models\TransactionJournalMeta;
/**
* Class GroupCloneService
* TODO test.
*/
class GroupCloneService
{
/**
* @param TransactionGroup $group
*
* @return TransactionGroup
*/
public function cloneGroup(TransactionGroup $group): TransactionGroup
{
$newGroup = $group->replicate();
$newGroup->save();
foreach ($group->transactionJournals as $journal) {
$this->cloneJournal($journal, $newGroup, (int)$group->id);
}
return $newGroup;
}
/**
* @param TransactionJournal $journal
* @param TransactionGroup $newGroup
* @param int $originalGroup
*/
private function cloneJournal(TransactionJournal $journal, TransactionGroup $newGroup, int $originalGroup): void
{
$newJournal = $journal->replicate();
$newJournal->transaction_group_id = $newGroup->id;
$newJournal->date = Carbon::now();
$newJournal->save();
foreach ($journal->transactions as $transaction) {
$this->cloneTransaction($transaction, $newJournal);
}
// clone notes
/** @var Note $note */
foreach ($journal->notes as $note) {
$this->cloneNote($note, $newJournal, $originalGroup);
}
// clone location (not yet available)
// clone meta
/** @var TransactionJournalMeta $meta */
foreach ($journal->transactionJournalMeta as $meta) {
$this->cloneMeta($meta, $newJournal);
}
// clone category
/** @var Category $category */
foreach ($journal->categories as $category) {
$newJournal->categories()->save($category);
}
// clone budget
/** @var Budget $budget */
foreach ($journal->budgets as $budget) {
$newJournal->budgets()->save($budget);
}
// clone links (ongoing).
// clone tags
/** @var Tag $tag */
foreach ($journal->tags as $tag) {
$newJournal->tags()->save($tag);
}
// add note saying "cloned".
// add relation.
}
/**
* @param TransactionJournalMeta $meta
* @param TransactionJournal $newJournal
*/
private function cloneMeta(TransactionJournalMeta $meta, TransactionJournal $newJournal): void
{
$newMeta = $meta->replicate();
$newMeta->transaction_journal_id = $newJournal->id;
if ('recurrence_id' !== $newMeta->name) {
$newMeta->save();
}
}
private function cloneNote(Note $note, TransactionJournal $newJournal, int $oldGroupId): void
{
$newNote = $note->replicate();
$newNote->text .= sprintf(
"\n\n%s", trans('firefly.clones_journal_x', ['description' => $newJournal->description, 'id' => $oldGroupId])
);
$newNote->noteable_id = $newJournal->id;
$newNote->save();
}
/**
* @param Transaction $transaction
* @param TransactionJournal $newJournal
*/
private function cloneTransaction(Transaction $transaction, TransactionJournal $newJournal): void
{
$newTransaction = $transaction->replicate();
$newTransaction->transaction_journal_id = $newJournal->id;
$newTransaction->save();
}
}

View File

@ -27,8 +27,14 @@ $(function () {
makeAutoComplete();
})
$('[data-toggle="tooltip"]').tooltip();
$('#clone_button').click(cloneNewFunction);
});
function cloneNewFunction() {
return confirm(newCloneInstructions);
}
function getLinkModal(e) {
var button = $(e.currentTarget);
var journalId = parseInt(button.data('journal'));

View File

@ -58,7 +58,8 @@ return [
'no_rules_for_bill' => 'This bill has no rules associated to it.',
'go_to_asset_accounts' => 'View your asset accounts',
'go_to_budgets' => 'Go to your budgets',
'clone_instructions' => 'To clone a transaction, search for the "store as new" checkbox in the edit screen',
'new_clone_instructions' => 'This button will automatically clone the transaction and set the date to today. Are you sure?',
'clones_journal_x' => 'This transaction is a clone of ":description" (#:id)',
'go_to_categories' => 'Go to your categories',
'go_to_bills' => 'Go to your bills',
'go_to_expense_accounts' => 'See your expense accounts',

View File

@ -61,9 +61,8 @@
{% if groupArray.transactions[0].type != 'opening balance' and groupArray.transactions[0].type != 'reconciliation' %}
<!--CLONE-->
<a href="#" class="btn btn-default" style="white-space: nowrap;" onclick="return false;" data-toggle="tooltip" data-placement="top" title="{{ 'clone_instructions' |_|escape}}">Clone</a>
{#<a href="{{ route('transactions.clone', [transactionGroup.id]) }}" class="btn btn-default"><i class="fa fa-copy"></i> {{ 'clone'|_ }}</a>#}
<!-- since 5.1.0 -->
<a href="{{ route('transactions.clone', [transactionGroup.id]) }}" id="clone_button" class="btn btn-default"><i class="fa fa-copy"></i> {{ 'clone'|_ }}</a>
{% endif %}
{#
<a href="{{ route('transactions.delete', [transactionGroup.id]) }}" class="btn btn-danger"><i class="fa fa-trash"></i> {{ 'delete'|_ }}</a>
@ -415,6 +414,7 @@
var modalDialogURI = '{{ route('transactions.link.modal', ['%JOURNAL%']) }}';
var acURI = '{{ route('json.autocomplete.all-journals-with-id') }}';
var groupURI = '{{ route('transactions.show',['%GROUP%']) }}';
var newCloneInstructions = '{{ 'new_clone_instructions'|_|escape('js') }}';
</script>
<script type="text/javascript" src="v1/js/lib/typeahead/typeahead.bundle.min.js?v={{ FF_VERSION }}" nonce="{{ JS_NONCE }}"></script>
<script type="text/javascript" src="v1/js/ff/transactions/show.js?v={{ FF_VERSION }}" nonce="{{ JS_NONCE }}"></script>

View File

@ -963,6 +963,9 @@ Route::group(
Route::get('create/{objectType}', ['uses' => 'Transaction\CreateController@create', 'as' => 'create']);
Route::post('store', ['uses' => 'Transaction\CreateController@store', 'as' => 'store']);
// clone group
Route::get('clone/{transactionGroup}', ['uses' => 'Transaction\CreateController@cloneGroup', 'as' => 'clone']);
// edit group
Route::get('edit/{transactionGroup}', ['uses' => 'Transaction\EditController@edit', 'as' => 'edit']);
Route::post('update', ['uses' => 'Transaction\EditController@update', 'as' => 'update']);
@ -971,17 +974,6 @@ Route::group(
Route::get('delete/{transactionGroup}', ['uses' => 'Transaction\DeleteController@delete', 'as' => 'delete']);
Route::post('destroy/{transactionGroup}', ['uses' => 'Transaction\DeleteController@destroy', 'as' => 'destroy']);
// clone group:
//Route::get('clone/{transactionGroup}', ['uses' => 'Transaction\CloneController@clone', 'as' => 'clone']);
//Route::get('debug/{tj}', ['uses' => 'Transaction\SingleController@debugShow', 'as' => 'debug']);
//Route::get('debug/{tj}', ['uses' => 'Transaction\SingleController@debugShow', 'as' => 'debug']);
//Route::post('reorder', ['uses' => 'TransactionController@reorder', 'as' => 'reorder']);
//Route::post('reconcile', ['uses' => 'TransactionController@reconcile', 'as' => 'reconcile']);
// TODO end of improvement.
Route::get('show/{transactionGroup}', ['uses' => 'Transaction\ShowController@show', 'as' => 'show']);
}
);