Lots of new code for new transaction screen.

This commit is contained in:
James Cole 2019-05-04 20:58:11 +02:00
parent 912fe99981
commit d5c5fa4fad
33 changed files with 55416 additions and 128 deletions

View File

@ -45,7 +45,7 @@ echo "Discover packages..."
php artisan package:discover
echo "Run various artisan commands..."
. $FIREFLY_PATH/.env
#. $FIREFLY_PATH/.env
if [[ -z "$DB_PORT" ]]; then
if [[ $DB_CONNECTION == "pgsql" ]]; then
DB_PORT=5432

View File

@ -519,22 +519,22 @@ return [
],
'test-triggers' => [
'test-triggers' => [
'limit' => 10,
'range' => 200,
],
'default_currency' => 'EUR',
'default_language' => 'en_US',
'search_modifiers' => ['amount_is', 'amount', 'amount_max', 'amount_min', 'amount_less', 'amount_more', 'source', 'destination', 'category',
'budget', 'bill', 'type', 'date', 'date_before', 'date_after', 'on', 'before', 'after'],
'default_currency' => 'EUR',
'default_language' => 'en_US',
'search_modifiers' => ['amount_is', 'amount', 'amount_max', 'amount_min', 'amount_less', 'amount_more', 'source', 'destination', 'category',
'budget', 'bill', 'type', 'date', 'date_before', 'date_after', 'on', 'before', 'after'],
// tag notes has_attachments
'cer_providers' => [
'cer_providers' => [
'fixer' => FixerIOv2::class,
'ratesapi' => RatesApiIOv1::class,
],
// expected source types for each transaction type, in order of preference.
'expected_source_types' => [
'expected_source_types' => [
'source' => [
TransactionTypeModel::WITHDRAWAL => [AccountType::ASSET, AccountType::LOAN, AccountType::DEBT, AccountType::MORTGAGE],
TransactionTypeModel::DEPOSIT => [AccountType::REVENUE, AccountType::CASH, AccountType::LOAN, AccountType::DEBT, AccountType::MORTGAGE,
@ -543,6 +543,15 @@ return [
TransactionTypeModel::OPENING_BALANCE => [AccountType::INITIAL_BALANCE, AccountType::ASSET, AccountType::LOAN, AccountType::DEBT,
AccountType::MORTGAGE],
TransactionTypeModel::RECONCILIATION => [AccountType::RECONCILIATION, AccountType::ASSET],
// in case no transaction type is known yet, it could be anything.
'none' => [
AccountType::ASSET,
AccountType::EXPENSE,
AccountType::REVENUE,
AccountType::LOAN,
AccountType::DEBT,
AccountType::MORTGAGE,
],
],
'destination' => [
TransactionTypeModel::WITHDRAWAL => [AccountType::EXPENSE, AccountType::CASH, AccountType::LOAN, AccountType::DEBT,
@ -554,9 +563,130 @@ return [
TransactionTypeModel::RECONCILIATION => [AccountType::RECONCILIATION, AccountType::ASSET],
],
],
'allowed_opposing_types' => [
'source' => [
AccountType::ASSET => [AccountType::ASSET, AccountType::CASH, AccountType::DEBT, AccountType::EXPENSE, AccountType::INITIAL_BALANCE,
AccountType::LOAN, AccountType::RECONCILIATION],
AccountType::CASH => [AccountType::ASSET],
AccountType::DEBT => [AccountType::ASSET, AccountType::DEBT, AccountType::EXPENSE, AccountType::INITIAL_BALANCE, AccountType::LOAN,
AccountType::MORTGAGE],
AccountType::EXPENSE => [], // is not allowed as a source.
AccountType::INITIAL_BALANCE => [AccountType::ASSET, AccountType::DEBT, AccountType::LOAN, AccountType::MORTGAGE],
AccountType::LOAN => [AccountType::ASSET, AccountType::DEBT, AccountType::EXPENSE, AccountType::INITIAL_BALANCE, AccountType::LOAN,
AccountType::MORTGAGE],
AccountType::MORTGAGE => [AccountType::ASSET, AccountType::DEBT, AccountType::EXPENSE, AccountType::INITIAL_BALANCE, AccountType::LOAN,
AccountType::MORTGAGE],
AccountType::RECONCILIATION => [AccountType::ASSET],
AccountType::REVENUE => [AccountType::ASSET, AccountType::DEBT, AccountType::LOAN, AccountType::MORTGAGE],
],
'destination' => [
AccountType::ASSET => [AccountType::ASSET, AccountType::CASH, AccountType::DEBT, AccountType::INITIAL_BALANCE, AccountType::LOAN,
AccountType::MORTGAGE, AccountType::RECONCILIATION, AccountType::REVENUE],
AccountType::CASH => [AccountType::ASSET],
AccountType::DEBT => [AccountType::ASSET, AccountType::DEBT, AccountType::INITIAL_BALANCE, AccountType::LOAN, AccountType::MORTGAGE,
AccountType::REVENUE],
AccountType::EXPENSE => [AccountType::ASSET, AccountType::DEBT, AccountType::LOAN, AccountType::MORTGAGE],
AccountType::INITIAL_BALANCE => [AccountType::ASSET, AccountType::DEBT, AccountType::LOAN, AccountType::MORTGAGE],
AccountType::LOAN => [AccountType::ASSET, AccountType::DEBT, AccountType::INITIAL_BALANCE, AccountType::LOAN, AccountType::MORTGAGE,
AccountType::REVENUE],
AccountType::MORTGAGE => [AccountType::ASSET, AccountType::DEBT, AccountType::INITIAL_BALANCE, AccountType::LOAN, AccountType::MORTGAGE,
AccountType::REVENUE],
AccountType::RECONCILIATION => [AccountType::ASSET],
AccountType::REVENUE => [], // is not allowed as a destination
],
],
// depending on the account type, return the allowed transaction types:
'allowed_transaction_types' => [
'source' => [
AccountType::ASSET => [TransactionTypeModel::WITHDRAWAL, TransactionTypeModel::TRANSFER, TransactionTypeModel::OPENING_BALANCE,
TransactionTypeModel::RECONCILIATION],
AccountType::EXPENSE => [], // is not allowed as a source.
AccountType::REVENUE => [TransactionTypeModel::DEPOSIT],
AccountType::LOAN => [TransactionTypeModel::WITHDRAWAL, TransactionTypeModel::DEPOSIT, TransactionTypeModel::TRANSFER,
TransactionTypeModel::OPENING_BALANCE],
AccountType::DEBT => [TransactionTypeModel::WITHDRAWAL, TransactionTypeModel::DEPOSIT, TransactionTypeModel::TRANSFER,
TransactionTypeModel::OPENING_BALANCE],
AccountType::MORTGAGE => [TransactionTypeModel::WITHDRAWAL, TransactionTypeModel::DEPOSIT, TransactionTypeModel::TRANSFER,
TransactionTypeModel::OPENING_BALANCE],
AccountType::INITIAL_BALANCE => [], // todo fill me in.
AccountType::RECONCILIATION => [], // todo fill me in.
],
'destination' => [
AccountType::ASSET => [TransactionTypeModel::DEPOSIT, TransactionTypeModel::TRANSFER, TransactionTypeModel::OPENING_BALANCE,
TransactionTypeModel::RECONCILIATION],
AccountType::EXPENSE => [TransactionTypeModel::WITHDRAWAL],
AccountType::REVENUE => [], // is not allowed as destination.
AccountType::LOAN => [TransactionTypeModel::WITHDRAWAL, TransactionTypeModel::DEPOSIT, TransactionTypeModel::TRANSFER,
TransactionTypeModel::OPENING_BALANCE],
AccountType::DEBT => [TransactionTypeModel::WITHDRAWAL, TransactionTypeModel::DEPOSIT, TransactionTypeModel::TRANSFER,
TransactionTypeModel::OPENING_BALANCE],
AccountType::MORTGAGE => [TransactionTypeModel::WITHDRAWAL, TransactionTypeModel::DEPOSIT, TransactionTypeModel::TRANSFER,
TransactionTypeModel::OPENING_BALANCE],
AccountType::INITIAL_BALANCE => [], // todo fill me in.
AccountType::RECONCILIATION => [], // todo fill me in.
],
],
// having the source + dest will tell you the transaction type.
'account_to_transaction' => [
AccountType::ASSET => [
AccountType::ASSET => TransactionTypeModel::TRANSFER,
AccountType::CASH => TransactionTypeModel::WITHDRAWAL,
AccountType::DEBT => TransactionTypeModel::WITHDRAWAL,
AccountType::EXPENSE => TransactionTypeModel::WITHDRAWAL,
AccountType::INITIAL_BALANCE => TransactionTypeModel::OPENING_BALANCE,
AccountType::LOAN => TransactionTypeModel::WITHDRAWAL,
AccountType::MORTGAGE => TransactionTypeModel::WITHDRAWAL,
AccountType::RECONCILIATION => TransactionTypeModel::RECONCILIATION,
],
AccountType::CASH => [
AccountType::ASSET => TransactionTypeModel::DEPOSIT,
],
AccountType::DEBT => [
AccountType::ASSET => TransactionTypeModel::DEPOSIT,
AccountType::DEBT => TransactionTypeModel::TRANSFER,
AccountType::EXPENSE => TransactionTypeModel::WITHDRAWAL,
AccountType::INITIAL_BALANCE => TransactionTypeModel::OPENING_BALANCE,
AccountType::LOAN => TransactionTypeModel::TRANSFER,
AccountType::MORTGAGE => TransactionTypeModel::TRANSFER,
],
AccountType::INITIAL_BALANCE => [
AccountType::ASSET => TransactionTypeModel::OPENING_BALANCE,
AccountType::DEBT => TransactionTypeModel::OPENING_BALANCE,
AccountType::LOAN => TransactionTypeModel::OPENING_BALANCE,
AccountType::MORTGAGE => TransactionTypeModel::OPENING_BALANCE,
],
AccountType::LOAN => [
AccountType::ASSET => TransactionTypeModel::DEPOSIT,
AccountType::DEBT => TransactionTypeModel::TRANSFER,
AccountType::EXPENSE => TransactionTypeModel::WITHDRAWAL,
AccountType::INITIAL_BALANCE => TransactionTypeModel::OPENING_BALANCE,
AccountType::LOAN => TransactionTypeModel::TRANSFER,
AccountType::MORTGAGE => TransactionTypeModel::TRANSFER,
],
AccountType::MORTGAGE => [
AccountType::ASSET => TransactionTypeModel::DEPOSIT,
AccountType::DEBT => TransactionTypeModel::TRANSFER,
AccountType::EXPENSE => TransactionTypeModel::WITHDRAWAL,
AccountType::INITIAL_BALANCE => TransactionTypeModel::OPENING_BALANCE,
AccountType::LOAN => TransactionTypeModel::TRANSFER,
AccountType::MORTGAGE => TransactionTypeModel::TRANSFER,
],
AccountType::RECONCILIATION => [
AccountType::ASSET => TransactionTypeModel::RECONCILIATION,
],
AccountType::REVENUE => [
AccountType::ASSET => TransactionTypeModel::DEPOSIT,
AccountType::DEBT => TransactionTypeModel::DEPOSIT,
AccountType::LOAN => TransactionTypeModel::DEPOSIT,
AccountType::MORTGAGE => TransactionTypeModel::DEPOSIT,
],
],
// allowed source / destination accounts.
'source_dests' => [
'source_dests' => [
TransactionTypeModel::WITHDRAWAL => [
AccountType::ASSET => [AccountType::EXPENSE, AccountType::LOAN, AccountType::DEBT, AccountType::MORTGAGE, AccountType::CASH],
AccountType::LOAN => [AccountType::EXPENSE],

View File

@ -13,12 +13,14 @@
"axios": "^0.17",
"bootstrap-sass": "^3.3.7",
"cross-env": "^5.1",
"jquery": "^3.1.1",
"laravel-mix": "^1.0",
"lodash": "^4.17.4",
"vue": "^2.5.7"
},
"dependencies": {
"font-awesome": "^4.7.0"
"@johmun/vue-tags-input": "^2.0.1",
"font-awesome": "^4.7.0",
"jquery": "^3.1.1",
"uiv": "^0.31.5"
}
}

View File

@ -1,7 +1,3 @@
{
"/v2/js/index.js": "/v2/js/index.js",
"/v2/js/manifest.js": "/v2/js/manifest.js",
"/v2/js/vendor.js": "/v2/js/vendor.js",
"/undefined.js": "/undefined.js",
"/v2/css/app.css": "/v2/css/app.css"
}
"/v1/js/app.js": "/v1/js/app.js"
}

2
public/v1/css/app.css Normal file
View File

@ -0,0 +1,2 @@
/* TODO REMOVE ME */

View File

@ -18,6 +18,14 @@
* along with Firefly III. If not, see <http://www.gnu.org/licenses/>.
*/
input.ti-new-tag-input {
font-size: 14px !important;
line-height: 1.42857143;
color: #555;
font-family:"Source Sans Pro", "Helvetica Neue",Helvetica,Arial,sans-serif !important;
}
.split_amount_input {
width: 40%;
border-radius: 0;
@ -36,6 +44,13 @@
}
.autocomplete-suggestions { border: 1px solid #999; background: #FFF; overflow: auto; }
.autocomplete-suggestion { padding: 2px 5px; white-space: nowrap; overflow: hidden; }
.autocomplete-selected { background: #F0F0F0; }
.autocomplete-suggestions strong { font-weight: normal; color: #3399FF; }
.autocomplete-group { padding: 2px 5px; font-weight: bold;}
.autocomplete-group strong { display: block; border-bottom: 1px solid #000; }
.split_amount_input:focus {
border-color: #98cbe8;
outline: 0;

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,225 @@
/*
* create.js
* Copyright (c) 2019 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/>.
*/
/** global: autoCompleteUri */
$(function () {
"use strict";
initPage();
});
function initPage() {
// recreate buttons and auto-complete things
autoComplete();
makeButtons();
runModernizer();
}
/**
* Reset all click triggers.
*/
function makeButtons() {
$('.clearDestination').unbind('click').on('click', clearDestination);
$('.clearSource').unbind('click').on('click', clearSource);
$('#addSplitButton').unbind('click').on('click', addSplit);
}
function addSplit() {
// clone the latest
var latest =$($('#transactions').children()[$('#transactions').children().length - 1]);
latest.clone(true).appendTo('#transactions');
initPage();
return false;
}
/**
* Code to handle clearing the source account.
* @param e
*/
function clearSource(e) {
console.log('Now clearing source.');
var button = $(e.currentTarget);
// empty value.
$(button.parent().parent().find('input').get(0)).val('');
// reset source account
setSourceAccount(null);
}
/**
* Code to handle clearing the destination account.
* @param e
*/
function clearDestination(e) {
console.log('Now clearing destination.');
var button = $(e.currentTarget);
// empty value.
$(button.parent().parent().find('input').get(0)).val('');
// reset destination account
setDestinationAccount(null);
}
/**
* Set the new source account (from a suggestion).
*
* @param newAccount
*/
function setSourceAccount(newAccount) {
if (null === newAccount) {
console.log('New source account is now null.');
sourceAccount = null;
setAllowedDestinationAccounts(newAccount);
return;
}
console.log('The new source account is now ' + newAccount.value + 'of type ' + newAccount.data.type);
setAllowedDestinationAccounts(newAccount);
sourceAccount = newAccount;
setTransactionType();
}
/**
* Set the new destination account (from a suggestion).
*
* @param newAccount
*/
function setDestinationAccount(newAccount) {
if (null === newAccount) {
console.log('New destination account is now null.');
destinationAccount = null;
setAllowedSourceAccounts(newAccount);
return;
}
console.log('The new destination account is now ' + newAccount.value + 'of type ' + newAccount.data.type);
setAllowedSourceAccounts(newAccount);
sourceAccount = newAccount;
setTransactionType();
}
/**
* Set a new limit on the allowed destination account.
*
* @param newAccount
*/
function setAllowedDestinationAccounts(newAccount) {
if (null === newAccount) {
console.log('Allowed type for destination account is anything.');
destAllowedAccountTypes = [];
return;
}
destAllowedAccountTypes = allowedOpposingTypes.source[newAccount.data.type];
console.log('The destination account must be of type: ', destAllowedAccountTypes);
// todo if the current destination account is not of this type, reset it.
}
/**
* Set a new limit on the allowed destination account.
*
* @param newAccount
*/
function setAllowedSourceAccounts(newAccount) {
if (null === newAccount) {
console.log('Allowed type for source account is anything.');
sourceAllowedAccountTypes = [];
return;
}
sourceAllowedAccountTypes = allowedOpposingTypes.source[newAccount.data.type];
console.log('The source account must be of type: ', sourceAllowedAccountTypes);
// todo if the current destination account is not of this type, reset it.
}
/**
* Create auto complete.
*/
function autoComplete() {
var options = {
serviceUrl: getSourceAutoCompleteURI,
groupBy: 'type',
onSelect: function (suggestion) {
setSourceAccount(suggestion);
}
};
$('.sourceAccountAC').autocomplete(options);
// also select destination account.
var destinationOptions = {
serviceUrl: getDestinationAutoCompleteURI,
groupBy: 'type',
onSelect: function (suggestion) {
setDestinationAccount(suggestion);
}
};
$('.destinationAccountAC').autocomplete(destinationOptions);
}
function setTransactionType() {
if (sourceAccount === undefined || destinationAccount === undefined || sourceAccount === null || destinationAccount === null) {
$('.transactionTypeIndicator').text('');
$('.transactionTypeIndicatorBlock').hide();
console.warn('Not both accounts are known yet.');
return;
}
$('.transactionTypeIndicatorBlock').show();
var expectedType = accountToTypes[sourceAccount.data.type][destinationAccount.data.type];
$('.transactionTypeIndicator').html(creatingTypes[expectedType]);
console.log('Expected transaction type is ' + expectedType);
}
/**
* Returns the auto complete URI for source accounts.
* @returns {string}
*/
function getSourceAutoCompleteURI() {
console.log('Will filter source accounts', sourceAllowedAccountTypes);
return accountAutoCompleteURI + '?types=' + encodeURI(sourceAllowedAccountTypes.join(','));
}
/**
* Returns the auto complete URI for destination accounts.
* @returns {string}
*/
function getDestinationAutoCompleteURI() {
console.log('Will filter destination accounts', destAllowedAccountTypes);
return accountAutoCompleteURI + '?types=' + encodeURI(destAllowedAccountTypes.join(','));
}
/**
* Give date a datepicker if not natively supported.
*/
function runModernizer() {
if (!Modernizr.inputtypes.date) {
$('input[type="date"]').datepicker(
{
dateFormat: 'yy-mm-dd'
}
);
}
}

8
public/v1/js/lib/jquery.autocomplete.min.js vendored Executable file

File diff suppressed because one or more lines are too long

View File

@ -3,10 +3,26 @@
* includes Vue and other libraries. It is a great starting point when
* building robust, powerful web applications using Vue and Laravel.
*/
/* TODO REMOVE ME */
require('./bootstrap');
window.Vue = require('vue');
import * as uiv from 'uiv';
Vue.use(uiv);
// components for create and edit transactions.
Vue.component('budget', require('./components/transactions/Budget.vue'));
Vue.component('custom-transaction-fields', require('./components/transactions/CustomTransactionFields.vue'));
Vue.component('piggy-bank', require('./components/transactions/PiggyBank.vue'));
Vue.component('tags', require('./components/transactions/Tags.vue'));
Vue.component('category', require('./components/transactions/Category.vue'));
Vue.component('amount', require('./components/transactions/Amount.vue'));
Vue.component('foreign-amount', require('./components/transactions/ForeignAmountSelect.vue'));
Vue.component('transaction-type', require('./components/transactions/TransactionType.vue'));
Vue.component('account-select', require('./components/transactions/AccountSelect.vue'));
/**
* Components for OAuth2 tokens.
@ -14,6 +30,7 @@ window.Vue = require('vue');
Vue.component('passport-clients', require('./components/passport/Clients.vue'));
Vue.component('passport-authorized-clients', require('./components/passport/AuthorizedClients.vue'));
Vue.component('passport-personal-access-tokens', require('./components/passport/PersonalAccessTokens.vue'));
Vue.component('create-transaction', require('./components/transactions/CreateTransaction'));
const app = new Vue({

View File

@ -0,0 +1,160 @@
<!--
- AccountSelect.vue
- Copyright (c) 2019 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/>.
-->
<template>
<div class="form-group">
<div class="col-sm-12">
<div class="input-group">
<input
ref="input"
type="text"
:placeholder="title"
:data-index="index"
autocomplete="off"
data-role="input"
v-on:keypress="handleEnter"
:disabled="inputDisabled"
class="form-control"
v-on:submit.prevent
:name="inputName"
:title="title">
<span class="input-group-btn">
<button
v-on:click="clearSource"
class="btn btn-default"
type="button"><i class="fa fa-trash-o"></i></button>
</span>
</div>
<typeahead
:open-on-empty=true
:open-on-focus=true
v-on:input="selectedItem"
:async-src="accountAutoCompleteURI"
v-model="name"
:target="target"
item-key="name"
></typeahead>
</div>
</div>
</template>
<script>
export default {
props: {
inputName: String,
title: String,
index: Number,
transactionType: String,
accountName: {
type: String,
default: ''
},
accountTypeFilters: {
type: Array,
default: function () {
return [];
}
}
},
data() {
return {
accountAutoCompleteURI: null,
name: null,
trType: this.transactionType,
target: null,
inputDisabled: false,
allowedTypes: this.accountTypeFilters
}
},
ready() {
this.name = this.accountName;
},
mounted() {
this.target = this.$refs.input;
let types = this.allowedTypes.join(',');
this.name = this.accountName;
this.accountAutoCompleteURI = document.getElementsByTagName('base')[0].href + "json/accounts?types=" + types + "&query=";
this.triggerTransactionType();
},
watch: {
transactionType() {
this.triggerTransactionType();
},
accountTypeFilters() {
let types = this.accountTypeFilters.join(',');
console.log(this.inputName + '[' + this.index + '] is now searching for: ' + types);
this.accountAutoCompleteURI = document.getElementsByTagName('base')[0].href + "json/accounts?types=" + types + "&query=";
}
},
methods:
{
triggerTransactionType: function () {
if (null === this.transactionType) {
return;
}
this.inputDisabled = false;
if (this.transactionType.toString() !== '' && this.index > 0) {
if (this.transactionType.toString() === 'Transfer') {
this.inputDisabled = true;
// todo: needs to copy value from very first input
return;
}
if (this.transactionType.toString() === 'Withdrawal' && this.inputName.substr(0, 6).toLowerCase() === 'source') {
// todo also clear value?
this.inputDisabled = true;
return;
}
if (this.transactionType.toString() === 'Deposit' && this.inputName.substr(0, 11).toLowerCase() === 'destination') {
// todo also clear value?
this.inputDisabled = true;
}
}
},
selectedItem: function (e) {
if (typeof this.name === 'undefined') {
return;
}
// emit the fact that the user selected a type of account
// (influencing the destination)
this.$emit('select:account', this.name);
},
clearSource: function (e) {
//props.value = '';
this.name = '';
// some event?
this.$emit('clear:value')
},
handleEnter: function (e) {
// todo feels sloppy
if (e.keyCode === 13) {
e.preventDefault();
}
}
}
}
</script>
<style scoped>
</style>

View File

@ -0,0 +1,76 @@
<!--
- Amount.vue
- Copyright (c) 2019 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/>.
-->
<template>
<div class="form-group">
<label class="col-sm-4 control-label" ref="cur"></label>
<div class="col-sm-8">
<input type="number" step="any" class="form-control" name="amount[]"
title="amount" autocomplete="off" placeholder="Amount">
</div>
</div>
</template>
<script>
export default {
name: "Amount",
props: ['source', 'destination', 'transactionType'],
data() {
return {
sourceAccount: this.source,
destinationAccount: this.destination,
type: this.transactionType,
}
},
methods: {
changeData: function () {
if ('' === this.transactionType) {
$(this.$refs.cur).text(this.sourceAccount.currency_name);
return;
}
if (this.transactionType === 'Withdrawal' || this.transactionType === 'Transfer') {
$(this.$refs.cur).text(this.sourceAccount.currency_name);
return;
}
if (this.transactionType === 'Deposit') {
$(this.$refs.cur).text(this.destinationAccount.currency_name);
}
}
},
watch: {
source: function () {
this.changeData();
},
destination: function () {
this.changeData();
},
transactionType: function () {
this.changeData();
}
},
mounted() {
this.changeData();
}
}
</script>
<style scoped>
</style>

View File

@ -0,0 +1,66 @@
<!--
- Budget.vue
- Copyright (c) 2019 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/>.
-->
<template>
<div class="form-group" v-if="typeof this.transactionType !== 'undefined' && this.transactionType === 'Withdrawal'">
<div class="col-sm-12">
<select name="budget[]" class="form-control" v-if="this.budgets.length > 0">
<option v-for="budget in this.budgets">{{budget.name}}</option>
</select>
</div>
</div>
</template>
<script>
export default {
name: "Budget",
props: ['transactionType'],
mounted() {
this.loadBudgets();
},
data() {
return {
budgets: [],
}
},
methods: {
loadBudgets: function () {
let URI = document.getElementsByTagName('base')[0].href + "json/budgets";
axios.get(URI, {}).then((res) => {
this.budgets = [
{
name: '(no budget)',
id: 0,
}
];
for (const key in res.data) {
if (res.data.hasOwnProperty(key) && /^0$|^[1-9]\d*$/.test(key) && key <= 4294967294) {
this.budgets.push(res.data[key]);
}
}
});
}
}
}
</script>
<style scoped>
</style>

View File

@ -0,0 +1,108 @@
<!--
- Category.vue
- Copyright (c) 2019 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/>.
-->
<template>
<div class="form-group">
<div class="col-sm-12">
<div class="input-group">
<input
ref="input"
type="text"
placeholder="Category"
autocomplete="off"
data-role="input"
v-on:keypress="handleEnter"
class="form-control"
v-on:submit.prevent
name="category[]"
title="Category">
<span class="input-group-btn">
<button
v-on:click="clearCategory"
class="btn btn-default"
type="button"><i class="fa fa-trash-o"></i></button>
</span>
</div>
<typeahead
:open-on-empty=true
:open-on-focus=true
v-on:input="selectedItem"
:async-src="categoryAutoCompleteURI"
v-model="name"
:target="target"
item-key="name"
></typeahead>
</div>
</div>
</template>
<script>
export default {
name: "Category",
props: {
inputName: String,
accountName: {
type: String,
default: ''
},
},
data() {
return {
categoryAutoCompleteURI: null,
name: null,
target: null,
}
},
ready() {
this.name = this.accountName;
},
mounted() {
this.target = this.$refs.input;
this.categoryAutoCompleteURI = document.getElementsByTagName('base')[0].href + "json/categories?query=";
//this.triggerTransactionType();
},
methods: {
clearCategory: function () {
//props.value = '';
this.name = '';
// some event?
this.$emit('clear:category')
},
selectedItem: function (e) {
if (typeof this.name === 'undefined') {
return;
}
// emit the fact that the user selected a type of account
// (influencing the destination)
this.$emit('select:category', this.name);
},
handleEnter: function (e) {
// todo feels sloppy
if (e.keyCode === 13) {
e.preventDefault();
}
}
}
}
</script>
<style scoped>
</style>

View File

@ -0,0 +1,301 @@
<!--
- CreateTransaction.vue
- Copyright (c) 2019 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/>.
-->
<template>
<form method="POST" action="xxxx" accept-charset="UTF-8" class="form-horizontal" id="store" enctype="multipart/form-data">
<input name="_token" type="hidden" value="xxx">
<div class="row" v-if="transactions.transactions.length > 1">
<div class="col-lg-6">
<div class="box">
<div class="box-header with-border">
<h3 class="box-title">
Description of the split transaction
</h3>
</div>
<div class="box-body">
<div class="form-group">
<div class="col-sm-12">
<input type="text" class="form-control" name="group_title"
v-model="transactions.group_title"
title="Description of the split transaction" autocomplete="off" placeholder="Description of the split transaction">
<p class="help-block">
If you create a split transaction, there must be a global description for all splits of the transaction.
</p>
</div>
</div>
</div>
</div>
</div>
</div>
<div v-for="(transaction, index) in transactions.transactions">
<div class="row">
<div class="col-lg-12">
<div class="box">
<div class="box-header with-border">
<h3 class="box-title splitTitle">
<span v-if="transactions.transactions.length > 1">Split {{ index+1 }} / {{ transactions.transactions.length }}</span>
<span v-if="transactions.transactions.length === 1">Transaction information</span>
</h3>
</div>
<div class="box-body">
<div class="row">
<div class="col-lg-4">
<account-select
inputName="source[]"
title="Source account"
:accountName="transaction.source_account.name"
:accountTypeFilters="transaction.source_account.allowed_types"
:transactionType="transactionType"
:index="index"
v-on:clear:value="clearSource(index)"
v-on:select:account="selectedSourceAccount(index, $event)"
></account-select>
<account-select
inputName="destination[]"
title="Destination account"
:accountName="transaction.destination_account.name"
:accountTypeFilters="transaction.destination_account.allowed_types"
:transactionType="transactionType"
:index="index"
v-on:clear:value="clearDestination(index)"
v-on:select:account="selectedDestinationAccount(index, $event)"
></account-select>
<div class="form-group">
<div class="col-sm-12">
<input type="text" class="form-control" name="description[]"
:value="transaction.description"
title="Description" autocomplete="off" placeholder="Description">
</div>
</div>
<div class="form-group">
<div class="col-sm-12">
<input type="date" class="form-control" name="date[]"
title="Date" value="" autocomplete="off"
:value="transaction.date"
:disabled="index > 0"
placeholder="Date">
</div>
</div>
<div v-if="index===0">
<transaction-type
:source="transaction.source_account.type"
:destination="transaction.destination_account.type"
v-on:set:transactionType="setTransactionType($event)"
v-on:act:limitSourceType="limitSourceType($event)"
v-on:act:limitDestinationType="limitDestinationType($event)"
></transaction-type>
</div>
</div>
<div class="col-lg-4">
<amount
:source="transaction.source_account"
:destination="transaction.destination_account"
:transactionType="transactionType"
></amount>
<foreign-amount
:source="transaction.source_account"
:destination="transaction.destination_account"
:transactionType="transactionType"
></foreign-amount>
</div>
<div class="col-lg-4">
<budget :transactionType="transactionType"></budget>
<category :transactionType="transactionType"></category>
<piggy-bank :transactionType="transactionType"></piggy-bank>
<tags></tags>
<!-- custom string fields -->
<custom-transaction-fields></custom-transaction-fields>
<!-- custom date fields -->
<!-- custom other fields -->
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-lg-12">
<p>
<button class="btn btn-primary" v-on:click="addTransaction">Add another split</button>
</p>
</div>
</div>
</form>
</template>
<script>
export default {
name: "CreateTransaction",
components: {
},
mounted() {
// not sure if something needs to happen here.
},
ready() {
},
methods: {
addTransaction: function (e) {
let latest = this.transactions.transactions[this.transactions.transactions.length - 1];
this.transactions.transactions.push(latest);
e.preventDefault();
},
setTransactionType: function (type) {
this.transactionType = type;
},
limitSourceType: function (type) {
let i;
for (i = 0; i < this.transactions.transactions.length; i++) {
this.transactions.transactions[i].source_account.allowed_types = [type];
}
},
limitDestinationType: function (type) {
let i;
for (i = 0; i < this.transactions.transactions.length; i++) {
this.transactions.transactions[i].destination_account.allowed_types = [type];
}
},
selectedSourceAccount: function (index, model) {
if (typeof model === 'string') {
// cant change types, only name.
this.transactions.transactions[index].source_account.name = model;
} else {
// todo maybe replace the entire model?
this.transactions.transactions[index].source_account.id = model.id;
this.transactions.transactions[index].source_account.name = model.name;
this.transactions.transactions[index].source_account.type = model.type;
this.transactions.transactions[index].source_account.currency_id = model.currency_id;
this.transactions.transactions[index].source_account.currency_name = model.currency_name;
this.transactions.transactions[index].source_account.currency_code = model.currency_code;
this.transactions.transactions[index].source_account.currency_decimal_places = model.currency_decimal_places;
// force types on destination selector.
this.transactions.transactions[index].destination_account.allowed_types = window.allowedOpposingTypes.source[model.type];
}
},
selectedDestinationAccount: function (index, model) {
if (typeof model === 'string') {
// cant change types, only name.
this.transactions.transactions[index].destination_account.name = model;
} else {
// todo maybe replace the entire model?
this.transactions.transactions[index].destination_account.id = model.id;
this.transactions.transactions[index].destination_account.name = model.name;
this.transactions.transactions[index].destination_account.type = model.type;
this.transactions.transactions[index].destination_account.currency_id = model.currency_id;
this.transactions.transactions[index].destination_account.currency_name = model.currency_name;
this.transactions.transactions[index].destination_account.currency_code = model.currency_code;
this.transactions.transactions[index].destination_account.currency_decimal_places = model.currency_decimal_places;
// force types on destination selector.
this.transactions.transactions[index].source_account.allowed_types = window.allowedOpposingTypes.destination[model.type];
}
},
clearSource: function (index) {
this.transactions.transactions[index].source_account.id = 0;
this.transactions.transactions[index].source_account.name = "";
this.transactions.transactions[index].source_account.type = "";
this.transactions.transactions[index].destination_account.allowed_types = [];
// if there is a destination model, reset the types of the source
// by pretending we selected it again.
if (this.transactions.transactions[index].destination_account) {
console.log('There is a destination account.');
this.selectedDestinationAccount(index, this.transactions.transactions[index].destination_account);
}
},
clearDestination: function (index) {
this.transactions.transactions[index].destination_account.id = 0;
this.transactions.transactions[index].destination_account.name = "";
this.transactions.transactions[index].destination_account.type = "";
this.transactions.transactions[index].source_account.allowed_types = [];
// if there is a source model, reset the types of the destination
// by pretending we selected it again.
if (this.transactions.transactions[index].source_account) {
console.log('There is a source account.');
this.selectedSourceAccount(index, this.transactions.transactions[index].source_account);
}
}
},
/*
* The component's data.
*/
data() {
return {
transactionType: null,
transactions: {
group_title: "",
transactions: [
{
description: "",
date: "",
amount: "",
foreign_amount: "",
source_account: {
id: 0,
name: "",
type: "",
//currency_id: window.defaultCurrency.id,
//currency_name: window.defaultCurrency.name,
//currency_code: window.defaultCurrency.code,
//currency_decimal_places: window.defaultCurrency.decimal_places,
currency_id: 0,
currency_name: '',
currency_code: '',
currency_decimal_places: 2,
allowed_types: []
},
destination_account: {
id: 0,
name: "",
type: "",
//currency_id: window.defaultCurrency.id,
//currency_name: window.defaultCurrency.name,
//currency_code: window.defaultCurrency.code,
//currency_decimal_places: window.defaultCurrency.decimal_places,
currency_id: 0,
currency_name: '',
currency_code: '',
currency_decimal_places: 2,
allowed_types: []
}
}
]
}
};
},
}
</script>
<style scoped>
</style>

View File

@ -0,0 +1,46 @@
<!--
- CustomTransactionFields.vue
- Copyright (c) 2019 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/>.
-->
<template>
</template>
<script>
export default {
name: "CustomTransactionFields",
mounted() {
this.getPreference();
},
methods: {
getPreference() {
const url = document.getElementsByTagName('base')[0].href + 'api/v1/preferences/transaction_journal_optional_fields';
axios.get(url).then(response => {
console.log(response.data.data.attributes);
}).catch(() => console.warn('Oh. Something went wrong'));
},
}
}
</script>
<style scoped>
</style>

View File

@ -0,0 +1,127 @@
<!--
- ForeignAmountSelect.vue
- Copyright (c) 2019 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/>.
-->
<template>
<div class="form-group">
<div class="col-sm-4">
<select class="form-control" name="foreign_currency[]" v-if="this.enabledCurrencies.length > 0">
<option v-for="currency in this.enabledCurrencies" v-if="currency.enabled">{{ currency.name }}</option>
</select>
</div>
<div class="col-sm-8">
<input type="number" step="any" class="form-control" name="foreign_amount[]" v-if="this.enabledCurrencies.length > 0"
title="Foreign amount" autocomplete="off" placeholder="Foreign amount">
</div>
</div>
</template>
<script>
export default {
name: "ForeignAmountSelect",
props: ['source', 'destination', 'transactionType'],
mounted() {
this.loadCurrencies();
},
data() {
return {
currencies: [],
enabledCurrencies: [],
exclude: null
}
},
watch: {
source: function () {
this.changeData();
},
destination: function () {
this.changeData();
},
transactionType: function () {
this.changeData();
}
},
methods: {
changeData: function () {
this.enabledCurrencies = [];
if (this.transactionType === 'Transfer') {
// lock source on currencyID of destination
for (const key in this.currencies) {
if (this.currencies.hasOwnProperty(key) && /^0$|^[1-9]\d*$/.test(key) && key <= 4294967294) {
if (this.currencies[key].id === this.destination.currency_id) {
this.enabledCurrencies.push(this.currencies[key]);
}
}
}
return;
}
// if type is withdrawal, list all but skip the source account ID.
if (this.transactionType === 'Withdrawal' && this.source) {
for (const key in this.currencies) {
if (this.currencies.hasOwnProperty(key) && /^0$|^[1-9]\d*$/.test(key) && key <= 4294967294) {
if (this.source.currency_id !== this.currencies[key].id) {
this.enabledCurrencies.push(this.currencies[key]);
}
}
}
return;
}
// if type is deposit, list all but skip the source account ID.
if (this.transactionType === 'Deposit' && this.destination) {
for (const key in this.currencies) {
if (this.currencies.hasOwnProperty(key) && /^0$|^[1-9]\d*$/.test(key) && key <= 4294967294) {
if (this.destination.currency_id !== this.currencies[key].id) {
this.enabledCurrencies.push(this.currencies[key]);
}
}
}
return;
}
for (const key in this.currencies) {
if (this.currencies.hasOwnProperty(key) && /^0$|^[1-9]\d*$/.test(key) && key <= 4294967294) {
this.enabledCurrencies.push(this.currencies[key]);
}
}
},
loadCurrencies: function () {
let URI = document.getElementsByTagName('base')[0].href + "json/currencies";
axios.get(URI, {}).then((res) => {
this.currencies = [
{
name: '(none)',
id: 0,
enabled: true
}
];
for (const key in res.data) {
if (res.data.hasOwnProperty(key) && /^0$|^[1-9]\d*$/.test(key) && key <= 4294967294) {
this.currencies.push(res.data[key]);
this.enabledCurrencies.push(res.data[key]);
}
}
});
}
}
}
</script>
<style scoped>
</style>

View File

@ -0,0 +1,66 @@
<!--
- PiggyBank.vue
- Copyright (c) 2019 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/>.
-->
<template>
<div class="form-group" v-if="typeof this.transactionType !== 'undefined' && this.transactionType === 'Transfer'">
<div class="col-sm-12">
<select name="piggy_bank[]" class="form-control" v-if="this.piggies.length > 0">
<option v-for="piggy in this.piggies">{{piggy.name}}</option>
</select>
</div>
</div>
</template>
<script>
export default {
name: "PiggyBank",
props: ['transactionType'],
mounted() {
this.loadPiggies();
},
data() {
return {
piggies: [],
}
},
methods: {
loadPiggies: function () {
let URI = document.getElementsByTagName('base')[0].href + "json/piggy-banks";
axios.get(URI, {}).then((res) => {
this.piggies = [
{
name: '(no piggy bank)',
id: 0,
}
];
for (const key in res.data) {
if (res.data.hasOwnProperty(key) && /^0$|^[1-9]\d*$/.test(key) && key <= 4294967294) {
this.piggies.push(res.data[key]);
}
}
});
}
}
}
</script>
<style scoped>
</style>

View File

@ -0,0 +1,82 @@
<!--
- Tags.vue
- Copyright (c) 2019 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/>.
-->
<template>
<div class="form-group">
<div class="col-sm-12">
<vue-tags-input
v-model="tag"
:tags="tags"
classes="form-input"
:autocomplete-items="autocompleteItems"
:add-only-from-autocomplete="false"
@tags-changed="update"
placeholder="Tags"
/>
</div>
</div>
</template>
<script>
import axios from 'axios';
import VueTagsInput from '@johmun/vue-tags-input';
export default {
name: "Tags",
components: {
VueTagsInput
}, data() {
return {
tag: '',
tags: [],
autocompleteItems: [],
debounce: null,
};
},
watch: {
'tag': 'initItems',
},
methods: {
update(newTags) {
this.autocompleteItems = [];
this.tags = newTags;
},
initItems() {
if (this.tag.length < 2) {
return;
}
const url = document.getElementsByTagName('base')[0].href + `json/tags?query=${this.tag}`;
clearTimeout(this.debounce);
this.debounce = setTimeout(() => {
axios.get(url).then(response => {
this.autocompleteItems = response.data.map(a => {
return {text: a.tag};
});
}).catch(() => console.warn('Oh. Something went wrong'));
}, 600);
},
},
}
</script>
<style scoped>
</style>

View File

@ -0,0 +1,90 @@
<!--
- TransactionType.vue
- Copyright (c) 2019 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/>.
-->
<template>
<div class="form-group">
<div class="col-sm-12">
<label v-if="sentence !== ''" class="control-label text-info">
{{ sentence }}
</label>
</div>
</div>
</template>
<script>
export default {
props: {
source: String,
destination: String,
type: String
},
methods: {
changeValue: function () {
if (this.source && this.destination) {
let transactionType = '';
if (window.accountToTypes[this.source]) {
if (window.accountToTypes[this.source][this.destination]) {
transactionType = window.accountToTypes[this.source][this.destination];
} else {
console.warn('User selected an impossible destination.');
}
} else {
console.warn('User selected an impossible source.');
}
if ('' !== transactionType) {
this.transactionType = transactionType;
this.sentence = 'You\'re creating a ' + this.transactionType;
// Must also emit a change to set ALL sources and destinations to this particular type.
this.$emit('act:limitSourceType', this.source);
this.$emit('act:limitDestinationType', this.destination);
}
} else {
this.sentence = '';
this.transactionType = '';
}
// emit event how cool is that.
this.$emit('set:transactionType', this.transactionType);
}
},
data() {
return {
transactionType: this.type,
sentence: ''
}
},
watch: {
source() {
this.changeValue();
},
destination() {
this.changeValue();
}
},
name: "TransactionType"
}
</script>
<style scoped>
</style>

View File

@ -23,35 +23,36 @@
declare(strict_types=1);
return [
'home' => 'Home',
'edit_currency' => 'Edit currency ":name"',
'delete_currency' => 'Delete currency ":name"',
'newPiggyBank' => 'Create a new piggy bank',
'edit_piggyBank' => 'Edit piggy bank ":name"',
'preferences' => 'Preferences',
'profile' => 'Profile',
'changePassword' => 'Change your password',
'change_email' => 'Change your email address',
'bills' => 'Bills',
'newBill' => 'New bill',
'edit_bill' => 'Edit bill ":name"',
'delete_bill' => 'Delete bill ":name"',
'reports' => 'Reports',
'search_result' => 'Search results for ":query"',
'withdrawal_list' => 'Expenses',
'deposit_list' => 'Revenue, income and deposits',
'transfer_list' => 'Transfers',
'transfers_list' => 'Transfers',
'reconciliation_list' => 'Reconciliations',
'create_withdrawal' => 'Create new withdrawal',
'create_deposit' => 'Create new deposit',
'create_transfer' => 'Create new transfer',
'edit_journal' => 'Edit transaction ":description"',
'edit_reconciliation' => 'Edit ":description"',
'delete_journal' => 'Delete transaction ":description"',
'tags' => 'Tags',
'createTag' => 'Create new tag',
'edit_tag' => 'Edit tag ":tag"',
'delete_tag' => 'Delete tag ":tag"',
'delete_journal_link' => 'Delete link between transactions',
'home' => 'Home',
'edit_currency' => 'Edit currency ":name"',
'delete_currency' => 'Delete currency ":name"',
'newPiggyBank' => 'Create a new piggy bank',
'edit_piggyBank' => 'Edit piggy bank ":name"',
'preferences' => 'Preferences',
'profile' => 'Profile',
'changePassword' => 'Change your password',
'change_email' => 'Change your email address',
'bills' => 'Bills',
'newBill' => 'New bill',
'edit_bill' => 'Edit bill ":name"',
'delete_bill' => 'Delete bill ":name"',
'reports' => 'Reports',
'search_result' => 'Search results for ":query"',
'withdrawal_list' => 'Expenses',
'deposit_list' => 'Revenue, income and deposits',
'transfer_list' => 'Transfers',
'transfers_list' => 'Transfers',
'reconciliation_list' => 'Reconciliations',
'create_withdrawal' => 'Create new withdrawal',
'create_deposit' => 'Create new deposit',
'create_transfer' => 'Create new transfer',
'create_new_transaction' => 'Create a new transaction',
'edit_journal' => 'Edit transaction ":description"',
'edit_reconciliation' => 'Edit ":description"',
'delete_journal' => 'Delete transaction ":description"',
'tags' => 'Tags',
'createTag' => 'Create new tag',
'edit_tag' => 'Edit tag ":tag"',
'delete_tag' => 'Delete tag ":tag"',
'delete_journal_link' => 'Delete link between transactions',
];

View File

@ -1148,7 +1148,7 @@ return [
'deleted_piggy_bank' => 'Deleted piggy bank ":name"',
'added_amount_to_piggy' => 'Added :amount to ":name"',
'removed_amount_from_piggy' => 'Removed :amount from ":name"',
'piggy_events' => 'Related piggy banks',
'piggy_events' => 'Related piggy banks',
// tags
'delete_tag' => 'Delete tag ":tag"',
@ -1158,49 +1158,57 @@ return [
'updated_tag' => 'Updated tag ":tag"',
'created_tag' => 'Tag ":tag" has been created!',
'transaction_journal_information' => 'Transaction information',
'transaction_journal_meta' => 'Meta information',
'transaction_journal_more' => 'More information',
'att_part_of_journal' => 'Stored under ":journal"',
'total_amount' => 'Total amount',
'number_of_decimals' => 'Number of decimals',
'transaction_journal_information' => 'Transaction information',
'transaction_journal_meta' => 'Meta information',
'transaction_journal_more' => 'More information',
'att_part_of_journal' => 'Stored under ":journal"',
'total_amount' => 'Total amount',
'number_of_decimals' => 'Number of decimals',
// administration
'administration' => 'Administration',
'user_administration' => 'User administration',
'list_all_users' => 'All users',
'all_users' => 'All users',
'instance_configuration' => 'Configuration',
'firefly_instance_configuration' => 'Configuration options for Firefly III',
'setting_single_user_mode' => 'Single user mode',
'setting_single_user_mode_explain' => 'By default, Firefly III only accepts one (1) registration: you. This is a security measure, preventing others from using your instance unless you allow them to. Future registrations are blocked. When you uncheck this box, others can use your instance as well, assuming they can reach it (when it is connected to the internet).',
'store_configuration' => 'Store configuration',
'single_user_administration' => 'User administration for :email',
'edit_user' => 'Edit user :email',
'hidden_fields_preferences' => 'Not all fields are visible right now. You must enable them in your <a href=":link">settings</a>.',
'user_data_information' => 'User data',
'user_information' => 'User information',
'total_size' => 'total size',
'budget_or_budgets' => 'budget(s)',
'budgets_with_limits' => 'budget(s) with configured amount',
'nr_of_rules_in_total_groups' => ':count_rules rule(s) in :count_groups rule group(s)',
'tag_or_tags' => 'tag(s)',
'configuration_updated' => 'The configuration has been updated',
'setting_is_demo_site' => 'Demo site',
'setting_is_demo_site_explain' => 'If you check this box, this installation will behave as if it is the demo site, which can have weird side effects.',
'block_code_bounced' => 'Email message(s) bounced',
'block_code_expired' => 'Demo account expired',
'no_block_code' => 'No reason for block or user not blocked',
'block_code_email_changed' => 'User has not yet confirmed new email address',
'admin_update_email' => 'Contrary to the profile page, the user will NOT be notified their email address has changed!',
'update_user' => 'Update user',
'updated_user' => 'User data has been changed.',
'delete_user' => 'Delete user :email',
'user_deleted' => 'The user has been deleted',
'send_test_email' => 'Send test email message',
'send_test_email_text' => 'To see if your installation is capable of sending email, please press this button. You will not see an error here (if any), <strong>the log files will reflect any errors</strong>. You can press this button as many times as you like. There is no spam control. The message will be sent to <code>:email</code> and should arrive shortly.',
'send_message' => 'Send message',
'send_test_triggered' => 'Test was triggered. Check your inbox and the log files.',
'administration' => 'Administration',
'user_administration' => 'User administration',
'list_all_users' => 'All users',
'all_users' => 'All users',
'instance_configuration' => 'Configuration',
'firefly_instance_configuration' => 'Configuration options for Firefly III',
'setting_single_user_mode' => 'Single user mode',
'setting_single_user_mode_explain' => 'By default, Firefly III only accepts one (1) registration: you. This is a security measure, preventing others from using your instance unless you allow them to. Future registrations are blocked. When you uncheck this box, others can use your instance as well, assuming they can reach it (when it is connected to the internet).',
'store_configuration' => 'Store configuration',
'single_user_administration' => 'User administration for :email',
'edit_user' => 'Edit user :email',
'hidden_fields_preferences' => 'You can enable more transaction options in your <a href=":link">settings</a>.',
'user_data_information' => 'User data',
'user_information' => 'User information',
'total_size' => 'total size',
'budget_or_budgets' => 'budget(s)',
'budgets_with_limits' => 'budget(s) with configured amount',
'nr_of_rules_in_total_groups' => ':count_rules rule(s) in :count_groups rule group(s)',
'tag_or_tags' => 'tag(s)',
'configuration_updated' => 'The configuration has been updated',
'setting_is_demo_site' => 'Demo site',
'setting_is_demo_site_explain' => 'If you check this box, this installation will behave as if it is the demo site, which can have weird side effects.',
'block_code_bounced' => 'Email message(s) bounced',
'block_code_expired' => 'Demo account expired',
'no_block_code' => 'No reason for block or user not blocked',
'block_code_email_changed' => 'User has not yet confirmed new email address',
'admin_update_email' => 'Contrary to the profile page, the user will NOT be notified their email address has changed!',
'update_user' => 'Update user',
'updated_user' => 'User data has been changed.',
'delete_user' => 'Delete user :email',
'user_deleted' => 'The user has been deleted',
'send_test_email' => 'Send test email message',
'send_test_email_text' => 'To see if your installation is capable of sending email, please press this button. You will not see an error here (if any), <strong>the log files will reflect any errors</strong>. You can press this button as many times as you like. There is no spam control. The message will be sent to <code>:email</code> and should arrive shortly.',
'send_message' => 'Send message',
'send_test_triggered' => 'Test was triggered. Check your inbox and the log files.',
'split_transaction_title' => 'Description of the split transaction',
'split_title_help' => 'If you create a split transaction, there must be a global description for all splits of the transaction.',
'transaction_information' => 'Transaction information',
'you_create_transfer' => 'You\'re creating a <strong>transfer</strong>.',
'you_create_withdrawal' => 'You\'re creating a <strong>withdrawal</strong>.',
'you_create_deposit' => 'You\'re creating a <strong>deposit</strong>.',
// links
'journal_link_configuration' => 'Transaction links configuration',

View File

@ -57,6 +57,7 @@ return [
'asset_source_account' => 'Source account',
'journal_description' => 'Description',
'note' => 'Notes',
'store_new_transaction' => 'Store new transaction',
'split_journal' => 'Split this transaction',
'split_journal_explanation' => 'Split this transaction in multiple parts',
'currency' => 'Currency',

View File

@ -31,18 +31,4 @@
</div>
</div>
{% endif %}
{% if type == 'create' and name == 'transaction' %}
<div class="form-group">
<label for="{{ name }}_split" class="col-sm-4 control-label">
{{ trans('form.split_journal') }}
</label>
<div class="col-sm-8">
<div class="checkbox"><label>
{{ Form.checkbox('split_journal', '1', old('split_journal') == '1', {'id': name ~ 'split'}) }}
{{ trans('form.split_journal_explanation') }}
</label>
</div>
</div>
</div>
{% endif %}

View File

@ -193,8 +193,8 @@
{% if not shownDemo %}
<script type="text/javascript">
var routeForTour = "{{ current_route_name }}";
var routeStepsUri = "{{ route('json.intro', [current_route_name, what|default("")]) }}";
var routeForFinishedTour = "{{ route('json.intro.finished', [current_route_name, what|default("")]) }}";
var routeStepsUri = "{{ route('json.intro', [current_route_name, objectType|default("")]) }}";
var routeForFinishedTour = "{{ route('json.intro.finished', [current_route_name, objectType|default("")]) }}";
</script>
<script type="text/javascript" src="v1/lib/intro/intro.min.js?v={{ FF_VERSION }}"></script>
<script type="text/javascript" src="v1/js/ff/intro/intro.js?v={{ FF_VERSION }}"></script>

View File

@ -1,7 +1,9 @@
<table class="table">
<thead>
<tr>
<th>X</th>
<th>
{{ groups.render }}
</th>
</tr>
</thead>
<tbody>

View File

@ -12,22 +12,22 @@
</span>
</a>
<ul class="treeview-menu">
<li class="{{ activeRoutePartialWhat('accounts', 'asset') }}">
<li class="{{ activeRoutePartialObjectType('accounts', 'asset') }}">
<a href="{{ route('accounts.index','asset') }}">
<i class="fa fa-money fa-fw"></i> {{ 'asset_accounts'|_ }}
</a>
</li>
<li class="{{ activeRoutePartialWhat('accounts', 'expense') }}">
<li class="{{ activeRoutePartialObjectType('accounts', 'expense') }}">
<a href="{{ route('accounts.index','expense') }}">
<i class="fa fa-shopping-cart fa-fw"></i> {{ 'expense_accounts'|_ }}
</a>
</li>
<li class="{{ activeRoutePartialWhat('accounts', 'revenue') }}">
<li class="{{ activeRoutePartialObjectType('accounts', 'revenue') }}">
<a href="{{ route('accounts.index','revenue') }}">
<i class="fa fa-download fa-fw"></i> {{ 'revenue_accounts'|_ }}
</a>
</li>
<li class="{{ activeRoutePartialWhat('accounts', 'liabilities') }}">
<li class="{{ activeRoutePartialObjectType('accounts', 'liabilities') }}">
<a href="{{ route('accounts.index','liabilities') }}">
<i class="fa fa-ticket fa-fw"></i> {{ 'liabilities_accounts'|_ }}
</a>
@ -67,15 +67,15 @@
</span>
</a>
<ul class="treeview-menu">
<li class="{{ activeRoutePartialWhat('transactions','withdrawal') }}">
<li class="{{ activeRoutePartialObjectType('transactions','withdrawal') }}">
<a href="{{ route('transactions.index','withdrawal') }}">
<i class="fa fa-long-arrow-left fa-fw"></i> {{ 'expenses'|_ }}</a>
</li>
<li class="{{ activeRoutePartialWhat('transactions','deposit') }}">
<li class="{{ activeRoutePartialObjectType('transactions','deposit') }}">
<a href="{{ route('transactions.index','deposit') }}"><i
class="fa fa-long-arrow-right fa-fw"></i> {{ 'income'|_ }}</a>
</li>
<li class="{{ activeRoutePartialWhat('transactions','transfers') }}">
<li class="{{ activeRoutePartialObjectType('transactions','transfers') }}">
<a href="{{ route('transactions.index','transfers') }}">
<i class="fa fa-fw fa-exchange"></i> {{ 'transfers'|_ }}</a>
</li>

View File

@ -0,0 +1,288 @@
{% extends "./layout/default" %}
{% block breadcrumbs %}
{{ Breadcrumbs.render(Route.getCurrentRoute.getName, objectType) }}
{% endblock %}
{% block content %}
<create-transaction></create-transaction>
{#
<form method="POST" action="{{ route('transactions.store') }}" accept-charset="UTF-8" class="form-horizontal" id="store" enctype="multipart/form-data">
<input name="_token" type="hidden" value="{{ csrf_token() }}">
<div class="row">
<div class="col-lg-6">
<div class="box">
<div class="box-header with-border">
<h3 class="box-title">
{{ 'split_transaction_title'|_ }}
</h3>
</div>
<div class="box-body">
<div class="form-group">
<div class="col-sm-12">
<input type="text" class="form-control" name="group_title"
title="{{ 'split_transaction_title'|_ }}" autocomplete="off" placeholder="{{ 'split_transaction_title'|_ }}">
<p class="help-block">
{{ 'split_title_help'|_ }}
</p>
</div>
</div>
</div>
</div>
</div>
</div>
<div id="transactions">
<div class="row transactionRow">
<div class="col-lg-12">
<div class="box">
<div class="box-header with-border">
<h3 class="box-title splitTitle">
{{ 'transaction_information'|_ }}
</h3>
</div>
<div class="box-body">
<div class="row">
<div class="col-lg-4">
<div class="form-group transactionTypeIndicatorBlock" style="display:none;">
<div class="col-sm-12">
<label class="control-label transactionTypeIndicator text-info"></label>
</div>
</div>
<div class="form-group">
<div class="col-sm-12">
<div class="input-group">
<input type="text" data-index="0" class="form-control indexField sourceAccountAC" name="source[]"
title="{{ trans('form.source_account') }}" autocomplete="off"
placeholder="{{ trans('form.source_account') }}">
<span class="input-group-btn">
<button class="btn btn-default clearSource" type="button"><i class="fa fa-trash-o"></i></button>
</span>
</div>
</div>
</div>
<div class="form-group">
<div class="col-sm-12">
<div class="input-group">
<input data-index="0" type="text" class="form-control indexField destinationAccountAC" name="destination[]"
title="{{ trans('form.destination_account') }}" autocomplete="off"
placeholder="{{ trans('form.destination_account') }}">
<span class="input-group-btn">
<button class="btn btn-default clearDestination" type="button"><i class="fa fa-trash-o"></i></button>
</span>
</div>
</div>
</div>
<div class="form-group">
<div class="col-sm-12">
<input type="text" class="form-control" name="description[]"
title="{{ trans('form.description') }}" autocomplete="off" placeholder="{{ trans('form.description') }}">
</div>
</div>
<div class="form-group">
<div class="col-sm-12">
<input type="date" class="form-control" name="date[]"
title="{{ trans('form.date') }}" value="{{ phpdate('Y-m-d') }}" autocomplete="off"
placeholder="{{ trans('form.date') }}">
</div>
</div>
</div>
<div class="col-lg-4">
<div class="form-group">
<label class="col-sm-3 control-label">$</label>
<div class="col-sm-9">
<input type="number" step="any" class="form-control" name="amount[]"
title="{{ trans('form.amount') }}" autocomplete="off" placeholder="{{ trans('form.amount') }}">
</div>
</div>
<div class="form-group">
<div class="col-sm-3">
<select name="foreign_amount">
<option>none</option>
<option>USD</option>
</select>
</div>
<div class="col-sm-9">
<input type="number" step="any" class="form-control" name="amount[]"
title="Foreign amount" autocomplete="off" placeholder="Foreign amount">
</div>
</div>
</div>
<div class="col-lg-4">
<div class="form-group">
<div class="col-sm-12">
<select name="budget">
<option>budget</option>
</select>
</div>
</div>
<div class="form-group">
<div class="col-sm-12">
<input type="text" class="form-control" name="category[]"
title="Category" autocomplete="off" placeholder="Category">
</div>
</div>
<div class="form-group">
<div class="col-sm-12">
<input type="text" class="form-control" name="tags[]"
title="Tags" autocomplete="off" placeholder="Tags">
</div>
</div>
<div class="form-group">
<div class="col-sm-12">
<select name="piggy">
<option>Piggy</option>
</select>
</div>
</div>
{% if
optionalFields.interest_date or optionalFields.book_date or optionalFields.process_date
or optionalFields.due_date or optionalFields.payment_date
or optionalFields.invoice_date %}
{% for field in ['interest_date','book_date','process_date','due_date','payment_date','invoice_date'] %}
{% if optionalFields[field] %}
<div class="form-group">
<div class="col-sm-12">
<input type="text" class="form-control" name="{{ field }}[]"
title="{{ field }}" autocomplete="off" placeholder="{{ field }}">
</div>
</div>
{% endif %}
{% endfor %}
{% endif %}
{% if optionalFields.internal_reference or optionalFields.notes %}
{% if optionalFields.internal_reference %}
<div class="form-group">
<div class="col-sm-12">
<input type="text" class="form-control" name="internal_reference[]"
title="internal_reference" autocomplete="off" placeholder="internal_reference">
</div>
</div>
{% endif %}
{% if optionalFields.notes %}
<div class="form-group">
<div class="col-sm-12">
<textarea></textarea>
<br>
{{ trans('firefly.field_supports_markdown')|raw }}
</div>
</div>
{% endif %}
{% endif %}
{% if optionalFields.attachments %}
<div class="form-group">
<div class="col-sm-12">
<input multiple="multiple" class="form-control"
autocomplete="off" placeholder="Attachments" name="attachments[]" type="file">
<p class="help-block">
{{ trans('firefly.upload_max_file_size', {'size': uploadSize|filesize}) }}
</p>
</div>
</div>
{% endif %}
{% if
not optionalFields.interest_date or
not optionalFields.book_date or
not optionalFields.process_date or
not optionalFields.due_date or
not optionalFields.payment_date or
not optionalFields.invoice_date or
not optionalFields.internal_reference or
not optionalFields.notes or
not optionalFields.attachments %}
<div class="form-group">
<div class="col-sm-12">
<p class="text-success"><i class="fa fa-info-circle"></i>
<em>{{ trans('firefly.hidden_fields_preferences', {link: route('preferences.index')})|raw }}</em></p>
</div>
</div>
{% endif %}
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-lg-12">
<p>
<button id="addSplitButton" class="btn btn-primary">Add another split</button>
</p>
</div>
</div>
<div class="row">
<div class="col-lg-6">
<div class="box">
<div class="box-header with-border">
<h3 class="box-title">{{ 'options'|_ }}</h3>
</div>
<div class="box-body">
{{ ExpandedForm.optionsList('create','transaction') }}
</div>
<div class="box-footer">
<button type="submit" class="transaction-btn btn btn-success pull-right">
{{ trans('form.store_new_transaction') }}
</button>
</div>
</div>
</div>
</div>
</form>
#}
{% endblock %}
{% block scripts %}
<script type="text/javascript">
var allowedOpposingTypes = {{ allowedOpposingTypes|json_encode|raw }};
var accountToTypes = {{ accountToTypes|json_encode|raw }};
var defaultCurrency = {{ defaultCurrency.toArray()|json_encode|raw }};
</script>
<!--
<script type="text/javascript">
var transactionType = 'none';
var accountToTypes = {{ accountToTypes|json_encode|raw }};
var creatingTypes = {
Transfer: "{{ 'you_create_transfer'|_ }}",
Withdrawal: "{{ 'you_create_withdrawal'|_ }}",
Deposit: "{{ 'you_create_deposit'|_ }}",
};
// options for source account selection.
var sourceAccount = null;
var sourceAllowedAccountTypes = [];
// options for destination account selection.
var destinationAccount = null;
var destAllowedAccountTypes = [];
</script>
<script type="text/javascript" src="v1/js/lib/modernizr-custom.js?v={{ FF_VERSION }}"></script>
<script type="text/javascript" src="v1/js/lib/jquery.autocomplete.min.js?v={{ FF_VERSION }}"></script>
<script type="text/javascript" src="v1/js/ff/transactions/create.js?v={{ FF_VERSION }}"></script>
-->
{% endblock %}
{% block styles %}
{% endblock %}

View File

@ -31,7 +31,7 @@
{% endif %}
</div>
{# actual list #}
{% include 'list.transactions' %}
{% include 'list.groups' %}
</div>
<div class="box-footer">
{# links for other views #}

View File

@ -1022,9 +1022,9 @@ try {
Breadcrumbs::register(
'transactions.create',
function (BreadcrumbsGenerator $breadcrumbs, string $what) {
$breadcrumbs->parent('transactions.index', $what);
$breadcrumbs->push(trans('breadcrumbs.create_' . e($what)), route('transactions.create', [$what]));
function (BreadcrumbsGenerator $breadcrumbs, string $objectType) {
$breadcrumbs->parent('transactions.index', $objectType);
$breadcrumbs->push(trans('breadcrumbs.create_new_transaction'), route('transactions.create', [$objectType]));
}
);

View File

@ -546,14 +546,20 @@ Route::group(
['middleware' => 'user-full-auth', 'namespace' => 'FireflyIII\Http\Controllers', 'prefix' => 'json', 'as' => 'json.'], function () {
// for auto complete
Route::get('accounts', ['uses' => 'Json\AutoCompleteController@accounts', 'as' => 'autocomplete.accounts']);
Route::get('currencies', ['uses' => 'Json\AutoCompleteController@currencies', 'as' => 'autocomplete.currencies']);
Route::get('budgets', ['uses' => 'Json\AutoCompleteController@budgets', 'as' => 'autocomplete.budgets']);
Route::get('categories', ['uses' => 'Json\AutoCompleteController@categories', 'as' => 'autocomplete.categories']);
Route::get('piggy-banks', ['uses' => 'Json\AutoCompleteController@piggyBanks', 'as' => 'autocomplete.piggy-banks']);
Route::get('tags', ['uses' => 'Json\AutoCompleteController@tags', 'as' => 'autocomplete.tags']);
// TODO improve 3 routes:
Route::get('transaction-journals/all', ['uses' => 'Json\AutoCompleteController@allTransactionJournals', 'as' => 'all-transaction-journals']);
Route::get('transaction-journals/with-id/{tj}', ['uses' => 'Json\AutoCompleteController@journalsWithId', 'as' => 'journals-with-id']);
Route::get('transaction-journals/{what}', ['uses' => 'Json\AutoCompleteController@transactionJournals', 'as' => 'transaction-journals']);
//Route::get('transaction-journals/all', ['uses' => 'Json\AutoCompleteController@allTransactionJournals', 'as' => 'all-transaction-journals']);
//Route::get('transaction-journals/with-id/{tj}', ['uses' => 'Json\AutoCompleteController@journalsWithId', 'as' => 'journals-with-id']);
//Route::get('transaction-journals/{what}', ['uses' => 'Json\AutoCompleteController@transactionJournals', 'as' => 'transaction-journals']);
// TODO end of improvement
Route::get('transaction-types', ['uses' => 'Json\AutoCompleteController@transactionTypes', 'as' => 'transaction-types']);
// boxes
@ -577,7 +583,7 @@ Route::group(
Route::post('intro/enable/{route}/{specificPage?}', ['uses' => 'Json\IntroController@postEnable', 'as' => 'intro.enable']);
Route::get('intro/{route}/{specificPage?}', ['uses' => 'Json\IntroController@getIntroSteps', 'as' => 'intro']);
Route::get('/{subject}', ['uses' => 'Json\AutoCompleteController@autoComplete', 'as' => 'autocomplete']);
//Route::get('/{subject}', ['uses' => 'Json\AutoCompleteController@autoComplete', 'as' => 'autocomplete']);
}
);
@ -873,11 +879,13 @@ Route::group(
Route::group(
['middleware' => 'user-full-auth', 'namespace' => 'FireflyIII\Http\Controllers', 'prefix' => 'transactions', 'as' => 'transactions.'], function () {
// show groups:
Route::get('{what}/{start_date?}/{end_date?}', ['uses' => 'Transaction\IndexController@index', 'as' => 'index'])->where(
['what' => 'withdrawal|deposit|transfers|transfer']
);
// create group:
Route::get('create/{objectType}', ['uses' => 'Transaction\CreateController@create', 'as' => 'create'])->where(['objectType' => 'withdrawal|deposit|transfer']);
// TODO improve these routes
@ -903,7 +911,7 @@ Route::group(
['middleware' => 'user-full-auth', 'namespace' => 'FireflyIII\Http\Controllers\Transaction', 'prefix' => 'transactions', 'as' => 'transactions.'],
function () {
// TODO improve these routes
Route::get('create/{what}', ['uses' => 'SingleController@create', 'as' => 'create'])->where(['what' => 'withdrawal|deposit|transfer']);
Route::get('edit/{tj}', ['uses' => 'SingleController@edit', 'as' => 'edit']);
Route::get('delete/{tj}', ['uses' => 'SingleController@delete', 'as' => 'delete']);
Route::post('store', ['uses' => 'SingleController@store', 'as' => 'store'])->where(['what' => 'withdrawal|deposit|transfer']);

View File

@ -11,4 +11,4 @@ let mix = require('laravel-mix');
|
*/
mix.js('resources/assets/js/app.js', 'public/v1/js');
mix.js('resources/assets/js/app.js', 'public/v1/js');

View File

@ -2,6 +2,13 @@
# yarn lockfile v1
"@johmun/vue-tags-input@^2.0.1":
version "2.0.1"
resolved "https://registry.yarnpkg.com/@johmun/vue-tags-input/-/vue-tags-input-2.0.1.tgz#5ca22a573858c8df6c05788e3ffabe92e1baa1df"
integrity sha512-1LUsINr6iBROfG31C05qf+XpoM4jLstpLzTmfu+57fxErgP2gGnVB41oz1qVxjKe1gdpOaAZSByhoAm2h0cO3w==
dependencies:
vue "^2.5.16"
"@types/q@^1.5.1":
version "1.5.1"
resolved "https://registry.yarnpkg.com/@types/q/-/q-1.5.1.tgz#48fd98c1561fe718b61733daed46ff115b496e18"
@ -7974,6 +7981,13 @@ uglifyjs-webpack-plugin@^1.0.0:
webpack-sources "^1.1.0"
worker-farm "^1.5.2"
uiv@^0.31.5:
version "0.31.5"
resolved "https://registry.yarnpkg.com/uiv/-/uiv-0.31.5.tgz#bfb87833b9abb59d8f0bb4f630943449b053b733"
integrity sha512-VcizUxkJCr4XhnFJ3KWCuiVaDvU3H5yDLX4F1yhrmK5hz+2+OIuCShJd6Is366oJdJagoh42sjWQqZL74uMEmw==
dependencies:
vue-functional-data-merge "^2.0.3"
unbzip2-stream@^1.0.9:
version "1.3.1"
resolved "https://registry.yarnpkg.com/unbzip2-stream/-/unbzip2-stream-1.3.1.tgz#7854da51622a7e63624221196357803b552966a1"
@ -8252,6 +8266,11 @@ vm-browserify@0.0.4:
dependencies:
indexof "0.0.1"
vue-functional-data-merge@^2.0.3:
version "2.0.7"
resolved "https://registry.yarnpkg.com/vue-functional-data-merge/-/vue-functional-data-merge-2.0.7.tgz#bdee655181eacdcb1f96ce95a4cc14e75313d1da"
integrity sha512-pvLc+H+x2prwBj/uSEIITyxjz/7ZUVVK8uYbrYMmhDvMXnzh9OvQvVEwcOSBQjsubd4Eq41/CSJaWzy4hemMNQ==
vue-hot-reload-api@^2.2.0:
version "2.3.1"
resolved "https://registry.yarnpkg.com/vue-hot-reload-api/-/vue-hot-reload-api-2.3.1.tgz#b2d3d95402a811602380783ea4f566eb875569a2"
@ -8297,6 +8316,11 @@ vue-template-es2015-compiler@^1.6.0:
resolved "https://registry.yarnpkg.com/vue-template-es2015-compiler/-/vue-template-es2015-compiler-1.6.0.tgz#dc42697133302ce3017524356a6c61b7b69b4a18"
integrity sha512-x3LV3wdmmERhVCYy3quqA57NJW7F3i6faas++pJQWtknWT+n7k30F4TVdHvCLn48peTJFRvCpxs3UuFPqgeELg==
vue@^2.5.16:
version "2.6.10"
resolved "https://registry.yarnpkg.com/vue/-/vue-2.6.10.tgz#a72b1a42a4d82a721ea438d1b6bf55e66195c637"
integrity sha512-ImThpeNU9HbdZL3utgMCq0oiMzAkt1mcgy3/E6zWC/G6AaQoeuFdsl9nDhTDU3X1R6FK7nsIUuRACVcjI+A2GQ==
vue@^2.5.7:
version "2.5.21"
resolved "https://registry.yarnpkg.com/vue/-/vue-2.5.21.tgz#3d33dcd03bb813912ce894a8303ab553699c4a85"