mirror of
https://github.com/firefly-iii/firefly-iii.git
synced 2025-02-25 18:45:27 -06:00
Implemented new link thing.
This commit is contained in:
parent
63832b31f8
commit
6d34cfb940
@ -149,7 +149,42 @@ class AutoCompleteController extends Controller
|
||||
|
||||
|
||||
return response()->json($array);
|
||||
}
|
||||
|
||||
/**
|
||||
* Searches in the titles of all transaction journals.
|
||||
* The result is limited to the top 15 unique results.
|
||||
*
|
||||
* If the query is numeric, it will append the journal with that particular ID.
|
||||
*
|
||||
* @param Request $request
|
||||
* @return JsonResponse
|
||||
*/
|
||||
public function allJournalsWithID(Request $request): JsonResponse
|
||||
{
|
||||
$search = (string)$request->get('search');
|
||||
/** @var JournalRepositoryInterface $repository */
|
||||
$repository = app(JournalRepositoryInterface::class);
|
||||
$result = $repository->searchJournalDescriptions($search);
|
||||
$array = [];
|
||||
if (is_numeric($search)) {
|
||||
$firstResult = $repository->findNull((int)$search);
|
||||
if (null !== $firstResult) {
|
||||
$array[] = $firstResult->toArray();
|
||||
}
|
||||
}
|
||||
// if not numeric, search ahead!
|
||||
|
||||
// limit and unique
|
||||
$limited = $result->slice(0, 15);
|
||||
$array = array_merge($array, $limited->toArray());
|
||||
foreach ($array as $index => $item) {
|
||||
// give another key for consistency
|
||||
$array[$index]['name'] = sprintf('#%d: %s', $item['id'], $item['description']);
|
||||
}
|
||||
|
||||
|
||||
return response()->json($array);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -33,7 +33,8 @@ class EditController extends Controller
|
||||
{
|
||||
|
||||
/**
|
||||
* SingleController constructor.
|
||||
* EditController constructor.
|
||||
* @codeCoverageIgnore
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
@ -48,7 +49,7 @@ class EditController extends Controller
|
||||
|
||||
// some useful repositories:
|
||||
$this->middleware(
|
||||
function ($request, $next) {
|
||||
static function ($request, $next) {
|
||||
|
||||
app('view')->share('title', (string)trans('firefly.transactions'));
|
||||
app('view')->share('mainTitleIcon', 'fa-repeat');
|
||||
|
@ -28,6 +28,8 @@ use FireflyIII\Models\TransactionJournal;
|
||||
use FireflyIII\Models\TransactionJournalLink;
|
||||
use FireflyIII\Repositories\Journal\JournalRepositoryInterface;
|
||||
use FireflyIII\Repositories\LinkType\LinkTypeRepositoryInterface;
|
||||
use Illuminate\Contracts\View\Factory;
|
||||
use Illuminate\View\View;
|
||||
use Log;
|
||||
use URL;
|
||||
|
||||
@ -43,6 +45,7 @@ class LinkController extends Controller
|
||||
|
||||
/**
|
||||
* LinkController constructor.
|
||||
* @codeCoverageIgnore
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
@ -61,12 +64,23 @@ class LinkController extends Controller
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param TransactionJournal $journal
|
||||
* @return Factory|View
|
||||
*/
|
||||
public function modal(TransactionJournal $journal)
|
||||
{
|
||||
$linkTypes = $this->repository->get();
|
||||
|
||||
return view('transactions.links.modal', compact('journal', 'linkTypes'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a link.
|
||||
*
|
||||
* @param TransactionJournalLink $link
|
||||
*
|
||||
* @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
|
||||
* @return Factory|View
|
||||
*/
|
||||
public function delete(TransactionJournalLink $link)
|
||||
{
|
||||
@ -104,9 +118,9 @@ class LinkController extends Controller
|
||||
*/
|
||||
public function store(JournalLinkRequest $request, TransactionJournal $journal)
|
||||
{
|
||||
$linkInfo = $request->getLinkInfo();
|
||||
|
||||
Log::debug('We are here (store)');
|
||||
$linkInfo = $request->getLinkInfo();
|
||||
$other = $this->journalRepository->findNull($linkInfo['transaction_journal_id']);
|
||||
if (null === $other) {
|
||||
session()->flash('error', (string)trans('firefly.invalid_link_selection'));
|
||||
|
@ -73,7 +73,7 @@ class ShowController extends Controller
|
||||
$type = (string)trans(sprintf('firefly.%s', strtolower($first->transactionType->type)));
|
||||
$title = 1 === $splits ? $first->description : $transactionGroup->title;
|
||||
$subTitle = sprintf('%s: "%s"', $type, $title);
|
||||
$message = $request->get('message');
|
||||
$message = $request->get('message');
|
||||
|
||||
/** @var TransactionGroupTransformer $transformer */
|
||||
$transformer = app(TransactionGroupTransformer::class);
|
||||
@ -112,9 +112,9 @@ class ShowController extends Controller
|
||||
|
||||
return view(
|
||||
'transactions.show', compact(
|
||||
'transactionGroup', 'amounts', 'first', 'type', 'subTitle', 'splits', 'groupArray',
|
||||
'events', 'attachments', 'links','message'
|
||||
)
|
||||
'transactionGroup', 'amounts', 'first', 'type', 'subTitle', 'splits', 'groupArray',
|
||||
'events', 'attachments', 'links', 'message'
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
@ -52,12 +52,9 @@ class JournalLinkRequest extends Request
|
||||
$linkType = $this->get('link_type');
|
||||
$parts = explode('_', $linkType);
|
||||
$return['link_type_id'] = (int)$parts[0];
|
||||
$return['transaction_journal_id'] = $this->integer('link_journal_id');
|
||||
$return['transaction_journal_id'] = $this->integer('opposing');
|
||||
$return['notes'] = $this->string('notes');
|
||||
$return['direction'] = $parts[1];
|
||||
if (0 === $return['transaction_journal_id'] && ctype_digit($this->string('link_other'))) {
|
||||
$return['transaction_journal_id'] = $this->integer('link_other');
|
||||
}
|
||||
|
||||
return $return;
|
||||
}
|
||||
@ -81,8 +78,8 @@ class JournalLinkRequest extends Request
|
||||
|
||||
// fixed
|
||||
return [
|
||||
'link_type' => sprintf('required|in:%s', $string),
|
||||
'link_journal_id' => 'belongsToUser:transaction_journals',
|
||||
'link_type' => sprintf('required|in:%s', $string),
|
||||
'opposing' => 'belongsToUser:transaction_journals',
|
||||
];
|
||||
}
|
||||
}
|
||||
|
@ -174,14 +174,12 @@ class TransactionJournal extends Model
|
||||
*/
|
||||
public static function routeBinder(string $value): TransactionJournal
|
||||
{
|
||||
throw new FireflyException('Journal binder is permanently out of order.');
|
||||
if (auth()->check()) {
|
||||
$journalId = (int)$value;
|
||||
/** @var User $user */
|
||||
$user = auth()->user();
|
||||
/** @var TransactionJournal $journal */
|
||||
$journal = $user->transactionJournals()->where('transaction_journals.id', $journalId)
|
||||
->first(['transaction_journals.*']);
|
||||
$journal = $user->transactionJournals()->where('transaction_journals.id', $journalId)->first(['transaction_journals.*']);
|
||||
if (null !== $journal) {
|
||||
return $journal;
|
||||
}
|
||||
|
@ -119,6 +119,7 @@ class TransactionGroupRepository implements TransactionGroupRepositoryInterface
|
||||
$amount = $this->getFormattedAmount($entry->destination);
|
||||
$foreignAmount = $this->getFormattedForeignAmount($entry->destination);
|
||||
$return[$journalId][] = [
|
||||
'id' => $entry->id,
|
||||
'link' => $entry->outward,
|
||||
'group' => $entry->destination->transaction_group_id,
|
||||
'description' => $entry->destination->description,
|
||||
@ -130,6 +131,7 @@ class TransactionGroupRepository implements TransactionGroupRepositoryInterface
|
||||
$amount = $this->getFormattedAmount($entry->source);
|
||||
$foreignAmount = $this->getFormattedForeignAmount($entry->source);
|
||||
$return[$journalId][] = [
|
||||
'id' => $entry->id,
|
||||
'link' => $entry->inward,
|
||||
'group' => $entry->source->transaction_group_id,
|
||||
'description' => $entry->source->description,
|
||||
@ -145,7 +147,7 @@ class TransactionGroupRepository implements TransactionGroupRepositoryInterface
|
||||
/**
|
||||
* Return object with all found meta field things as Carbon objects.
|
||||
*
|
||||
* @param int $journalId
|
||||
* @param int $journalId
|
||||
* @param array $fields
|
||||
*
|
||||
* @return NullArrayObject
|
||||
@ -171,7 +173,7 @@ class TransactionGroupRepository implements TransactionGroupRepositoryInterface
|
||||
/**
|
||||
* Return object with all found meta field things.
|
||||
*
|
||||
* @param int $journalId
|
||||
* @param int $journalId
|
||||
* @param array $fields
|
||||
*
|
||||
* @return NullArrayObject
|
||||
@ -247,9 +249,9 @@ class TransactionGroupRepository implements TransactionGroupRepositoryInterface
|
||||
$return[$journalId] = $return[$journalId] ?? [];
|
||||
|
||||
$return[$journalId][] = [
|
||||
'piggy' => $row->piggyBank->name,
|
||||
'piggy' => $row->piggyBank->name,
|
||||
'piggy_id' => $row->piggy_bank_id,
|
||||
'amount' => app('amount')->formatAnything($currency, $row->amount),
|
||||
'amount' => app('amount')->formatAnything($currency, $row->amount),
|
||||
];
|
||||
}
|
||||
|
||||
@ -300,7 +302,7 @@ class TransactionGroupRepository implements TransactionGroupRepositoryInterface
|
||||
|
||||
/**
|
||||
* @param TransactionGroup $transactionGroup
|
||||
* @param array $data
|
||||
* @param array $data
|
||||
*
|
||||
* @return TransactionGroup
|
||||
*
|
||||
|
@ -214,10 +214,6 @@ return [
|
||||
'application/vnd.oasis.opendocument.image',
|
||||
],
|
||||
'list_length' => 10,
|
||||
'export_formats' => [
|
||||
'csv' => CsvExporter::class,
|
||||
],
|
||||
'default_export_format' => 'csv',
|
||||
'default_import_format' => 'csv',
|
||||
'bill_periods' => ['weekly', 'monthly', 'quarterly', 'half-year', 'yearly'],
|
||||
'accountRoles' => ['defaultAsset', 'sharedAsset', 'savingAsset', 'ccAsset', 'cashWalletAsset'],
|
||||
@ -381,7 +377,6 @@ return [
|
||||
'recurrence' => Recurrence::class,
|
||||
'rule' => Rule::class,
|
||||
'ruleGroup' => RuleGroup::class,
|
||||
'exportJob' => ExportJob::class,
|
||||
'importJob' => ImportJob::class,
|
||||
'transaction' => Transaction::class,
|
||||
'transactionGroup' => TransactionGroup::class,
|
||||
|
57
public/v1/js/ff/transactions/show.js
vendored
57
public/v1/js/ff/transactions/show.js
vendored
@ -22,5 +22,60 @@
|
||||
|
||||
$(function () {
|
||||
"use strict";
|
||||
$('.link-modal').click(getLinkModal);
|
||||
$('#linkJournalModal').on('shown.bs.modal', function () {
|
||||
makeAutoComplete();
|
||||
})
|
||||
});
|
||||
|
||||
});
|
||||
function getLinkModal(e) {
|
||||
var button = $(e.currentTarget);
|
||||
var journalId = parseInt(button.data('journal'));
|
||||
var url = modalDialogURI.replace('%JOURNAL%', journalId);
|
||||
console.log(url);
|
||||
$.get(url).done(function (data) {
|
||||
$('#linkJournalModal').html(data).modal('show');
|
||||
|
||||
}).fail(function () {
|
||||
alert('Could not load the data to link journals. Sorry :(');
|
||||
button.prop('disabled', true);
|
||||
});
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
function makeAutoComplete() {
|
||||
|
||||
// input link-journal
|
||||
var source = new Bloodhound({
|
||||
datumTokenizer: Bloodhound.tokenizers.obj.whitespace('name'),
|
||||
queryTokenizer: Bloodhound.tokenizers.whitespace,
|
||||
prefetch: {
|
||||
url: acURI + '?uid=' + uid,
|
||||
filter: function (list) {
|
||||
return $.map(list, function (item) {
|
||||
return item;
|
||||
});
|
||||
}
|
||||
},
|
||||
remote: {
|
||||
url: acURI + '?search=%QUERY&uid=' + uid,
|
||||
wildcard: '%QUERY',
|
||||
filter: function (list) {
|
||||
return $.map(list, function (item) {
|
||||
return item;
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
source.initialize();
|
||||
$('.link-journal').typeahead({hint: true, highlight: true,}, {source: source, displayKey: 'name', autoSelect: false})
|
||||
.on('typeahead:select', selectedJournal);
|
||||
}
|
||||
|
||||
function selectedJournal(event, journal) {
|
||||
$('#journal-selector').hide();
|
||||
$('#journal-selection').show();
|
||||
$('#selected-journal').html('<a href="' + groupURI.replace('%GROUP%', journal.transaction_group_id) + '">' + journal.description + '</a>').show();
|
||||
$('input[name="opposing"]').val(journal.id);
|
||||
}
|
@ -1215,12 +1215,13 @@ return [
|
||||
'do_not_save_connection' => '(do not save connection)',
|
||||
'link_transaction' => 'Link transaction',
|
||||
'link_to_other_transaction' => 'Link this transaction to another transaction',
|
||||
'select_transaction_to_link' => 'Select a transaction to link this transaction to',
|
||||
'select_transaction_to_link' => 'Select a transaction to link this transaction to. The links are currently unused in Firefly III (apart from being shown), but I plan to change this in the future. Use the search box to select a transaction either by title or by ID. If you want to add custom link types, check out the administration section.',
|
||||
'this_transaction' => 'This transaction',
|
||||
'transaction' => 'Transaction',
|
||||
'comments' => 'Comments',
|
||||
'to_link_not_found' => 'If the transaction you want to link to is not listed, simply enter its ID.',
|
||||
'link_notes' => 'Any notes you wish to store with the link.',
|
||||
'invalid_link_selection' => 'Cannot link these transactions',
|
||||
'selected_transaction' => 'Selected transaction',
|
||||
'journals_linked' => 'Transactions are linked.',
|
||||
'journals_error_linked' => 'These transactions are already linked.',
|
||||
'journals_link_to_self' => 'You cannot link a transaction to itself',
|
||||
|
52
resources/views/v1/transactions/links/modal.twig
Normal file
52
resources/views/v1/transactions/links/modal.twig
Normal file
@ -0,0 +1,52 @@
|
||||
<form action="{{ route('transactions.link.store', [journal.id]) }}" method="post" class="form-horizontal">
|
||||
<input type="hidden" name="_token" value="{{ csrf_token() }}">
|
||||
<input type="hidden" name="opposing" value="">
|
||||
<div class="modal-dialog modal-lg">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h4 class="modal-title">{{ 'link_to_other_transaction'|_ }}</h4>
|
||||
</div>
|
||||
<div class="modal-body" id="helpBody">
|
||||
<p>{{ 'select_transaction_to_link'|_ }}</p>
|
||||
<div class="form-group">
|
||||
<label for="link_type" class="col-sm-4 control-label">{{ 'this_transaction'|_ }}</label>
|
||||
<div class="col-sm-8">
|
||||
<select id="link_type" class="form-control" name="link_type">
|
||||
{% for linkType in linkTypes %}
|
||||
<option label="{{ journalLinkTranslation('inward', linkType.inward) }}"
|
||||
value="{{ linkType.id }}_inward">{{ journalLinkTranslation('inward', linkType.inward) }}</option>
|
||||
<option label="{{ journalLinkTranslation('outward', linkType.outward) }}"
|
||||
value="{{ linkType.id }}_outward">{{ journalLinkTranslation('outward', linkType.outward) }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group" id="journal-selection">
|
||||
<label for="selected" class="col-sm-4 control-label">{{ 'selected_transaction'|_ }}</label>
|
||||
<div class="col-sm-8">
|
||||
<p class="form-control-static" id="selected-journal">
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group" id="journal-selector">
|
||||
<label for="link_other" class="col-sm-4 control-label">{{ 'transaction'|_ }}</label>
|
||||
<div class="col-sm-8">
|
||||
<input type="text" name="link_other" autocomplete="off" id="link_other" value="" class="form-control link-journal">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="notes" class="col-sm-4 control-label">{{ 'link_notes'|_ }}</label>
|
||||
<div class="col-sm-8">
|
||||
<textarea id="notes" name="notes" class="form-control"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-default" data-dismiss="modal">{{ 'close'|_ }}</button>
|
||||
<button type="submit" class="btn btn-primary">{{ 'submit'|_ }}</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
@ -6,18 +6,18 @@
|
||||
|
||||
{% block content %}
|
||||
{% if message == 'created' %}
|
||||
<div class="row">
|
||||
<div class="col-lg-12">
|
||||
<div class="alert alert-success alert-dismissible" role="alert">
|
||||
<button type="button" class="close" data-dismiss="alert">
|
||||
<span>×</span><span class="sr-only">{{ 'close'|_ }}</span>
|
||||
</button>
|
||||
<strong>{{ 'flash_success'|_ }}</strong>
|
||||
{{ trans('firefly.stored_journal_no_descr') }}
|
||||
<div class="row">
|
||||
<div class="col-lg-12">
|
||||
<div class="alert alert-success alert-dismissible" role="alert">
|
||||
<button type="button" class="close" data-dismiss="alert">
|
||||
<span>×</span><span class="sr-only">{{ 'close'|_ }}</span>
|
||||
</button>
|
||||
<strong>{{ 'flash_success'|_ }}</strong>
|
||||
{{ trans('firefly.stored_journal_no_descr') }}
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if message == 'updated' %}
|
||||
@ -69,335 +69,362 @@
|
||||
</div>
|
||||
<div class="box-footer">
|
||||
<div class="btn-group btn-group-xs">
|
||||
<a href="{{ route('transactions.edit', [transactionGroup.id]) }}" class="btn btn-default"><i class="fa fa-pencil"></i> {{ 'edit'|_ }}</a>
|
||||
<a href="{{ route('transactions.edit', [transactionGroup.id]) }}" class="btn btn-default"><i class="fa fa-pencil"></i> {{ 'edit'|_ }}
|
||||
</a>
|
||||
|
||||
{% if groupArray.transactions[0].type != 'withdrawal' %}
|
||||
<a href="{{ route('transactions.convert.index', ['withdrawal', transactionGroup.id]) }}" class="btn btn-default"><i class="fa fa-exchange"></i> {{ 'convert_to_withdrawal'|_ }}</a>
|
||||
<a href="{{ route('transactions.convert.index', ['withdrawal', transactionGroup.id]) }}" class="btn btn-default"><i
|
||||
class="fa fa-exchange"></i> {{ 'convert_to_withdrawal'|_ }}</a>
|
||||
{% endif %}
|
||||
|
||||
{% if groupArray.transactions[0].type != 'deposit' %}
|
||||
<a href="{{ route('transactions.convert.index', ['deposit', transactionGroup.id]) }}" class="btn btn-default"><i class="fa fa-exchange"></i> {{ 'convert_to_deposit'|_ }}</a>
|
||||
<a href="{{ route('transactions.convert.index', ['deposit', transactionGroup.id]) }}" class="btn btn-default"><i
|
||||
class="fa fa-exchange"></i> {{ 'convert_to_deposit'|_ }}</a>
|
||||
{% endif %}
|
||||
|
||||
{% if groupArray.transactions[0].type != 'transfer' %}
|
||||
<a href="{{ route('transactions.convert.index', ['transfer', transactionGroup.id]) }}" class="btn btn-default"><i class="fa fa-exchange"></i> {{ 'convert_to_transfer'|_ }}</a>
|
||||
<a href="{{ route('transactions.convert.index', ['transfer', transactionGroup.id]) }}" class="btn btn-default"><i
|
||||
class="fa fa-exchange"></i> {{ 'convert_to_transfer'|_ }}</a>
|
||||
{% endif %}
|
||||
|
||||
|
||||
{% if groupArray.transactions[0].type != 'opening balance' and groupArray.transactions[0].type != 'reconciliation' %}
|
||||
CLONE
|
||||
{#<a href="{{ route('transactions.clone', [transactionGroup.id]) }}" class="btn btn-default"><i class="fa fa-copy"></i> {{ 'clone'|_ }}</a>#}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{#
|
||||
<a href="{{ route('transactions.delete', [transactionGroup.id]) }}" class="btn btn-danger"><i class="fa fa-trash"></i> {{ 'delete'|_ }}</a>
|
||||
#}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-6">
|
||||
<div class="box box-primary">
|
||||
<div class="box-header with-border">
|
||||
<h3 class="box-title">{{ 'transaction_journal_meta'|_ }}</h3>
|
||||
</div>
|
||||
<div class="box-body no-padding">
|
||||
<table class="table table-hover">
|
||||
<tbody>
|
||||
{% if type != 'Withdrawal' or splits == 1 %}
|
||||
<tr>
|
||||
<td>
|
||||
{{ 'source_accounts'|_ }}
|
||||
</td>
|
||||
<td>
|
||||
{% for journal in groupArray.transactions %}
|
||||
<a href="{{ route('accounts.show',journal.source_id) }}"
|
||||
title="{{ journal.source_iban|default(journal.source_name) }}">
|
||||
{{ journal.source_name }}
|
||||
</a>
|
||||
{% if loop.index0 != groupArray.transactions|length -1 %}, {% endif %}
|
||||
{% endfor %}
|
||||
</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
|
||||
{% if type != 'Deposit' or splits == 1 %}
|
||||
<tr>
|
||||
<td>
|
||||
{{ 'destination_accounts'|_ }}
|
||||
|
||||
</td>
|
||||
<td>
|
||||
{% for journal in groupArray.transactions %}
|
||||
<a href="{{ route('accounts.show',journal.source_id) }}"
|
||||
title="{{ journal.destination_iban|default(journal.destination_name) }}">
|
||||
{{ journal.destination_name }}
|
||||
</a>
|
||||
{% if loop.index0 != groupArray.transactions|length -1 %}, {% endif %}
|
||||
{% endfor %}
|
||||
</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
<tr>
|
||||
<td style="width:30%;">{{ 'total_amount'|_ }}</td>
|
||||
<td>
|
||||
{% for amount in amounts %}
|
||||
{% if type == 'Withdrawal' or type == 'Deposit' %}
|
||||
{{ formatAmountBySymbol(amount.amount*-1,amount.symbol, amount.decimal_places) }},
|
||||
{% elseif type == 'Transfer' %}
|
||||
<span class="text-info">
|
||||
{{ formatAmountBySymbol(amount.amount, amount.symbol, amount.decimal_places, false) }},
|
||||
</span>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
|
||||
</div>
|
||||
{% if splits > 1 %}
|
||||
<div class="row">
|
||||
<div class="col-lg-12">
|
||||
<h3>{{ 'splits'|_ }}</h3>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% set boxSize=12 %}
|
||||
{% if(splits == 2) %}
|
||||
{% set boxSize=6 %}
|
||||
{% endif %}
|
||||
{% if (splits > 2) %}
|
||||
{% set boxSize = 4 %}
|
||||
{% endif %}
|
||||
<div class="row">
|
||||
{% for index,journal in groupArray.transactions %}
|
||||
<div class="col-lg-{{ boxSize }}">
|
||||
<div class="box">
|
||||
<div class="col-lg-6">
|
||||
<div class="box box-primary">
|
||||
<div class="box-header with-border">
|
||||
<h3 class="box-title">
|
||||
{{ journal.description }}
|
||||
{% if journal.reconciled %}
|
||||
<i class="fa fa-check"></i>
|
||||
{% endif %}
|
||||
{% if splits > 1 %}
|
||||
<small>
|
||||
{{ index+1 }} / {{ splits }}
|
||||
</small>
|
||||
{% endif %}
|
||||
</h3>
|
||||
<h3 class="box-title">{{ 'transaction_journal_meta'|_ }}</h3>
|
||||
</div>
|
||||
<div class="box-body no-padding">
|
||||
<table class="table">
|
||||
<tr>
|
||||
<td colspan="2">
|
||||
<a href="{{ route('accounts.show', journal.source_id) }}"
|
||||
title="{{ journal.source_iban|default(journal.source_name) }}">{{ journal.source_name }}</a> →
|
||||
{% if type == 'Withdrawal' or type == 'Deposit' %}
|
||||
{{ formatAmountBySymbol(journal.amount*-1, journal.currency_symbol, journal.currency_decimal_places) }}
|
||||
{% elseif type == 'Transfer' %}
|
||||
<span class="text-info">
|
||||
{{ formatAmountBySymbol(journal.amount, journal.currency_symbol, journal.currency_decimal_places, false) }}
|
||||
</span>
|
||||
{% endif %}
|
||||
|
||||
<!-- do foreign amount -->
|
||||
{% if null != journal.foreign_amount %}
|
||||
{% if type == 'Withdrawal' or type == 'Deposit' %}
|
||||
({{ formatAmountBySymbol(journal.foreign_amount*-1, journal.foreign_currency_symbol, journal.foreign_currency_decimal_places) }})
|
||||
{% elseif type == 'Transfer' %}
|
||||
<span class="text-info">
|
||||
({{ formatAmountBySymbol(journal.foreign_amount, journal.foreign_currency_symbol, journal.foreign_currency_decimal_places, false) }})
|
||||
</span>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
|
||||
→
|
||||
<a href="{{ route('accounts.show', journal.destination_id) }}"
|
||||
title="{{ journal.destination_iban|default(journal.destination_name) }}">{{ journal.destination_name }}</a>
|
||||
</td>
|
||||
</tr>
|
||||
{% if null != journal.category_id %}
|
||||
<table class="table table-hover">
|
||||
<tbody>
|
||||
{% if type != 'Withdrawal' or splits == 1 %}
|
||||
<tr>
|
||||
<td style="width:30%;">{{ 'category'|_ }}</td>
|
||||
<td><a href="{{ route('categories.show', [journal.category_id]) }}">{{ journal.category_name }}</a></td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
{% if null != journal.budget_id and type == 'Withdrawal' %}
|
||||
<tr>
|
||||
<td>{{ 'budget'|_ }}</td>
|
||||
<td><a href="{{ route('budgets.show', [journal.budget_id]) }}">{{ journal.budget_name }}</a></td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
{% if null != journal.bill_id and type == 'Withdrawal' %}
|
||||
<tr>
|
||||
<td>{{ 'bill'|_ }}</td>
|
||||
<td><a href="{{ route('bills.show', [journal.bill_id]) }}">{{ journal.bill_name }}</a></td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
<!-- other fields -->
|
||||
{% for dateField in ['interest_date','book_date','process_date','due_date','payment_date','invoice_date'] %}
|
||||
{% if journalHasMeta(journal.transaction_journal_id, dateField) %}
|
||||
<tr>
|
||||
<td>{{ trans('list.'~dateField) }}</td>
|
||||
<td>{{ journalGetMetaDate(journal.transaction_journal_id, dateField).formatLocalized(monthAndDayFormat) }}</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% for metaField in ['external_id','bunq_payment_id','internal_reference','sepa_batch_id','sepa_ct_id','sepa_ct_op','sepa_db','sepa_country','sepa_cc','sepa_ep','sepa_ci'] %}
|
||||
{% if journalHasMeta(journal.transaction_journal_id, metaField) %}
|
||||
<tr>
|
||||
<td>{{ trans('list.'~metaField) }}</td>
|
||||
<td>{{ journalGetMetaField(journal.transaction_journal_id, metaField) }}</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% if null != journal.notes and '' != journal.notes %}
|
||||
<tr>
|
||||
<td>{{ trans('list.notes') }}</td>
|
||||
<td class="markdown">{{ journal.notes|markdown }}</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
{% if journal.tags|length > 0 %}
|
||||
<tr>
|
||||
<td>{{ 'tags'|_ }}</td>
|
||||
<td>
|
||||
{% for tag in journal.tags %}
|
||||
<h4 style="display: inline;"><a class="label label-success" href="{{ route('tags.show', tag) }}">
|
||||
<i class="fa fa-fw fa-tag"></i>
|
||||
{{ tag }}</a>
|
||||
</h4>
|
||||
{{ 'source_accounts'|_ }}
|
||||
</td>
|
||||
<td>
|
||||
{% for journal in groupArray.transactions %}
|
||||
<a href="{{ route('accounts.show',journal.source_id) }}"
|
||||
title="{{ journal.source_iban|default(journal.source_name) }}">
|
||||
{{ journal.source_name }}
|
||||
</a>
|
||||
{% if loop.index0 != groupArray.transactions|length -1 %}, {% endif %}
|
||||
{% endfor %}
|
||||
</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
|
||||
{% if type != 'Deposit' or splits == 1 %}
|
||||
<tr>
|
||||
<td>
|
||||
{{ 'destination_accounts'|_ }}
|
||||
|
||||
</td>
|
||||
<td>
|
||||
{% for journal in groupArray.transactions %}
|
||||
<a href="{{ route('accounts.show',journal.source_id) }}"
|
||||
title="{{ journal.destination_iban|default(journal.destination_name) }}">
|
||||
{{ journal.destination_name }}
|
||||
</a>
|
||||
{% if loop.index0 != groupArray.transactions|length -1 %}, {% endif %}
|
||||
{% endfor %}
|
||||
</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
<tr>
|
||||
<td style="width:30%;">{{ 'total_amount'|_ }}</td>
|
||||
<td>
|
||||
{% for amount in amounts %}
|
||||
{% if type == 'Withdrawal' or type == 'Deposit' %}
|
||||
{{ formatAmountBySymbol(amount.amount*-1,amount.symbol, amount.decimal_places) }},
|
||||
{% elseif type == 'Transfer' %}
|
||||
<span class="text-info">
|
||||
{{ formatAmountBySymbol(amount.amount, amount.symbol, amount.decimal_places, false) }},
|
||||
</span>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
|
||||
<!-- Transaction links -->
|
||||
{% if links[journal.transaction_journal_id]|length > 0 %}
|
||||
</div>
|
||||
{% if splits > 1 %}
|
||||
<div class="row">
|
||||
<div class="col-lg-12">
|
||||
<h3>{{ 'splits'|_ }}</h3>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% set boxSize=6 %}
|
||||
{% if(splits == 2) %}
|
||||
{% set boxSize=6 %}
|
||||
{% endif %}
|
||||
{% if (splits > 2) %}
|
||||
{% set boxSize = 4 %}
|
||||
{% endif %}
|
||||
<div class="row">
|
||||
{% for index,journal in groupArray.transactions %}
|
||||
<div class="col-lg-{{ boxSize }}">
|
||||
<div class="box">
|
||||
<div class="box-header with-border">
|
||||
<h3 class="box-title">
|
||||
{{ 'journal_links'|_ }}
|
||||
{{ journal.description }}
|
||||
{% if journal.reconciled %}
|
||||
<i class="fa fa-check"></i>
|
||||
{% endif %}
|
||||
{% if splits > 1 %}
|
||||
<small>
|
||||
{{ index+1 }} / {{ splits }}
|
||||
</small>
|
||||
{% endif %}
|
||||
</h3>
|
||||
</div>
|
||||
<div class="box-body no-padding">
|
||||
<table class="table">
|
||||
{% for link in links[journal.transaction_journal_id] %}
|
||||
<tr>
|
||||
<td style="width:30%;">
|
||||
<div class="btn-group btn-group-xs">
|
||||
<a href="#" class="btn btn-default"><i class="fa fa-pencil"></i></a>
|
||||
<a href="#" class="btn btn-danger"><i class="fa fa-trash"></i></a>
|
||||
</div>
|
||||
</td>
|
||||
<td>{{ link.link }} "<a href="{{ route('transactions.show', link.group) }}"
|
||||
title="{{ link.description }}">{{ link.description }}</a>"
|
||||
<tr>
|
||||
<td colspan="2">
|
||||
<a href="{{ route('accounts.show', journal.source_id) }}"
|
||||
title="{{ journal.source_iban|default(journal.source_name) }}">{{ journal.source_name }}</a> →
|
||||
{% if type == 'Withdrawal' or type == 'Deposit' %}
|
||||
{{ formatAmountBySymbol(journal.amount*-1, journal.currency_symbol, journal.currency_decimal_places) }}
|
||||
{% elseif type == 'Transfer' %}
|
||||
<span class="text-info">
|
||||
{{ formatAmountBySymbol(journal.amount, journal.currency_symbol, journal.currency_decimal_places, false) }}
|
||||
</span>
|
||||
{% endif %}
|
||||
|
||||
({{ link.amount|raw }})
|
||||
{% if '' != link.foreign_amount %}
|
||||
({{ link.foreign_amount|raw }})
|
||||
<!-- do foreign amount -->
|
||||
{% if null != journal.foreign_amount %}
|
||||
{% if type == 'Withdrawal' or type == 'Deposit' %}
|
||||
({{ formatAmountBySymbol(journal.foreign_amount*-1, journal.foreign_currency_symbol, journal.foreign_currency_decimal_places) }})
|
||||
{% elseif type == 'Transfer' %}
|
||||
<span class="text-info">
|
||||
({{ formatAmountBySymbol(journal.foreign_amount, journal.foreign_currency_symbol, journal.foreign_currency_decimal_places, false) }})
|
||||
</span>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
|
||||
→
|
||||
<a href="{{ route('accounts.show', journal.destination_id) }}"
|
||||
title="{{ journal.destination_iban|default(journal.destination_name) }}">{{ journal.destination_name }}</a>
|
||||
</td>
|
||||
</tr>
|
||||
{% if null != journal.category_id %}
|
||||
<tr>
|
||||
<td style="width:30%;">{{ 'category'|_ }}</td>
|
||||
<td><a href="{{ route('categories.show', [journal.category_id]) }}">{{ journal.category_name }}</a></td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
{% if null != journal.budget_id and type == 'Withdrawal' %}
|
||||
<tr>
|
||||
<td>{{ 'budget'|_ }}</td>
|
||||
<td><a href="{{ route('budgets.show', [journal.budget_id]) }}">{{ journal.budget_name }}</a></td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
{% if null != journal.bill_id and type == 'Withdrawal' %}
|
||||
<tr>
|
||||
<td>{{ 'bill'|_ }}</td>
|
||||
<td><a href="{{ route('bills.show', [journal.bill_id]) }}">{{ journal.bill_name }}</a></td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
<!-- other fields -->
|
||||
{% for dateField in ['interest_date','book_date','process_date','due_date','payment_date','invoice_date'] %}
|
||||
{% if journalHasMeta(journal.transaction_journal_id, dateField) %}
|
||||
<tr>
|
||||
<td>{{ trans('list.'~dateField) }}</td>
|
||||
<td>{{ journalGetMetaDate(journal.transaction_journal_id, dateField).formatLocalized(monthAndDayFormat) }}</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% for metaField in ['external_id','bunq_payment_id','internal_reference','sepa_batch_id','sepa_ct_id','sepa_ct_op','sepa_db','sepa_country','sepa_cc','sepa_ep','sepa_ci'] %}
|
||||
{% if journalHasMeta(journal.transaction_journal_id, metaField) %}
|
||||
<tr>
|
||||
<td>{{ trans('list.'~metaField) }}</td>
|
||||
<td>{{ journalGetMetaField(journal.transaction_journal_id, metaField) }}</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% if null != journal.notes and '' != journal.notes %}
|
||||
<tr>
|
||||
<td>{{ trans('list.notes') }}</td>
|
||||
<td class="markdown">{{ journal.notes|markdown }}</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
{% if journal.tags|length > 0 %}
|
||||
<tr>
|
||||
<td>{{ 'tags'|_ }}</td>
|
||||
<td>
|
||||
{% for tag in journal.tags %}
|
||||
<h4 style="display: inline;"><a class="label label-success" href="{{ route('tags.show', tag) }}">
|
||||
<i class="fa fa-fw fa-tag"></i>
|
||||
{{ tag }}</a>
|
||||
</h4>
|
||||
{% endfor %}
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
|
||||
{% endif %}
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<!-- Attachments -->
|
||||
{% if attachments[journal.transaction_journal_id]|length > 0 %}
|
||||
<div class="box">
|
||||
<div class="box-header with-border">
|
||||
<h3 class="box-title">{{ 'attachments'|_ }}</h3>
|
||||
<div class="box-footer">
|
||||
<div class="btn-group btn-group-xs">
|
||||
<a href="#" class="btn btn-default link-modal" data-journal="{{ journal.transaction_journal_id }}">
|
||||
<i class="fa fa-fw fa-link"></i>
|
||||
{{ 'link_transaction'|_ }}
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="box-body table-responsive no-padding">
|
||||
<table class="table table-hover">
|
||||
{% for attachment in attachments[journal.transaction_journal_id] %}
|
||||
<tr>
|
||||
<td style="width:30%;">
|
||||
<div class="btn-group btn-group-xs">
|
||||
<a href="{{ route('attachments.edit', attachment.id) }}" class="btn btn-default"><i
|
||||
class="fa fa-pencil"></i></a>
|
||||
<a href="{{ route('attachments.delete', attachment.id) }}" class="btn btn-danger"><i
|
||||
class="fa fa-trash"></i></a>
|
||||
</div>
|
||||
|
||||
<!-- Transaction links -->
|
||||
{% if links[journal.transaction_journal_id]|length > 0 %}
|
||||
<div class="box">
|
||||
<div class="box-header with-border">
|
||||
<h3 class="box-title">
|
||||
{{ 'journal_links'|_ }}
|
||||
</h3>
|
||||
</div>
|
||||
<div class="box-body no-padding">
|
||||
<table class="table">
|
||||
{% for link in links[journal.transaction_journal_id] %}
|
||||
<tr>
|
||||
<td style="width:120px;">
|
||||
<div class="btn-group btn-group-xs">
|
||||
<a href="{{ route('transactions.link.switch', [link.id]) }}" class="btn btn-default"><i class="fa fa-fw fa-arrows-h"></i></a>
|
||||
<a href="{{ route('transactions.link.delete', [link.id]) }}" class="btn btn-danger"><i class="fa fa-trash"></i></a>
|
||||
</div>
|
||||
</td>
|
||||
<td>{{ link.link }} "<a href="{{ route('transactions.show', link.group) }}"
|
||||
title="{{ link.description }}">{{ link.description }}</a>"
|
||||
|
||||
({{ link.amount|raw }})
|
||||
{% if '' != link.foreign_amount %}
|
||||
({{ link.foreign_amount|raw }})
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<!-- Attachments -->
|
||||
{% if attachments[journal.transaction_journal_id]|length > 0 %}
|
||||
<div class="box">
|
||||
<div class="box-header with-border">
|
||||
<h3 class="box-title">{{ 'attachments'|_ }}</h3>
|
||||
</div>
|
||||
<div class="box-body table-responsive no-padding">
|
||||
<table class="table table-hover">
|
||||
{% for attachment in attachments[journal.transaction_journal_id] %}
|
||||
<tr>
|
||||
<td style="width:120px;">
|
||||
<div class="btn-group btn-group-xs">
|
||||
<a href="{{ route('attachments.edit', attachment.id) }}" class="btn btn-default"><i
|
||||
class="fa fa-pencil"></i></a>
|
||||
<a href="{{ route('attachments.delete', attachment.id) }}" class="btn btn-danger"><i
|
||||
class="fa fa-trash"></i></a>
|
||||
{% if attachment.file_exists %}
|
||||
<a href="{{ route('attachments.download', attachment.id) }}" class="btn btn-default"><i
|
||||
class="fa fa-download"></i></a>
|
||||
{% endif %}
|
||||
{% if not attachment.file_exists %}
|
||||
<a href="#" class="btn btn-danger"><i class="fa fa-exclamation-triangle"></i></a>
|
||||
{% endif %}
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
{% if attachment.file_exists %}
|
||||
<a href="{{ route('attachments.download', attachment.id) }}" class="btn btn-default"><i
|
||||
class="fa fa-download"></i></a>
|
||||
<i class="fa {{ attachment.mime|mimeIcon }}"></i>
|
||||
<a href="{{ route('attachments.view', attachment.id) }}" title="{{ attachment.filename }}">
|
||||
{% if attachment.title %}
|
||||
{{ attachment.title }}
|
||||
{% else %}
|
||||
{{ attachment.filename }}
|
||||
{% endif %}
|
||||
</a>
|
||||
({{ attachment.size|filesize }})
|
||||
{% if null != attachment.notes and '' != attachment.notes %}
|
||||
{{ attachment.notes|markdown }}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% if not attachment.file_exists %}
|
||||
<a href="#" class="btn btn-danger"><i class="fa fa-exclamation-triangle"></i></a>
|
||||
{% endif %}
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
{% if attachment.file_exists %}
|
||||
<i class="fa {{ attachment.mime|mimeIcon }}"></i>
|
||||
<a href="{{ route('attachments.view', attachment.id) }}" title="{{ attachment.filename }}">
|
||||
<i class="fa fa-fw fa-exclamation-triangle"></i>
|
||||
{% if attachment.title %}
|
||||
{{ attachment.title }}
|
||||
{% else %}
|
||||
{{ attachment.filename }}
|
||||
{% endif %}
|
||||
</a>
|
||||
({{ attachment.size|filesize }})
|
||||
{% if null != attachment.notes and '' != attachment.notes %}
|
||||
{{ attachment.notes|markdown }}
|
||||
<br>
|
||||
<span class="text-danger">{{ 'attachment_not_found'|_ }}</span>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% if not attachment.file_exists %}
|
||||
<i class="fa fa-fw fa-exclamation-triangle"></i>
|
||||
{% if attachment.title %}
|
||||
{{ attachment.title }}
|
||||
{% else %}
|
||||
{{ attachment.filename }}
|
||||
{% endif %}
|
||||
<br>
|
||||
<span class="text-danger">{{ 'attachment_not_found'|_ }}</span>
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
<!-- Piggy bank events -->
|
||||
{% if events[journal.transaction_journal_id]|length > 0 %}
|
||||
<div class="box">
|
||||
<div class="box-header with-border">
|
||||
<h3 class="box-title">{{ 'piggy_events'|_ }}</h3>
|
||||
<!-- Piggy bank events -->
|
||||
{% if events[journal.transaction_journal_id]|length > 0 %}
|
||||
<div class="box">
|
||||
<div class="box-header with-border">
|
||||
<h3 class="box-title">{{ 'piggy_events'|_ }}</h3>
|
||||
</div>
|
||||
<div class="box-body table-responsive no-padding">
|
||||
<table class="table table-hover">
|
||||
{% for event in events[journal.transaction_journal_id] %}
|
||||
<tr>
|
||||
<td style="width:30%;">{{ event.amount|raw }}</td>
|
||||
<td>
|
||||
<a href="{{ route('piggy-banks.show', [event.piggy_id]) }}">{{ event.piggy }}</a></td>
|
||||
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<div class="box-body table-responsive no-padding">
|
||||
<table class="table table-hover">
|
||||
{% for event in events[journal.transaction_journal_id] %}
|
||||
<tr>
|
||||
<td style="width:30%;">{{ event.amount|raw }}</td>
|
||||
<td>
|
||||
<a href="{{ route('piggy-banks.show', [event.piggy_id]) }}">{{ event.piggy }}</a></td>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
{# modal for linking journals. Will be filled by AJAX #}
|
||||
<div class="modal fade" tabindex="-1" role="dialog" id="linkJournalModal">
|
||||
</div>
|
||||
|
||||
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endfor %}
|
||||
|
||||
</div>
|
||||
{% endblock %}
|
||||
{% block scripts %}
|
||||
<script type="text/javascript">
|
||||
var modalDialogURI = '{{ route('transactions.link.modal', ['%JOURNAL%']) }}';
|
||||
var acURI = '{{ route('json.autocomplete.all-journals-with-id') }}';
|
||||
var groupURI = '{{ route('transactions.show',['%GROUP']) }}';
|
||||
</script>
|
||||
<script type="text/javascript" src="v1/js/lib/typeahead/typeahead.bundle.min.js?v={{ FF_VERSION }}"></script>
|
||||
<script type="text/javascript" src="v1/js/ff/transactions/show.js?v={{ FF_VERSION }}"></script>
|
||||
{% endblock %}
|
||||
|
||||
{#
|
||||
|
@ -540,6 +540,7 @@ Route::group(
|
||||
Route::get('piggy-banks', ['uses' => 'Json\AutoCompleteController@piggyBanks', 'as' => 'autocomplete.piggy-banks']);
|
||||
Route::get('tags', ['uses' => 'Json\AutoCompleteController@tags', 'as' => 'autocomplete.tags']);
|
||||
Route::get('transaction-journals/all', ['uses' => 'Json\AutoCompleteController@allJournals', 'as' => 'autocomplete.all-journals']);
|
||||
Route::get('transaction-journals/with-id', ['uses' => 'Json\AutoCompleteController@allJournalsWithID', 'as' => 'autocomplete.all-journals-with-id']);
|
||||
Route::get('currency-names', ['uses' => 'Json\AutoCompleteController@currencyNames', 'as' => 'autocomplete.currency-names']);
|
||||
|
||||
|
||||
@ -884,8 +885,8 @@ Route::group(
|
||||
// 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::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']);
|
||||
@ -942,16 +943,16 @@ Route::group(
|
||||
/**
|
||||
* Transaction Split Controller
|
||||
*/
|
||||
Route::group(
|
||||
['middleware' => 'user-full-auth', 'namespace' => 'FireflyIII\Http\Controllers\Transaction', 'prefix' => 'transactions/split',
|
||||
'as' => 'transactions.split.'], function () {
|
||||
// TODO improve these routes
|
||||
Route::get('edit/{tj}', ['uses' => 'SplitController@edit', 'as' => 'edit']);
|
||||
Route::post('update/{tj}', ['uses' => 'SplitController@update', 'as' => 'update']);
|
||||
// TODO end of todo.
|
||||
|
||||
}
|
||||
);
|
||||
//Route::group(
|
||||
// ['middleware' => 'user-full-auth', 'namespace' => 'FireflyIII\Http\Controllers\Transaction', 'prefix' => 'transactions/split',
|
||||
// 'as' => 'transactions.split.'], function () {
|
||||
// // TODO improve these routes
|
||||
// Route::get('edit/{tj}', ['uses' => 'SplitController@edit', 'as' => 'edit']);
|
||||
// Route::post('update/{tj}', ['uses' => 'SplitController@update', 'as' => 'update']);
|
||||
// // TODO end of todo.
|
||||
//
|
||||
//}
|
||||
//);
|
||||
|
||||
/**
|
||||
* Transaction Convert Controller
|
||||
@ -970,6 +971,9 @@ Route::group(
|
||||
Route::group(
|
||||
['middleware' => 'user-full-auth', 'namespace' => 'FireflyIII\Http\Controllers\Transaction', 'prefix' => 'transactions/link', 'as' => 'transactions.link.'],
|
||||
function () {
|
||||
|
||||
Route::get('modal/{tj}', ['uses' => 'LinkController@modal', 'as' => 'modal']);
|
||||
|
||||
// TODO improve this route:
|
||||
Route::post('store/{tj}', ['uses' => 'LinkController@store', 'as' => 'store']);
|
||||
Route::get('delete/{journalLink}', ['uses' => 'LinkController@delete', 'as' => 'delete']);
|
||||
|
@ -28,8 +28,10 @@ use FireflyIII\Models\TransactionJournalLink;
|
||||
use FireflyIII\Repositories\Journal\JournalRepositoryInterface;
|
||||
use FireflyIII\Repositories\LinkType\LinkTypeRepositoryInterface;
|
||||
use FireflyIII\Repositories\User\UserRepositoryInterface;
|
||||
use Illuminate\Support\Collection;
|
||||
use Log;
|
||||
use Mockery;
|
||||
use Preferences;
|
||||
use Tests\TestCase;
|
||||
|
||||
/**
|
||||
@ -48,23 +50,39 @@ class LinkControllerTest extends TestCase
|
||||
|
||||
|
||||
/**
|
||||
* @covers \FireflyIII\Http\Controllers\Transaction\LinkController
|
||||
* @covers \FireflyIII\Http\Controllers\Transaction\LinkController
|
||||
*/
|
||||
public function testDelete(): void
|
||||
{ $this->markTestIncomplete('Needs to be rewritten for v4.8.0');
|
||||
{
|
||||
$this->mock(LinkTypeRepositoryInterface::class);
|
||||
$link = $this->getRandomLink();
|
||||
$userRepos = $this->mock(UserRepositoryInterface::class);
|
||||
|
||||
$this->mockDefaultSession();
|
||||
|
||||
|
||||
return;
|
||||
$journalRepos = $this->mock(JournalRepositoryInterface::class);
|
||||
$linkRepos = $this->mock(LinkTypeRepositoryInterface::class);
|
||||
$userRepos = $this->mock(UserRepositoryInterface::class);
|
||||
$userRepos->shouldReceive('hasRole')->withArgs([Mockery::any(), 'owner'])->atLeast()->once()->andReturn(true);
|
||||
|
||||
$this->be($this->user());
|
||||
$response = $this->get(route('transactions.link.delete', [$link->id]));
|
||||
$response->assertStatus(200);
|
||||
}
|
||||
|
||||
$journalRepos->shouldReceive('firstNull')->once()->andReturn(new TransactionJournal);
|
||||
|
||||
/**
|
||||
* @covers \FireflyIII\Http\Controllers\Transaction\LinkController
|
||||
*/
|
||||
public function testModal(): void
|
||||
{
|
||||
$journal = $this->getRandomWithdrawal();
|
||||
$linkRepos = $this->mock(LinkTypeRepositoryInterface::class);
|
||||
|
||||
$this->mockDefaultSession();
|
||||
|
||||
$linkRepos->shouldReceive('get')->atLeast()->once()->andReturn(new Collection);
|
||||
|
||||
$this->be($this->user());
|
||||
$response = $this->get(route('transactions.link.delete', [1]));
|
||||
$response = $this->get(route('transactions.link.modal', [$journal->id]));
|
||||
$response->assertStatus(200);
|
||||
}
|
||||
|
||||
@ -72,22 +90,18 @@ class LinkControllerTest extends TestCase
|
||||
* @covers \FireflyIII\Http\Controllers\Transaction\LinkController
|
||||
*/
|
||||
public function testDestroy(): void
|
||||
{ $this->markTestIncomplete('Needs to be rewritten for v4.8.0');
|
||||
|
||||
return;
|
||||
$journalRepos = $this->mock(JournalRepositoryInterface::class);
|
||||
{
|
||||
$link = $this->getRandomLink();
|
||||
$repository = $this->mock(LinkTypeRepositoryInterface::class);
|
||||
$userRepos = $this->mock(UserRepositoryInterface::class);
|
||||
|
||||
Preferences::shouldReceive('mark')->once();
|
||||
$this->mockDefaultSession();
|
||||
|
||||
$repository->shouldReceive('destroyLink');
|
||||
$journalRepos->shouldReceive('firstNull')->once()->andReturn(new TransactionJournal);
|
||||
|
||||
$repository->shouldReceive('destroyLink')->atLeast()->once();
|
||||
$this->be($this->user());
|
||||
|
||||
$this->session(['journal_links.delete.uri' => 'http://localhost/']);
|
||||
|
||||
$response = $this->post(route('transactions.link.destroy', [1]));
|
||||
$response = $this->post(route('transactions.link.destroy', [$link->id]));
|
||||
$response->assertStatus(302);
|
||||
$response->assertSessionHas('success');
|
||||
|
||||
@ -98,29 +112,28 @@ class LinkControllerTest extends TestCase
|
||||
* @covers \FireflyIII\Http\Requests\JournalLinkRequest
|
||||
*/
|
||||
public function testStore(): void
|
||||
{ $this->markTestIncomplete('Needs to be rewritten for v4.8.0');
|
||||
|
||||
return;
|
||||
{
|
||||
$withdrawal = $this->getRandomWithdrawal();
|
||||
$deposit = $this->getRandomDeposit();
|
||||
$repository = $this->mock(LinkTypeRepositoryInterface::class);
|
||||
$journalRepos = $this->mock(JournalRepositoryInterface::class);
|
||||
$userRepos = $this->mock(UserRepositoryInterface::class);
|
||||
$journalRepos = $this->mockDefaultSession();
|
||||
|
||||
$data = [
|
||||
'link_other' => 8,
|
||||
'link_type' => '1_inward',
|
||||
'opposing' => $deposit->id,
|
||||
'link_type' => '1_inward',
|
||||
];
|
||||
|
||||
$journalRepos->shouldReceive('firstNull')->andReturn(new TransactionJournal);
|
||||
$journalRepos->shouldReceive('findNull')->andReturn(new TransactionJournal);
|
||||
$repository->shouldReceive('findLink')->andReturn(false);
|
||||
$repository->shouldReceive('storeLink')->andReturn(new TransactionJournalLink);
|
||||
//$journalRepos->shouldReceive('firstNull')->andReturn(new TransactionJournal);
|
||||
$journalRepos->shouldReceive('findNull')->andReturn($deposit)->atLeast()->once();
|
||||
$repository->shouldReceive('findLink')->andReturn(false)->atLeast()->once();
|
||||
$repository->shouldReceive('storeLink')->andReturn(new TransactionJournalLink)->atLeast()->once();
|
||||
|
||||
$this->be($this->user());
|
||||
$response = $this->post(route('transactions.link.store', [1]), $data);
|
||||
$response = $this->post(route('transactions.link.store', [$withdrawal->id]), $data);
|
||||
|
||||
$response->assertStatus(302);
|
||||
$response->assertSessionHas('success');
|
||||
$response->assertRedirect(route('transactions.show', [1]));
|
||||
$response->assertRedirect(route('transactions.show', [$withdrawal->id]));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -128,28 +141,25 @@ class LinkControllerTest extends TestCase
|
||||
* @covers \FireflyIII\Http\Requests\JournalLinkRequest
|
||||
*/
|
||||
public function testStoreAlreadyLinked(): void
|
||||
{ $this->markTestIncomplete('Needs to be rewritten for v4.8.0');
|
||||
|
||||
return;
|
||||
{
|
||||
$repository = $this->mock(LinkTypeRepositoryInterface::class);
|
||||
$journalRepos = $this->mock(JournalRepositoryInterface::class);
|
||||
$userRepos = $this->mock(UserRepositoryInterface::class);
|
||||
$journalRepos = $this->mockDefaultSession();
|
||||
$link = $this->getRandomLink();
|
||||
|
||||
$data = [
|
||||
'link_other' => 8,
|
||||
'link_type' => '1_inward',
|
||||
'opposing' => $link->source_id,
|
||||
'link_type' => '1_inward',
|
||||
];
|
||||
|
||||
$journalRepos->shouldReceive('firstNull')->andReturn(new TransactionJournal);
|
||||
$journalRepos->shouldReceive('findNull')->andReturn(new TransactionJournal);
|
||||
$repository->shouldReceive('findLink')->andReturn(true);
|
||||
$journalRepos->shouldReceive('findNull')->andReturn(new TransactionJournal)->atLeast()->once();
|
||||
$repository->shouldReceive('findLink')->andReturn(true)->atLeast()->once();
|
||||
|
||||
$this->be($this->user());
|
||||
$response = $this->post(route('transactions.link.store', [1]), $data);
|
||||
$response = $this->post(route('transactions.link.store', [$link->destination_id]), $data);
|
||||
|
||||
$response->assertStatus(302);
|
||||
$response->assertSessionHas('error');
|
||||
$response->assertRedirect(route('transactions.show', [1]));
|
||||
$response->assertRedirect(route('transactions.show', [$link->destination_id]));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -157,26 +167,23 @@ class LinkControllerTest extends TestCase
|
||||
* @covers \FireflyIII\Http\Requests\JournalLinkRequest
|
||||
*/
|
||||
public function testStoreInvalid(): void
|
||||
{ $this->markTestIncomplete('Needs to be rewritten for v4.8.0');
|
||||
{
|
||||
$this->mock(LinkTypeRepositoryInterface::class);
|
||||
$journalRepos = $this->mockDefaultSession();
|
||||
$withdrawal = $this->getRandomWithdrawal();
|
||||
|
||||
return;
|
||||
$data = [
|
||||
'link_other' => 0,
|
||||
'link_type' => '1_inward',
|
||||
'opposing' => 0,
|
||||
'link_type' => '1_inward',
|
||||
];
|
||||
|
||||
$journalRepos = $this->mock(JournalRepositoryInterface::class);
|
||||
$userRepos = $this->mock(UserRepositoryInterface::class);
|
||||
$repository = $this->mock(LinkTypeRepositoryInterface::class);
|
||||
|
||||
$journalRepos->shouldReceive('firstNull')->andReturn(null);
|
||||
$journalRepos->shouldReceive('findNull')->andReturn(null);
|
||||
$journalRepos->shouldReceive('findNull')->andReturn(null)->atLeast()->once();
|
||||
|
||||
$this->be($this->user());
|
||||
$response = $this->post(route('transactions.link.store', [1]), $data);
|
||||
$response = $this->post(route('transactions.link.store', [$withdrawal->id]), $data);
|
||||
$response->assertStatus(302);
|
||||
$response->assertSessionHas('error');
|
||||
$response->assertRedirect(route('transactions.show', [1]));
|
||||
$response->assertRedirect(route('transactions.show', [$withdrawal->id]));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -184,39 +191,33 @@ class LinkControllerTest extends TestCase
|
||||
* @covers \FireflyIII\Http\Requests\JournalLinkRequest
|
||||
*/
|
||||
public function testStoreSame(): void
|
||||
{ $this->markTestIncomplete('Needs to be rewritten for v4.8.0');
|
||||
|
||||
return;
|
||||
{
|
||||
$withdrawal = $this->getRandomWithdrawal();
|
||||
$repository = $this->mock(LinkTypeRepositoryInterface::class);
|
||||
$journalRepos = $this->mock(JournalRepositoryInterface::class);
|
||||
$userRepos = $this->mock(UserRepositoryInterface::class);
|
||||
$journalRepos = $this->mockDefaultSession();
|
||||
|
||||
$data = [
|
||||
'link_other' => 8,
|
||||
'link_other' => $withdrawal->id,
|
||||
'link_type' => '1_inward',
|
||||
];
|
||||
$journal = $this->user()->transactionJournals()->first();
|
||||
|
||||
$journalRepos->shouldReceive('firstNull')->andReturn($journal);
|
||||
$journalRepos->shouldReceive('findNull')->andReturn($journal);
|
||||
$repository->shouldReceive('findLink')->andReturn(false);
|
||||
$repository->shouldReceive('storeLink')->andReturn(new TransactionJournalLink);
|
||||
$journalRepos->shouldReceive('findNull')->andReturn($withdrawal)->atLeast()->once();
|
||||
$repository->shouldReceive('findLink')->andReturn(false)->atLeast()->once();
|
||||
|
||||
$this->be($this->user());
|
||||
$response = $this->post(route('transactions.link.store', [$journal->id]), $data);
|
||||
$response = $this->post(route('transactions.link.store', [$withdrawal->id]), $data);
|
||||
|
||||
$response->assertStatus(302);
|
||||
$response->assertSessionHas('error');
|
||||
$response->assertRedirect(route('transactions.show', [1]));
|
||||
$response->assertRedirect(route('transactions.show', [$withdrawal->id]));
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers \FireflyIII\Http\Controllers\Transaction\LinkController
|
||||
*/
|
||||
public function testSwitchLink(): void
|
||||
{ $this->markTestIncomplete('Needs to be rewritten for v4.8.0');
|
||||
|
||||
return;
|
||||
{
|
||||
$link = $this->getRandomLink();
|
||||
$withdrawal = $this->getRandomWithdrawal();
|
||||
$journalRepos = $this->mock(JournalRepositoryInterface::class);
|
||||
$repository = $this->mock(LinkTypeRepositoryInterface::class);
|
||||
$userRepos = $this->mock(UserRepositoryInterface::class);
|
||||
@ -224,7 +225,7 @@ class LinkControllerTest extends TestCase
|
||||
$journalRepos->shouldReceive('firstNull')->once()->andReturn(new TransactionJournal);
|
||||
$repository->shouldReceive('switchLink')->andReturn(false);
|
||||
$this->be($this->user());
|
||||
$response = $this->get(route('transactions.link.switch', [1]));
|
||||
$response = $this->get(route('transactions.link.switch', [$link->id]));
|
||||
|
||||
|
||||
$response->assertStatus(302);
|
||||
|
@ -40,6 +40,7 @@ use FireflyIII\Models\Preference;
|
||||
use FireflyIII\Models\TransactionCurrency;
|
||||
use FireflyIII\Models\TransactionGroup;
|
||||
use FireflyIII\Models\TransactionJournal;
|
||||
use FireflyIII\Models\TransactionJournalLink;
|
||||
use FireflyIII\Models\TransactionType;
|
||||
use FireflyIII\Repositories\Journal\JournalRepositoryInterface;
|
||||
use FireflyIII\Transformers\TransactionTransformer;
|
||||
@ -58,6 +59,14 @@ use RuntimeException;
|
||||
abstract class TestCase extends BaseTestCase
|
||||
{
|
||||
|
||||
/**
|
||||
* @return TransactionJournalLink
|
||||
*/
|
||||
public function getRandomLink(): TransactionJournalLink
|
||||
{
|
||||
return TransactionJournalLink::inRandomOrder()->first();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Budget
|
||||
*/
|
||||
|
Loading…
Reference in New Issue
Block a user