mirror of
https://github.com/firefly-iii/firefly-iii.git
synced 2025-02-25 18:45:27 -06:00
Code that allows transaction reconciliation. #736
This commit is contained in:
parent
bb46d034cd
commit
33d89d52c2
@ -80,6 +80,7 @@ class JournalCollector implements JournalCollectorInterface
|
||||
'transactions.id as id',
|
||||
'transactions.description as transaction_description',
|
||||
'transactions.account_id',
|
||||
'transactions.reconciled',
|
||||
'transactions.identifier',
|
||||
'transactions.transaction_journal_id',
|
||||
'transactions.amount as transaction_amount',
|
||||
@ -171,7 +172,7 @@ class JournalCollector implements JournalCollectorInterface
|
||||
$q1->where(
|
||||
function (EloquentBuilder $q2) use ($amount) {
|
||||
// amount < 0 and .amount > -$amount
|
||||
$amount = bcmul($amount,'-1');
|
||||
$amount = bcmul($amount, '-1');
|
||||
$q2->where('transactions.amount', '<', 0)->where('transactions.amount', '>', $amount);
|
||||
}
|
||||
)
|
||||
@ -199,7 +200,7 @@ class JournalCollector implements JournalCollectorInterface
|
||||
$q1->where(
|
||||
function (EloquentBuilder $q2) use ($amount) {
|
||||
// amount < 0 and .amount < -$amount
|
||||
$amount = bcmul($amount,'-1');
|
||||
$amount = bcmul($amount, '-1');
|
||||
$q2->where('transactions.amount', '<', 0)->where('transactions.amount', '<', $amount);
|
||||
}
|
||||
)
|
||||
@ -211,6 +212,7 @@ class JournalCollector implements JournalCollectorInterface
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
93
app/Http/Controllers/Json/TransactionController.php
Normal file
93
app/Http/Controllers/Json/TransactionController.php
Normal file
@ -0,0 +1,93 @@
|
||||
<?php
|
||||
/**
|
||||
* TransactionController.php
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Http\Controllers\Json;
|
||||
|
||||
|
||||
use FireflyIII\Http\Controllers\Controller;
|
||||
use FireflyIII\Models\TransactionType;
|
||||
use FireflyIII\Repositories\Journal\JournalRepositoryInterface;
|
||||
use FireflyIII\Support\SingleCacheProperties;
|
||||
use Illuminate\Http\Request;
|
||||
use Response;
|
||||
|
||||
class TransactionController extends Controller
|
||||
{
|
||||
public function amounts(Request $request, JournalRepositoryInterface $repository)
|
||||
{
|
||||
$ids = $request->get('transactions');
|
||||
|
||||
$cache = new SingleCacheProperties;
|
||||
$cache->addProperty('json-reconcile-amounts');
|
||||
$cache->addProperty($ids);
|
||||
if ($cache->has()) {
|
||||
return Response::json($cache->get());
|
||||
}
|
||||
|
||||
$totals = [];
|
||||
// for each transaction, get amount(s)
|
||||
foreach ($ids as $transactionId) {
|
||||
$transaction = $repository->findTransaction(intval($transactionId));
|
||||
$transactionType = $transaction->transactionJournal->transactionType->type;
|
||||
|
||||
// default amount:
|
||||
$currencyId = $transaction->transaction_currency_id;
|
||||
if (!isset($totals[$currencyId])) {
|
||||
$totals[$currencyId] = [
|
||||
'amount' => '0',
|
||||
'currency' => $transaction->transactionCurrency,
|
||||
'type' => $transactionType,
|
||||
];
|
||||
}
|
||||
// add default amount:
|
||||
$totals[$currencyId]['amount'] = bcadd($totals[$currencyId]['amount'], app('steam')->positive($transaction->amount));
|
||||
|
||||
// foreign amount:
|
||||
if (!is_null($transaction->foreign_amount)) {
|
||||
$currencyId = $transaction->foreign_currency_id;
|
||||
if (!isset($totals[$currencyId])) {
|
||||
$totals[$currencyId] = [
|
||||
'amount' => '0',
|
||||
'currency' => $transaction->foreignCurrency,
|
||||
'type' => $transactionType,
|
||||
];
|
||||
}
|
||||
// add foreign amount:
|
||||
$totals[$currencyId]['amount'] = bcadd($totals[$currencyId]['amount'], app('steam')->positive($transaction->foreign_amount));
|
||||
}
|
||||
}
|
||||
$entries = [];
|
||||
foreach ($totals as $entry) {
|
||||
$amount = $entry['amount'];
|
||||
if ($entry['type'] === TransactionType::WITHDRAWAL) {
|
||||
$amount = bcmul($entry['amount'], '-1');
|
||||
}
|
||||
$entries[] = app('amount')->formatAnything($entry['currency'], $amount, false);
|
||||
}
|
||||
$result = ['amounts' => join(' / ', $entries)];
|
||||
$cache->store($result);
|
||||
|
||||
return Response::json($result);
|
||||
}
|
||||
|
||||
}
|
@ -133,6 +133,22 @@ class TransactionController extends Controller
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Request $request
|
||||
*/
|
||||
public function reconcile(Request $request, JournalRepositoryInterface $repository)
|
||||
{
|
||||
$transactionIds = $request->get('transactions');
|
||||
foreach ($transactionIds as $transactionId) {
|
||||
$transactionId = intval($transactionId);
|
||||
$transaction = $repository->findTransaction($transactionId);
|
||||
Log::debug(sprintf('Transaction ID is %d', $transaction->id));
|
||||
|
||||
$repository->reconcile($transaction);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Request $request
|
||||
* @param JournalRepositoryInterface $repository
|
||||
@ -181,8 +197,6 @@ class TransactionController extends Controller
|
||||
$subTitle = trans('firefly.' . $what) . ' "' . $journal->description . '"';
|
||||
|
||||
return view('transactions.show', compact('journal', 'events', 'subTitle', 'what', 'transactions', 'linkTypes', 'links'));
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -93,6 +93,7 @@ class Transaction extends Model
|
||||
'identifier' => 'int',
|
||||
'encrypted' => 'boolean', // model does not have these fields though
|
||||
'bill_name_encrypted' => 'boolean',
|
||||
'reconciled' => 'boolean',
|
||||
];
|
||||
protected $fillable
|
||||
= ['account_id', 'transaction_journal_id', 'description', 'amount', 'identifier', 'transaction_currency_id', 'foreign_currency_id',
|
||||
|
@ -24,6 +24,7 @@ declare(strict_types=1);
|
||||
namespace FireflyIII\Repositories\Journal;
|
||||
|
||||
use FireflyIII\Models\Account;
|
||||
use FireflyIII\Models\Transaction;
|
||||
use FireflyIII\Models\TransactionJournal;
|
||||
use FireflyIII\Models\TransactionType;
|
||||
use FireflyIII\User;
|
||||
@ -123,6 +124,38 @@ class JournalRepository implements JournalRepositoryInterface
|
||||
return $journal;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Transaction $transaction
|
||||
*
|
||||
* @return Transaction|null
|
||||
*/
|
||||
public function findOpposingTransaction(Transaction $transaction): ?Transaction
|
||||
{
|
||||
$opposing = Transaction::leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id')
|
||||
->where('transaction_journals.user_id', $this->user->id)
|
||||
->where('transactions.transaction_journal_id', $transaction->transaction_journal_id)
|
||||
->where('transactions.identifier', $transaction->identifier)
|
||||
->where('amount', bcmul($transaction->amount, '-1'))
|
||||
->first(['transactions.*']);
|
||||
|
||||
return $opposing;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $transactionid
|
||||
*
|
||||
* @return Transaction|null
|
||||
*/
|
||||
public function findTransaction(int $transactionid): ?Transaction
|
||||
{
|
||||
$transaction = Transaction::leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id')
|
||||
->where('transaction_journals.user_id', $this->user->id)
|
||||
->where('transactions.id', $transactionid)
|
||||
->first(['transactions.*']);
|
||||
|
||||
return $transaction;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get users first transaction journal
|
||||
*
|
||||
@ -158,6 +191,32 @@ class JournalRepository implements JournalRepositoryInterface
|
||||
return $journal->transactionType->type === TransactionType::TRANSFER;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Transaction $transaction
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function reconcile(Transaction $transaction): bool
|
||||
{
|
||||
Log::debug(sprintf('Going to reconcile transaction #%d', $transaction->id));
|
||||
$opposing = $this->findOpposingTransaction($transaction);
|
||||
|
||||
if (is_null($opposing)) {
|
||||
Log::debug('Opposing transaction is NULL. Cannot reconcile.');
|
||||
|
||||
return false;
|
||||
}
|
||||
Log::debug(sprintf('Opposing transaction ID is #%d', $opposing->id));
|
||||
|
||||
$transaction->reconciled = true;
|
||||
$opposing->reconciled = true;
|
||||
$transaction->save();
|
||||
$opposing->save();
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param TransactionJournal $journal
|
||||
* @param int $order
|
||||
@ -303,7 +362,7 @@ class JournalRepository implements JournalRepositoryInterface
|
||||
}
|
||||
|
||||
// update note:
|
||||
if (isset($data['notes']) && !is_null($data['notes']) ) {
|
||||
if (isset($data['notes']) && !is_null($data['notes'])) {
|
||||
$this->updateNote($journal, strval($data['notes']));
|
||||
}
|
||||
|
||||
@ -345,7 +404,7 @@ class JournalRepository implements JournalRepositoryInterface
|
||||
$journal->budgets()->detach();
|
||||
|
||||
// update note:
|
||||
if (isset($data['notes']) && !is_null($data['notes']) ) {
|
||||
if (isset($data['notes']) && !is_null($data['notes'])) {
|
||||
$this->updateNote($journal, strval($data['notes']));
|
||||
}
|
||||
|
||||
|
@ -24,6 +24,7 @@ declare(strict_types=1);
|
||||
namespace FireflyIII\Repositories\Journal;
|
||||
|
||||
use FireflyIII\Models\Account;
|
||||
use FireflyIII\Models\Transaction;
|
||||
use FireflyIII\Models\TransactionJournal;
|
||||
use FireflyIII\Models\TransactionType;
|
||||
use FireflyIII\User;
|
||||
@ -73,6 +74,20 @@ interface JournalRepositoryInterface
|
||||
*/
|
||||
public function find(int $journalId): TransactionJournal;
|
||||
|
||||
/**
|
||||
* @param Transaction $transaction
|
||||
*
|
||||
* @return Transaction|null
|
||||
*/
|
||||
public function findOpposingTransaction(Transaction $transaction): ?Transaction;
|
||||
|
||||
/**
|
||||
* @param int $transactionid
|
||||
*
|
||||
* @return Transaction|null
|
||||
*/
|
||||
public function findTransaction(int $transactionid): ?Transaction;
|
||||
|
||||
/**
|
||||
* Get users very first transaction journal
|
||||
*
|
||||
@ -92,6 +107,13 @@ interface JournalRepositoryInterface
|
||||
*/
|
||||
public function isTransfer(TransactionJournal $journal): bool;
|
||||
|
||||
/**
|
||||
* @param Transaction $transaction
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function reconcile(Transaction $transaction): bool;
|
||||
|
||||
/**
|
||||
* @param TransactionJournal $journal
|
||||
* @param int $order
|
||||
|
@ -28,6 +28,7 @@ use FireflyIII\Models\AccountType;
|
||||
use FireflyIII\Models\PiggyBankEvent;
|
||||
use FireflyIII\Models\Transaction;
|
||||
use FireflyIII\Models\TransactionJournal;
|
||||
use FireflyIII\Support\SingleCacheProperties;
|
||||
use FireflyIII\User;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Database\Query\JoinClause;
|
||||
@ -74,6 +75,13 @@ class JournalTasker implements JournalTaskerInterface
|
||||
*/
|
||||
public function getTransactionsOverview(TransactionJournal $journal): array
|
||||
{
|
||||
$cache = new SingleCacheProperties;
|
||||
$cache->addProperty('transaction-overview');
|
||||
$cache->addProperty($journal->id);
|
||||
$cache->addProperty($journal->updated_at);
|
||||
if ($cache->has()) {
|
||||
return $cache->get();
|
||||
}
|
||||
// get all transaction data + the opposite site in one list.
|
||||
$set = $journal
|
||||
->transactions()// "source"
|
||||
@ -136,6 +144,7 @@ class JournalTasker implements JournalTaskerInterface
|
||||
'journal_type' => $transactionType,
|
||||
'updated_at' => $journal->updated_at,
|
||||
'source_id' => $entry->id,
|
||||
'source' => $journal->transactions()->find($entry->id),
|
||||
'source_amount' => $entry->amount,
|
||||
'foreign_source_amount' => $entry->foreign_amount,
|
||||
'description' => $entry->description,
|
||||
@ -174,6 +183,7 @@ class JournalTasker implements JournalTaskerInterface
|
||||
|
||||
$transactions[] = $transaction;
|
||||
}
|
||||
$cache->store($transactions);
|
||||
|
||||
return $transactions;
|
||||
}
|
||||
|
@ -39,6 +39,7 @@ use Twig_Extension;
|
||||
*/
|
||||
class Transaction extends Twig_Extension
|
||||
{
|
||||
|
||||
/**
|
||||
* Can show the amount of a transaction, if that transaction has been collected by the journal collector.
|
||||
*
|
||||
@ -127,13 +128,13 @@ class Transaction extends Twig_Extension
|
||||
$string = app('amount')->formatAnything($fakeCurrency, $amount, true);
|
||||
|
||||
// then display (if present) the foreign amount:
|
||||
if(!is_null($transaction['foreign_source_amount'])) {
|
||||
if (!is_null($transaction['foreign_source_amount'])) {
|
||||
$amount = $transaction['journal_type'] === TransactionType::WITHDRAWAL ? $transaction['foreign_source_amount']
|
||||
: $transaction['foreign_destination_amount'];
|
||||
$fakeCurrency = new TransactionCurrency;
|
||||
$fakeCurrency->decimal_places = $transaction['foreign_currency_dp'];
|
||||
$fakeCurrency->symbol = $transaction['foreign_currency_symbol'];
|
||||
$string .= ' ('.app('amount')->formatAnything($fakeCurrency, $amount, true).')';
|
||||
$string .= ' (' . app('amount')->formatAnything($fakeCurrency, $amount, true) . ')';
|
||||
}
|
||||
$cache->store($string);
|
||||
|
||||
@ -401,6 +402,30 @@ class Transaction extends Twig_Extension
|
||||
return $txt;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param TransactionModel $transaction
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function isReconciled(TransactionModel $transaction): string
|
||||
{
|
||||
$cache = new SingleCacheProperties;
|
||||
$cache->addProperty('transaction-reconciled');
|
||||
$cache->addProperty($transaction->id);
|
||||
$cache->addProperty($transaction->updated_at);
|
||||
if ($cache->has()) {
|
||||
return $cache->get();
|
||||
}
|
||||
$icon = '';
|
||||
if (intval($transaction->reconciled) === 1) {
|
||||
$icon = '<i class="fa fa-check"></i>';
|
||||
}
|
||||
|
||||
$cache->store($icon);
|
||||
|
||||
return $icon;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param TransactionModel $transaction
|
||||
*
|
||||
|
33
database/migrations/2017_11_04_170844_changes_for_v470a.php
Normal file
33
database/migrations/2017_11_04_170844_changes_for_v470a.php
Normal file
@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class ChangesForV470a extends Migration
|
||||
{
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @SuppressWarnings(PHPMD.ShortMethodName)
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::table(
|
||||
'transactions', function (Blueprint $table) {
|
||||
$table->boolean('reconciled')->after('deleted_at')->default(0);
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
90
public/js/ff/transactions/list.js
vendored
90
public/js/ff/transactions/list.js
vendored
@ -20,6 +20,9 @@
|
||||
|
||||
/** global: edit_selected_txt, delete_selected_txt */
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
$(document).ready(function () {
|
||||
"use strict";
|
||||
$('.mass_edit_all').show();
|
||||
@ -44,8 +47,43 @@ $(document).ready(function () {
|
||||
$('.mass_edit').click(goToMassEdit);
|
||||
// click the delete button:
|
||||
$('.mass_delete').click(goToMassDelete);
|
||||
// click reconcile button
|
||||
$('.mass_reconcile').click(goToReconcile);
|
||||
});
|
||||
|
||||
/**
|
||||
*
|
||||
* @returns {boolean}
|
||||
*/
|
||||
function goToReconcile() {
|
||||
|
||||
var checked = $('.select_all_single:checked');
|
||||
var ids = [];
|
||||
$.each(checked, function (i, v) {
|
||||
ids.push(parseInt($(v).data('transaction')));
|
||||
});
|
||||
|
||||
// go to specially crafted URL:
|
||||
var bases = document.getElementsByTagName('base');
|
||||
var baseHref = null;
|
||||
|
||||
if (bases.length > 0) {
|
||||
baseHref = bases[0].href;
|
||||
}
|
||||
|
||||
$.post(baseHref + 'transactions/reconcile', {transactions: ids}).done(function () {
|
||||
alert('OK then.');
|
||||
}).fail(function () {
|
||||
alert('Could not reconcile transactions: please check the logs and try again later.');
|
||||
});
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @returns {boolean}
|
||||
*/
|
||||
function goToMassEdit() {
|
||||
"use strict";
|
||||
var checkedArray = getCheckboxes();
|
||||
@ -62,6 +100,10 @@ function goToMassEdit() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @returns {boolean}
|
||||
*/
|
||||
function goToMassDelete() {
|
||||
"use strict";
|
||||
var checkedArray = getCheckboxes();
|
||||
@ -77,6 +119,10 @@ function goToMassDelete() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @returns {Array}
|
||||
*/
|
||||
function getCheckboxes() {
|
||||
"use strict";
|
||||
var list = [];
|
||||
@ -90,13 +136,19 @@ function getCheckboxes() {
|
||||
return list;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
function countChecked() {
|
||||
"use strict";
|
||||
var checked = $('.select_all_single:checked').length;
|
||||
if (checked > 0) {
|
||||
$('.mass_edit span').text(edit_selected_txt + ' (' + checked + ')');
|
||||
$('.mass_delete span').text(delete_selected_txt + ' (' + checked + ')');
|
||||
|
||||
// get amount for the transactions:
|
||||
getAmounts();
|
||||
|
||||
$('.mass_button_options').show();
|
||||
|
||||
} else {
|
||||
@ -104,17 +156,49 @@ function countChecked() {
|
||||
}
|
||||
}
|
||||
|
||||
function getAmounts() {
|
||||
$('.mass_reconcile span').html(reconcile_selected_txt + ' (<i class="fa fa-spinner fa-spin "></i>)');
|
||||
var checked = $('.select_all_single:checked');
|
||||
var ids = [];
|
||||
$.each(checked, function (i, v) {
|
||||
ids.push(parseInt($(v).data('transaction')));
|
||||
});
|
||||
|
||||
// go to specially crafted URL:
|
||||
var bases = document.getElementsByTagName('base');
|
||||
var baseHref = null;
|
||||
|
||||
if (bases.length > 0) {
|
||||
baseHref = bases[0].href;
|
||||
}
|
||||
|
||||
$.getJSON(baseHref + 'json/transactions/amount', {transactions: ids}).done(function (data) {
|
||||
$('.mass_reconcile span').text(reconcile_selected_txt + ' (' + data.amounts + ')');
|
||||
console.log(data);
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
function checkAll() {
|
||||
"use strict";
|
||||
$('.select_all_single').prop('checked', true);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
function uncheckAll() {
|
||||
"use strict";
|
||||
$('.select_all_single').prop('checked', false);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @returns {boolean}
|
||||
*/
|
||||
function stopMassSelect() {
|
||||
"use strict";
|
||||
|
||||
@ -145,6 +229,10 @@ function stopMassSelect() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @returns {boolean}
|
||||
*/
|
||||
function startMassSelect() {
|
||||
"use strict";
|
||||
// show "select all" box in table header.
|
||||
|
@ -663,8 +663,7 @@ return [
|
||||
'stored_journal' => 'Successfully created new transaction ":description"',
|
||||
'select_transactions' => 'Select transactions',
|
||||
'stop_selection' => 'Stop selecting transactions',
|
||||
'edit_selected' => 'Edit selected',
|
||||
'delete_selected' => 'Delete selected',
|
||||
'reconcile_selected' => 'Reconcile',
|
||||
'mass_delete_journals' => 'Delete a number of transactions',
|
||||
'mass_edit_journals' => 'Edit a number of transactions',
|
||||
'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.',
|
||||
|
@ -33,13 +33,15 @@
|
||||
</tbody>
|
||||
</table>
|
||||
<div class="row mass_edit_all hidden-xs" style="display: none;">
|
||||
<div class="col-lg-6 col-md-12 col-sm-12 col-xs-12">
|
||||
<div class="col-lg-8 col-md-12 col-sm-12 col-xs-12">
|
||||
<div class="mass_button_options btn-group btn-group" style="display:none;">
|
||||
<a href="#" class="btn btn-default mass_edit"><i class="fa fa-fw fa-pencil"></i> <span>{{ 'edit_selected'|_ }}</span></a>
|
||||
<a href="#" class="btn btn-danger mass_delete"><i class="fa fa-fw fa-trash"></i> <span>{{ 'delete_selected'|_ }}</span></a>
|
||||
<a href="#" class="btn btn-default mass_edit"><i class="fa fa-fw fa-pencil"></i> <span>{{ 'edit'|_ }}</span></a>
|
||||
<a href="#" class="btn btn-default mass_reconcile"><i class="fa fa-fw fa-check"></i> <span>{{ 'reconcile_selected'|_ }} (<i class="fa fa-spinner fa-spin"></i>)</span></a>
|
||||
<a href="#" class="btn btn-danger mass_delete"><i class="fa fa-fw fa-trash"></i> <span>{{ 'delete'|_ }}</span></a>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="col-lg-6 col-md-12 col-sm-12 col-xs-12 hidden-xs">
|
||||
<div class="col-lg-4 col-md-12 col-sm-12 col-xs-12 hidden-xs">
|
||||
|
||||
<div class="mass_buttons btn-group btn-group pull-right">
|
||||
<a href="#" class="btn btn-default mass_select"><i class="fa fa-fw fa-check-square-o"></i> {{ 'select_transactions'|_ }}</a>
|
||||
@ -54,6 +56,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<script type="text/javascript">
|
||||
var edit_selected_txt = "{{ 'edit_selected'|_ }}";
|
||||
var delete_selected_txt = "{{ 'delete_selected'|_ }}";
|
||||
var edit_selected_txt = "{{ 'edit'|_ }}";
|
||||
var delete_selected_txt = "{{ 'delete'|_ }}";
|
||||
var reconcile_selected_txt = "{{ 'reconcile_selected'|_ }}";
|
||||
</script>
|
||||
|
@ -1,9 +1,11 @@
|
||||
|
||||
<tr class="drag" data-date="{{ transaction.date.format('Y-m-d') }}" data-id="{{ transaction.journal_id }}">
|
||||
<tr class="drag" data-date="{{ transaction.date.format('Y-m-d') }}" data-id="{{ transaction.journal_id }}"
|
||||
data-transaction-id="{{ transaction.id }}"
|
||||
>
|
||||
{# input buttons #}
|
||||
<td class="hidden-xs">
|
||||
<div class="select_single" style="display:none;">
|
||||
<input name="select_all_single[]" class="select_all_single" value="{{ transaction.journal_id }}" type="checkbox"/>
|
||||
<input name="select_all_single[]" class="select_all_single" data-transaction="{{ transaction.id }}" value="{{ transaction.journal_id }}" type="checkbox"/>
|
||||
</div>
|
||||
<div class="btn-group btn-group-xs edit_buttons edit_tr_buttons">{% if sorting %}<a href="#" class="handle btn btn-default btn-xs"><i
|
||||
class="fa fa-fw fa-arrows-v"></i></a>{% endif %}<a href="{{ route('transactions.edit',transaction.journal_id) }}"
|
||||
@ -19,13 +21,19 @@
|
||||
|
||||
{# description #}
|
||||
<td>
|
||||
{# count attachments #}
|
||||
{{ transaction|transactionReconciled }}
|
||||
|
||||
<a href="{{ route('transactions.show',transaction.journal_id) }}">
|
||||
{{ transaction|transactionDescription }}
|
||||
</a>
|
||||
{# is a split journal #}
|
||||
{{ transaction|transactionIsSplit }}
|
||||
|
||||
{# count attachments #}
|
||||
{{ transaction|transactionHasAtt }}
|
||||
|
||||
|
||||
</td>
|
||||
<td style="text-align: right;"><span style="margin-right:5px;">{{ transaction|transactionAmount }}</span></td>
|
||||
<td class="hidden-sm hidden-xs">
|
||||
|
@ -107,8 +107,10 @@
|
||||
{% endblock %}
|
||||
{% block scripts %}
|
||||
<script type="text/javascript">
|
||||
var edit_selected_txt = "{{ 'edit_selected'|_ }}";
|
||||
var delete_selected_txt = "{{ 'delete_selected'|_ }}";
|
||||
var edit_selected_txt = "{{ 'edit'|_ }}";
|
||||
var delete_selected_txt = "{{ 'delete'|_ }}";
|
||||
var reconcile_selected_txt = "{{ 'reconcile_selected'|_ }}";
|
||||
|
||||
var searchQuery = "{{ fullQuery|escape('js') }}";
|
||||
var searchUri = "{{ route('search.search') }}";
|
||||
</script>
|
||||
|
@ -413,24 +413,13 @@
|
||||
{{ formatDestinationBefore(transaction) }} → {{ formatDestinationAfter(transaction) }}
|
||||
</td>
|
||||
<td>
|
||||
{% if journal.transactionType.type == "Withdrawal" %}
|
||||
{{ formatAmountBySymbol(transaction.source_amount, transaction.transaction_currency_symbol, transaction.transaction_currency_dp, true) }}
|
||||
{% if(transaction.foreign_source_amount) %}
|
||||
({{ formatAmountBySymbol(transaction.foreign_source_amount, transaction.foreign_currency_symbol, transaction.foreign_currency_dp, true) }})
|
||||
{% endif %}
|
||||
{% else %}
|
||||
{{ formatAmountBySymbol(transaction.destination_amount, transaction.transaction_currency_symbol,2) }}
|
||||
|
||||
{% if(transaction.foreign_source_amount) %}
|
||||
({{ formatAmountBySymbol(transaction.foreign_destination_amount, transaction.foreign_currency_symbol, transaction.foreign_currency_dp, true) }})
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{{ transaction|transactionArrayAmount }}
|
||||
</td>
|
||||
<td class="hidden-md hidden-xs">
|
||||
{{ transactionIdBudgets(transaction.source_id) }}
|
||||
{{ transaction.source|transactionBudgets }}
|
||||
</td>
|
||||
<td class="hidden-md hidden-xs">
|
||||
{{ transactionIdCategories(transaction.source_id) }}
|
||||
{{ transaction.source|transactionCategories }}
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
|
@ -462,6 +462,9 @@ Route::group(
|
||||
// frontpage
|
||||
Route::get('frontpage/piggy-banks', ['uses' => 'Json\FrontpageController@piggyBanks', 'as' => 'fp.piggy-banks']);
|
||||
|
||||
// amount reconciliation
|
||||
Route::get('transactions/amount', ['uses' => 'Json\TransactionController@amounts', 'as' => 'transactions.amounts']);
|
||||
|
||||
// currency conversion:
|
||||
Route::get('rate/{fromCurrencyCode}/{toCurrencyCode}/{date}', ['uses' => 'Json\ExchangeController@getRate', 'as' => 'rate']);
|
||||
|
||||
@ -700,6 +703,7 @@ Route::group(
|
||||
Route::get('{what}/{moment?}', ['uses' => 'TransactionController@index', 'as' => 'index'])->where(['what' => 'withdrawal|deposit|transfers|transfer']);
|
||||
Route::get('show/{tj}', ['uses' => 'TransactionController@show', 'as' => 'show']);
|
||||
Route::post('reorder', ['uses' => 'TransactionController@reorder', 'as' => 'reorder']);
|
||||
Route::post('reconcile', ['uses' => 'TransactionController@reconcile', 'as' => 'reconcile']);
|
||||
}
|
||||
);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user