mirror of
https://github.com/firefly-iii/firefly-iii.git
synced 2025-09-24 22:48:18 +00:00
Lots of new code for new transaction screen.
This commit is contained in:
@@ -45,7 +45,7 @@ echo "Discover packages..."
|
|||||||
php artisan package:discover
|
php artisan package:discover
|
||||||
|
|
||||||
echo "Run various artisan commands..."
|
echo "Run various artisan commands..."
|
||||||
. $FIREFLY_PATH/.env
|
#. $FIREFLY_PATH/.env
|
||||||
if [[ -z "$DB_PORT" ]]; then
|
if [[ -z "$DB_PORT" ]]; then
|
||||||
if [[ $DB_CONNECTION == "pgsql" ]]; then
|
if [[ $DB_CONNECTION == "pgsql" ]]; then
|
||||||
DB_PORT=5432
|
DB_PORT=5432
|
||||||
|
@@ -543,6 +543,15 @@ return [
|
|||||||
TransactionTypeModel::OPENING_BALANCE => [AccountType::INITIAL_BALANCE, AccountType::ASSET, AccountType::LOAN, AccountType::DEBT,
|
TransactionTypeModel::OPENING_BALANCE => [AccountType::INITIAL_BALANCE, AccountType::ASSET, AccountType::LOAN, AccountType::DEBT,
|
||||||
AccountType::MORTGAGE],
|
AccountType::MORTGAGE],
|
||||||
TransactionTypeModel::RECONCILIATION => [AccountType::RECONCILIATION, AccountType::ASSET],
|
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' => [
|
'destination' => [
|
||||||
TransactionTypeModel::WITHDRAWAL => [AccountType::EXPENSE, AccountType::CASH, AccountType::LOAN, AccountType::DEBT,
|
TransactionTypeModel::WITHDRAWAL => [AccountType::EXPENSE, AccountType::CASH, AccountType::LOAN, AccountType::DEBT,
|
||||||
@@ -554,6 +563,127 @@ return [
|
|||||||
TransactionTypeModel::RECONCILIATION => [AccountType::RECONCILIATION, AccountType::ASSET],
|
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.
|
// allowed source / destination accounts.
|
||||||
'source_dests' => [
|
'source_dests' => [
|
||||||
|
@@ -13,12 +13,14 @@
|
|||||||
"axios": "^0.17",
|
"axios": "^0.17",
|
||||||
"bootstrap-sass": "^3.3.7",
|
"bootstrap-sass": "^3.3.7",
|
||||||
"cross-env": "^5.1",
|
"cross-env": "^5.1",
|
||||||
"jquery": "^3.1.1",
|
|
||||||
"laravel-mix": "^1.0",
|
"laravel-mix": "^1.0",
|
||||||
"lodash": "^4.17.4",
|
"lodash": "^4.17.4",
|
||||||
"vue": "^2.5.7"
|
"vue": "^2.5.7"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"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"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,7 +1,3 @@
|
|||||||
{
|
{
|
||||||
"/v2/js/index.js": "/v2/js/index.js",
|
"/v1/js/app.js": "/v1/js/app.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"
|
|
||||||
}
|
}
|
2
public/v1/css/app.css
vendored
Normal file
2
public/v1/css/app.css
vendored
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
/* TODO REMOVE ME */
|
||||||
|
|
15
public/v1/css/firefly.css
vendored
15
public/v1/css/firefly.css
vendored
@@ -18,6 +18,14 @@
|
|||||||
* along with Firefly III. If not, see <http://www.gnu.org/licenses/>.
|
* 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 {
|
.split_amount_input {
|
||||||
width: 40%;
|
width: 40%;
|
||||||
border-radius: 0;
|
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 {
|
.split_amount_input:focus {
|
||||||
border-color: #98cbe8;
|
border-color: #98cbe8;
|
||||||
outline: 0;
|
outline: 0;
|
||||||
|
53455
public/v1/js/app.js
vendored
53455
public/v1/js/app.js
vendored
File diff suppressed because one or more lines are too long
225
public/v1/js/ff/transactions/create.js
vendored
Normal file
225
public/v1/js/ff/transactions/create.js
vendored
Normal 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
8
public/v1/js/lib/jquery.autocomplete.min.js
vendored
Executable file
File diff suppressed because one or more lines are too long
19
resources/assets/js/app.js
vendored
19
resources/assets/js/app.js
vendored
@@ -3,10 +3,26 @@
|
|||||||
* includes Vue and other libraries. It is a great starting point when
|
* includes Vue and other libraries. It is a great starting point when
|
||||||
* building robust, powerful web applications using Vue and Laravel.
|
* building robust, powerful web applications using Vue and Laravel.
|
||||||
*/
|
*/
|
||||||
/* TODO REMOVE ME */
|
|
||||||
|
|
||||||
require('./bootstrap');
|
require('./bootstrap');
|
||||||
window.Vue = require('vue');
|
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.
|
* Components for OAuth2 tokens.
|
||||||
@@ -14,6 +30,7 @@ window.Vue = require('vue');
|
|||||||
Vue.component('passport-clients', require('./components/passport/Clients.vue'));
|
Vue.component('passport-clients', require('./components/passport/Clients.vue'));
|
||||||
Vue.component('passport-authorized-clients', require('./components/passport/AuthorizedClients.vue'));
|
Vue.component('passport-authorized-clients', require('./components/passport/AuthorizedClients.vue'));
|
||||||
Vue.component('passport-personal-access-tokens', require('./components/passport/PersonalAccessTokens.vue'));
|
Vue.component('passport-personal-access-tokens', require('./components/passport/PersonalAccessTokens.vue'));
|
||||||
|
Vue.component('create-transaction', require('./components/transactions/CreateTransaction'));
|
||||||
|
|
||||||
|
|
||||||
const app = new Vue({
|
const app = new Vue({
|
||||||
|
160
resources/assets/js/components/transactions/AccountSelect.vue
Normal file
160
resources/assets/js/components/transactions/AccountSelect.vue
Normal 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>
|
76
resources/assets/js/components/transactions/Amount.vue
Normal file
76
resources/assets/js/components/transactions/Amount.vue
Normal 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>
|
66
resources/assets/js/components/transactions/Budget.vue
Normal file
66
resources/assets/js/components/transactions/Budget.vue
Normal 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>
|
108
resources/assets/js/components/transactions/Category.vue
Normal file
108
resources/assets/js/components/transactions/Category.vue
Normal 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>
|
@@ -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>
|
@@ -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>
|
@@ -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>
|
66
resources/assets/js/components/transactions/PiggyBank.vue
Normal file
66
resources/assets/js/components/transactions/PiggyBank.vue
Normal 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>
|
82
resources/assets/js/components/transactions/Tags.vue
Normal file
82
resources/assets/js/components/transactions/Tags.vue
Normal 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>
|
@@ -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>
|
@@ -46,6 +46,7 @@ return [
|
|||||||
'create_withdrawal' => 'Create new withdrawal',
|
'create_withdrawal' => 'Create new withdrawal',
|
||||||
'create_deposit' => 'Create new deposit',
|
'create_deposit' => 'Create new deposit',
|
||||||
'create_transfer' => 'Create new transfer',
|
'create_transfer' => 'Create new transfer',
|
||||||
|
'create_new_transaction' => 'Create a new transaction',
|
||||||
'edit_journal' => 'Edit transaction ":description"',
|
'edit_journal' => 'Edit transaction ":description"',
|
||||||
'edit_reconciliation' => 'Edit ":description"',
|
'edit_reconciliation' => 'Edit ":description"',
|
||||||
'delete_journal' => 'Delete transaction ":description"',
|
'delete_journal' => 'Delete transaction ":description"',
|
||||||
|
@@ -1177,7 +1177,7 @@ return [
|
|||||||
'store_configuration' => 'Store configuration',
|
'store_configuration' => 'Store configuration',
|
||||||
'single_user_administration' => 'User administration for :email',
|
'single_user_administration' => 'User administration for :email',
|
||||||
'edit_user' => 'Edit user :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>.',
|
'hidden_fields_preferences' => 'You can enable more transaction options in your <a href=":link">settings</a>.',
|
||||||
'user_data_information' => 'User data',
|
'user_data_information' => 'User data',
|
||||||
'user_information' => 'User information',
|
'user_information' => 'User information',
|
||||||
'total_size' => 'total size',
|
'total_size' => 'total size',
|
||||||
@@ -1202,6 +1202,14 @@ return [
|
|||||||
'send_message' => 'Send message',
|
'send_message' => 'Send message',
|
||||||
'send_test_triggered' => 'Test was triggered. Check your inbox and the log files.',
|
'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
|
// links
|
||||||
'journal_link_configuration' => 'Transaction links configuration',
|
'journal_link_configuration' => 'Transaction links configuration',
|
||||||
'create_new_link_type' => 'Create new link type',
|
'create_new_link_type' => 'Create new link type',
|
||||||
|
@@ -57,6 +57,7 @@ return [
|
|||||||
'asset_source_account' => 'Source account',
|
'asset_source_account' => 'Source account',
|
||||||
'journal_description' => 'Description',
|
'journal_description' => 'Description',
|
||||||
'note' => 'Notes',
|
'note' => 'Notes',
|
||||||
|
'store_new_transaction' => 'Store new transaction',
|
||||||
'split_journal' => 'Split this transaction',
|
'split_journal' => 'Split this transaction',
|
||||||
'split_journal_explanation' => 'Split this transaction in multiple parts',
|
'split_journal_explanation' => 'Split this transaction in multiple parts',
|
||||||
'currency' => 'Currency',
|
'currency' => 'Currency',
|
||||||
|
@@ -31,18 +31,4 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% 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 %}
|
|
||||||
|
@@ -193,8 +193,8 @@
|
|||||||
{% if not shownDemo %}
|
{% if not shownDemo %}
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
var routeForTour = "{{ current_route_name }}";
|
var routeForTour = "{{ current_route_name }}";
|
||||||
var routeStepsUri = "{{ route('json.intro', [current_route_name, what|default("")]) }}";
|
var routeStepsUri = "{{ route('json.intro', [current_route_name, objectType|default("")]) }}";
|
||||||
var routeForFinishedTour = "{{ route('json.intro.finished', [current_route_name, what|default("")]) }}";
|
var routeForFinishedTour = "{{ route('json.intro.finished', [current_route_name, objectType|default("")]) }}";
|
||||||
</script>
|
</script>
|
||||||
<script type="text/javascript" src="v1/lib/intro/intro.min.js?v={{ FF_VERSION }}"></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>
|
<script type="text/javascript" src="v1/js/ff/intro/intro.js?v={{ FF_VERSION }}"></script>
|
||||||
|
@@ -1,7 +1,9 @@
|
|||||||
<table class="table">
|
<table class="table">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>X</th>
|
<th>
|
||||||
|
{{ groups.render }}
|
||||||
|
</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
@@ -12,22 +12,22 @@
|
|||||||
</span>
|
</span>
|
||||||
</a>
|
</a>
|
||||||
<ul class="treeview-menu">
|
<ul class="treeview-menu">
|
||||||
<li class="{{ activeRoutePartialWhat('accounts', 'asset') }}">
|
<li class="{{ activeRoutePartialObjectType('accounts', 'asset') }}">
|
||||||
<a href="{{ route('accounts.index','asset') }}">
|
<a href="{{ route('accounts.index','asset') }}">
|
||||||
<i class="fa fa-money fa-fw"></i> {{ 'asset_accounts'|_ }}
|
<i class="fa fa-money fa-fw"></i> {{ 'asset_accounts'|_ }}
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="{{ activeRoutePartialWhat('accounts', 'expense') }}">
|
<li class="{{ activeRoutePartialObjectType('accounts', 'expense') }}">
|
||||||
<a href="{{ route('accounts.index','expense') }}">
|
<a href="{{ route('accounts.index','expense') }}">
|
||||||
<i class="fa fa-shopping-cart fa-fw"></i> {{ 'expense_accounts'|_ }}
|
<i class="fa fa-shopping-cart fa-fw"></i> {{ 'expense_accounts'|_ }}
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="{{ activeRoutePartialWhat('accounts', 'revenue') }}">
|
<li class="{{ activeRoutePartialObjectType('accounts', 'revenue') }}">
|
||||||
<a href="{{ route('accounts.index','revenue') }}">
|
<a href="{{ route('accounts.index','revenue') }}">
|
||||||
<i class="fa fa-download fa-fw"></i> {{ 'revenue_accounts'|_ }}
|
<i class="fa fa-download fa-fw"></i> {{ 'revenue_accounts'|_ }}
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="{{ activeRoutePartialWhat('accounts', 'liabilities') }}">
|
<li class="{{ activeRoutePartialObjectType('accounts', 'liabilities') }}">
|
||||||
<a href="{{ route('accounts.index','liabilities') }}">
|
<a href="{{ route('accounts.index','liabilities') }}">
|
||||||
<i class="fa fa-ticket fa-fw"></i> {{ 'liabilities_accounts'|_ }}
|
<i class="fa fa-ticket fa-fw"></i> {{ 'liabilities_accounts'|_ }}
|
||||||
</a>
|
</a>
|
||||||
@@ -67,15 +67,15 @@
|
|||||||
</span>
|
</span>
|
||||||
</a>
|
</a>
|
||||||
<ul class="treeview-menu">
|
<ul class="treeview-menu">
|
||||||
<li class="{{ activeRoutePartialWhat('transactions','withdrawal') }}">
|
<li class="{{ activeRoutePartialObjectType('transactions','withdrawal') }}">
|
||||||
<a href="{{ route('transactions.index','withdrawal') }}">
|
<a href="{{ route('transactions.index','withdrawal') }}">
|
||||||
<i class="fa fa-long-arrow-left fa-fw"></i> {{ 'expenses'|_ }}</a>
|
<i class="fa fa-long-arrow-left fa-fw"></i> {{ 'expenses'|_ }}</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="{{ activeRoutePartialWhat('transactions','deposit') }}">
|
<li class="{{ activeRoutePartialObjectType('transactions','deposit') }}">
|
||||||
<a href="{{ route('transactions.index','deposit') }}"><i
|
<a href="{{ route('transactions.index','deposit') }}"><i
|
||||||
class="fa fa-long-arrow-right fa-fw"></i> {{ 'income'|_ }}</a>
|
class="fa fa-long-arrow-right fa-fw"></i> {{ 'income'|_ }}</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="{{ activeRoutePartialWhat('transactions','transfers') }}">
|
<li class="{{ activeRoutePartialObjectType('transactions','transfers') }}">
|
||||||
<a href="{{ route('transactions.index','transfers') }}">
|
<a href="{{ route('transactions.index','transfers') }}">
|
||||||
<i class="fa fa-fw fa-exchange"></i> {{ 'transfers'|_ }}</a>
|
<i class="fa fa-fw fa-exchange"></i> {{ 'transfers'|_ }}</a>
|
||||||
</li>
|
</li>
|
||||||
|
288
resources/views/v1/transactions/create.twig
Normal file
288
resources/views/v1/transactions/create.twig
Normal 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 %}
|
@@ -31,7 +31,7 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
{# actual list #}
|
{# actual list #}
|
||||||
{% include 'list.transactions' %}
|
{% include 'list.groups' %}
|
||||||
</div>
|
</div>
|
||||||
<div class="box-footer">
|
<div class="box-footer">
|
||||||
{# links for other views #}
|
{# links for other views #}
|
||||||
|
@@ -1022,9 +1022,9 @@ try {
|
|||||||
|
|
||||||
Breadcrumbs::register(
|
Breadcrumbs::register(
|
||||||
'transactions.create',
|
'transactions.create',
|
||||||
function (BreadcrumbsGenerator $breadcrumbs, string $what) {
|
function (BreadcrumbsGenerator $breadcrumbs, string $objectType) {
|
||||||
$breadcrumbs->parent('transactions.index', $what);
|
$breadcrumbs->parent('transactions.index', $objectType);
|
||||||
$breadcrumbs->push(trans('breadcrumbs.create_' . e($what)), route('transactions.create', [$what]));
|
$breadcrumbs->push(trans('breadcrumbs.create_new_transaction'), route('transactions.create', [$objectType]));
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@@ -546,14 +546,20 @@ Route::group(
|
|||||||
['middleware' => 'user-full-auth', 'namespace' => 'FireflyIII\Http\Controllers', 'prefix' => 'json', 'as' => 'json.'], function () {
|
['middleware' => 'user-full-auth', 'namespace' => 'FireflyIII\Http\Controllers', 'prefix' => 'json', 'as' => 'json.'], function () {
|
||||||
|
|
||||||
// for auto complete
|
// 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:
|
// TODO improve 3 routes:
|
||||||
Route::get('transaction-journals/all', ['uses' => 'Json\AutoCompleteController@allTransactionJournals', 'as' => 'all-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/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/{what}', ['uses' => 'Json\AutoCompleteController@transactionJournals', 'as' => 'transaction-journals']);
|
||||||
// TODO end of improvement
|
// TODO end of improvement
|
||||||
|
|
||||||
Route::get('transaction-types', ['uses' => 'Json\AutoCompleteController@transactionTypes', 'as' => 'transaction-types']);
|
Route::get('transaction-types', ['uses' => 'Json\AutoCompleteController@transactionTypes', 'as' => 'transaction-types']);
|
||||||
|
|
||||||
// boxes
|
// boxes
|
||||||
@@ -577,7 +583,7 @@ Route::group(
|
|||||||
Route::post('intro/enable/{route}/{specificPage?}', ['uses' => 'Json\IntroController@postEnable', 'as' => 'intro.enable']);
|
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('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(
|
Route::group(
|
||||||
['middleware' => 'user-full-auth', 'namespace' => 'FireflyIII\Http\Controllers', 'prefix' => 'transactions', 'as' => 'transactions.'], function () {
|
['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(
|
Route::get('{what}/{start_date?}/{end_date?}', ['uses' => 'Transaction\IndexController@index', 'as' => 'index'])->where(
|
||||||
['what' => 'withdrawal|deposit|transfers|transfer']
|
['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
|
// TODO improve these routes
|
||||||
@@ -903,7 +911,7 @@ Route::group(
|
|||||||
['middleware' => 'user-full-auth', 'namespace' => 'FireflyIII\Http\Controllers\Transaction', 'prefix' => 'transactions', 'as' => 'transactions.'],
|
['middleware' => 'user-full-auth', 'namespace' => 'FireflyIII\Http\Controllers\Transaction', 'prefix' => 'transactions', 'as' => 'transactions.'],
|
||||||
function () {
|
function () {
|
||||||
// TODO improve these routes
|
// 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('edit/{tj}', ['uses' => 'SingleController@edit', 'as' => 'edit']);
|
||||||
Route::get('delete/{tj}', ['uses' => 'SingleController@delete', 'as' => 'delete']);
|
Route::get('delete/{tj}', ['uses' => 'SingleController@delete', 'as' => 'delete']);
|
||||||
Route::post('store', ['uses' => 'SingleController@store', 'as' => 'store'])->where(['what' => 'withdrawal|deposit|transfer']);
|
Route::post('store', ['uses' => 'SingleController@store', 'as' => 'store'])->where(['what' => 'withdrawal|deposit|transfer']);
|
||||||
|
24
yarn.lock
24
yarn.lock
@@ -2,6 +2,13 @@
|
|||||||
# yarn lockfile v1
|
# 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":
|
"@types/q@^1.5.1":
|
||||||
version "1.5.1"
|
version "1.5.1"
|
||||||
resolved "https://registry.yarnpkg.com/@types/q/-/q-1.5.1.tgz#48fd98c1561fe718b61733daed46ff115b496e18"
|
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"
|
webpack-sources "^1.1.0"
|
||||||
worker-farm "^1.5.2"
|
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:
|
unbzip2-stream@^1.0.9:
|
||||||
version "1.3.1"
|
version "1.3.1"
|
||||||
resolved "https://registry.yarnpkg.com/unbzip2-stream/-/unbzip2-stream-1.3.1.tgz#7854da51622a7e63624221196357803b552966a1"
|
resolved "https://registry.yarnpkg.com/unbzip2-stream/-/unbzip2-stream-1.3.1.tgz#7854da51622a7e63624221196357803b552966a1"
|
||||||
@@ -8252,6 +8266,11 @@ vm-browserify@0.0.4:
|
|||||||
dependencies:
|
dependencies:
|
||||||
indexof "0.0.1"
|
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:
|
vue-hot-reload-api@^2.2.0:
|
||||||
version "2.3.1"
|
version "2.3.1"
|
||||||
resolved "https://registry.yarnpkg.com/vue-hot-reload-api/-/vue-hot-reload-api-2.3.1.tgz#b2d3d95402a811602380783ea4f566eb875569a2"
|
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"
|
resolved "https://registry.yarnpkg.com/vue-template-es2015-compiler/-/vue-template-es2015-compiler-1.6.0.tgz#dc42697133302ce3017524356a6c61b7b69b4a18"
|
||||||
integrity sha512-x3LV3wdmmERhVCYy3quqA57NJW7F3i6faas++pJQWtknWT+n7k30F4TVdHvCLn48peTJFRvCpxs3UuFPqgeELg==
|
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:
|
vue@^2.5.7:
|
||||||
version "2.5.21"
|
version "2.5.21"
|
||||||
resolved "https://registry.yarnpkg.com/vue/-/vue-2.5.21.tgz#3d33dcd03bb813912ce894a8303ab553699c4a85"
|
resolved "https://registry.yarnpkg.com/vue/-/vue-2.5.21.tgz#3d33dcd03bb813912ce894a8303ab553699c4a85"
|
||||||
|
Reference in New Issue
Block a user