mirror of
https://github.com/firefly-iii/firefly-iii.git
synced 2025-02-25 18:45:27 -06:00
Expand AC
This commit is contained in:
parent
c3b99c322d
commit
9939ed0aaf
@ -42,12 +42,19 @@
|
|||||||
:has-submission-error="hasSubmissionErrors.description"
|
:has-submission-error="hasSubmissionErrors.description"
|
||||||
:disabled-input="disabledInput"
|
:disabled-input="disabledInput"
|
||||||
:description="transaction.description"
|
:description="transaction.description"
|
||||||
@update:description="updateDescription"/>
|
@update:description="updateDescription"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-4 q-mb-xs q-pr-xs">
|
<div class="col-4 q-mb-xs q-pr-xs">
|
||||||
<SourceAccount name="Test" :disabled-input="false" submission-error="" :has-submission-error="false" />
|
<SourceAccount
|
||||||
|
:name="''"
|
||||||
|
@update:source="updateSource"
|
||||||
|
:disabled-input="false"
|
||||||
|
submission-error=""
|
||||||
|
:transaction-type="transactionType"
|
||||||
|
:has-submission-error="false"/>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-4 q-px-xs">
|
<div class="col-4 q-px-xs">
|
||||||
<q-input
|
<q-input
|
||||||
@ -60,14 +67,13 @@
|
|||||||
outlined reverse-fill-mask/>
|
outlined reverse-fill-mask/>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-4 q-pl-xs">
|
<div class="col-4 q-pl-xs">
|
||||||
<q-input dense
|
<DestinationAccount
|
||||||
v-model="transaction.destination"
|
:name="''"
|
||||||
:disable="disabledInput"
|
@update:destination="updateDestination"
|
||||||
:error="hasSubmissionErrors.destination"
|
:disabled-input="false"
|
||||||
:error-message="submissionErrors.destination" :label="$t('firefly.destination_account')"
|
submission-error=""
|
||||||
bottom-slots
|
:transaction-type="transactionType"
|
||||||
clearable
|
:has-submission-error="false"/>
|
||||||
outlined/>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
@ -268,15 +274,21 @@
|
|||||||
<script>
|
<script>
|
||||||
import TransactionDescription from "components/transactions/form/TransactionDescription.vue";
|
import TransactionDescription from "components/transactions/form/TransactionDescription.vue";
|
||||||
import SourceAccount from "components/transactions/form/SourceAccount.vue";
|
import SourceAccount from "components/transactions/form/SourceAccount.vue";
|
||||||
|
import DestinationAccount from "components/transactions/form/DestinationAccount.vue";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "Split",
|
name: "Split",
|
||||||
components: {SourceAccount, TransactionDescription},
|
components: {DestinationAccount, SourceAccount, TransactionDescription},
|
||||||
props: {
|
props: {
|
||||||
index: {
|
index: {
|
||||||
type: Number,
|
type: Number,
|
||||||
required: true
|
required: true
|
||||||
},
|
},
|
||||||
|
transactionType: {
|
||||||
|
type: String,
|
||||||
|
default: 'unknown',
|
||||||
|
required: true
|
||||||
|
},
|
||||||
disabledInput: {
|
disabledInput: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
required: true
|
required: true
|
||||||
@ -297,6 +309,17 @@ export default {
|
|||||||
methods: {
|
methods: {
|
||||||
updateDescription(newVal) {
|
updateDescription(newVal) {
|
||||||
this.transaction.description = newVal;
|
this.transaction.description = newVal;
|
||||||
|
console.log('Description is now "' + newVal + '"');
|
||||||
|
},
|
||||||
|
updateSource(newVal) {
|
||||||
|
this.transaction.source = newVal;
|
||||||
|
console.log('Source is now:');
|
||||||
|
console.log(newVal);
|
||||||
|
},
|
||||||
|
updateDestination(newVal) {
|
||||||
|
this.transaction.destination = newVal;
|
||||||
|
console.log('Destination is now:');
|
||||||
|
console.log(newVal);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
|
156
frontend/src/components/transactions/form/DestinationAccount.vue
Normal file
156
frontend/src/components/transactions/form/DestinationAccount.vue
Normal file
@ -0,0 +1,156 @@
|
|||||||
|
<!--
|
||||||
|
- SourceAccount.vue
|
||||||
|
- Copyright (c) 2023 james@firefly-iii.org
|
||||||
|
-
|
||||||
|
- This file is part of Firefly III (https://github.com/firefly-iii).
|
||||||
|
-
|
||||||
|
- This program is free software: you can redistribute it and/or modify
|
||||||
|
- it under the terms of the GNU Affero General Public License as
|
||||||
|
- published by the Free Software Foundation, either version 3 of the
|
||||||
|
- License, or (at your option) any later version.
|
||||||
|
-
|
||||||
|
- This program is distributed in the hope that it will be useful,
|
||||||
|
- but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
- GNU Affero General Public License for more details.
|
||||||
|
-
|
||||||
|
- You should have received a copy of the GNU Affero General Public License
|
||||||
|
- along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<q-select
|
||||||
|
v-model="model"
|
||||||
|
use-input
|
||||||
|
:options="options"
|
||||||
|
@filter="filterFn"
|
||||||
|
dense
|
||||||
|
:loading="loading"
|
||||||
|
outlined
|
||||||
|
new-value-mode="add-unique"
|
||||||
|
:disable="disabledInput"
|
||||||
|
:error="hasSubmissionError"
|
||||||
|
:label="$t('firefly.destination_account')"
|
||||||
|
:error-message="submissionError"
|
||||||
|
bottom-slots
|
||||||
|
clearable
|
||||||
|
>
|
||||||
|
<!--
|
||||||
|
|
||||||
|
input-debounce="0"
|
||||||
|
|
||||||
|
label="Lazy filter"
|
||||||
|
-->
|
||||||
|
<template v-slot:option="scope">
|
||||||
|
<q-item v-bind="scope.itemProps">
|
||||||
|
<q-item-section>
|
||||||
|
<q-item-label>{{ scope.opt.label }}</q-item-label>
|
||||||
|
<q-item-label caption>{{ scope.opt.type }}</q-item-label>
|
||||||
|
</q-item-section>
|
||||||
|
</q-item>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template v-slot:no-option>
|
||||||
|
<q-item>
|
||||||
|
<q-item-section class="text-grey">
|
||||||
|
No results
|
||||||
|
</q-item-section>
|
||||||
|
</q-item>
|
||||||
|
</template>
|
||||||
|
</q-select>
|
||||||
|
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
source account is basic dropdown from API
|
||||||
|
with optional filters on account type. This depends
|
||||||
|
on transaction type which is null or invalid or withdrawal or whatever
|
||||||
|
if the index is not null the field shall be disabled and empty.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import Accounts from '../../../api/v2/autocomplete/accounts'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: "DestinationAccount",
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
model: null,
|
||||||
|
transactionTypeString: '',
|
||||||
|
options: [],
|
||||||
|
loading: true,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
name: {
|
||||||
|
type: String,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
transactionType: {
|
||||||
|
type: String,
|
||||||
|
required: false,
|
||||||
|
default: 'unknown'
|
||||||
|
},
|
||||||
|
disabledInput: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
hasSubmissionError: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
submissionError: {
|
||||||
|
type: String,
|
||||||
|
required: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
this.getAccounts('');
|
||||||
|
this.model = this.name;
|
||||||
|
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
getAccounts: function (query) {
|
||||||
|
this.loading = true;
|
||||||
|
// default set of account types, will later be set by the transaction type.
|
||||||
|
let types = 'Expense account, Loan, Debt, Mortgage';
|
||||||
|
if('deposit' === this.transactionType) {
|
||||||
|
let types = 'Asset account, Loan, Debt, Mortgage';
|
||||||
|
}
|
||||||
|
(new Accounts).get(types, query).then(response => {
|
||||||
|
this.stringOptions = [];
|
||||||
|
for (let i in response.data) {
|
||||||
|
let entry = response.data[i];
|
||||||
|
let current = {
|
||||||
|
label: entry.name,
|
||||||
|
value: entry.id,
|
||||||
|
type: entry.type
|
||||||
|
}
|
||||||
|
|
||||||
|
this.stringOptions.push(current);
|
||||||
|
}
|
||||||
|
//this.stringOptions = response.data.data;
|
||||||
|
this.options = this.stringOptions;
|
||||||
|
this.loading = false;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
filterFn(val, update, abort) {
|
||||||
|
update(() => {
|
||||||
|
this.getAccounts(val);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
model: {
|
||||||
|
handler: function (newVal) {
|
||||||
|
if(newVal !== undefined) {
|
||||||
|
this.$emit('update:destination', newVal);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
deep: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
@ -27,6 +27,7 @@
|
|||||||
dense
|
dense
|
||||||
:loading="loading"
|
:loading="loading"
|
||||||
outlined
|
outlined
|
||||||
|
new-value-mode="add-unique"
|
||||||
:disable="disabledInput"
|
:disable="disabledInput"
|
||||||
:error="hasSubmissionError"
|
:error="hasSubmissionError"
|
||||||
:label="$t('firefly.source_account')"
|
:label="$t('firefly.source_account')"
|
||||||
@ -44,7 +45,7 @@
|
|||||||
<q-item v-bind="scope.itemProps">
|
<q-item v-bind="scope.itemProps">
|
||||||
<q-item-section>
|
<q-item-section>
|
||||||
<q-item-label>{{ scope.opt.label }}</q-item-label>
|
<q-item-label>{{ scope.opt.label }}</q-item-label>
|
||||||
<q-item-label caption>{{ scope.opt.description }}</q-item-label>
|
<q-item-label caption>{{ scope.opt.type }}</q-item-label>
|
||||||
</q-item-section>
|
</q-item-section>
|
||||||
</q-item>
|
</q-item>
|
||||||
</template>
|
</template>
|
||||||
@ -87,7 +88,8 @@ export default {
|
|||||||
},
|
},
|
||||||
transactionType: {
|
transactionType: {
|
||||||
type: String,
|
type: String,
|
||||||
required: false
|
required: false,
|
||||||
|
default: 'unknown'
|
||||||
},
|
},
|
||||||
disabledInput: {
|
disabledInput: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
@ -105,16 +107,18 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
console.log('Mounted');
|
|
||||||
//this.options.value = this.stringOptions
|
|
||||||
this.getAccounts('');
|
this.getAccounts('');
|
||||||
|
this.model = this.name;
|
||||||
|
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
getAccounts: function (query) {
|
getAccounts: function (query) {
|
||||||
this.loading = true;
|
this.loading = true;
|
||||||
console.log('getAccounts("'+query+'")');
|
|
||||||
// default set of account types, will later be set by the transaction type.
|
// default set of account types, will later be set by the transaction type.
|
||||||
let types = 'Asset account,Revenue account,Loan,Debt,Mortgage';
|
let types = 'Asset account,Revenue account,Loan,Debt,Mortgage';
|
||||||
|
if('deposit' === this.transactionType) {
|
||||||
|
console.log('NOW DEPOSIT');
|
||||||
|
}
|
||||||
(new Accounts).get(types, query).then(response => {
|
(new Accounts).get(types, query).then(response => {
|
||||||
this.stringOptions = [];
|
this.stringOptions = [];
|
||||||
for (let i in response.data) {
|
for (let i in response.data) {
|
||||||
@ -122,46 +126,31 @@ export default {
|
|||||||
let current = {
|
let current = {
|
||||||
label: entry.name,
|
label: entry.name,
|
||||||
value: entry.id,
|
value: entry.id,
|
||||||
description: entry.type
|
type: entry.type
|
||||||
}
|
}
|
||||||
|
|
||||||
this.stringOptions.push(current);
|
this.stringOptions.push(current);
|
||||||
}
|
}
|
||||||
//this.stringOptions = response.data.data;
|
//this.stringOptions = response.data.data;
|
||||||
this.options = this.stringOptions;
|
this.options = this.stringOptions;
|
||||||
this.loading = false;
|
this.loading = false;
|
||||||
console.log('getAccounts done!');
|
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
filterFn(val, update, abort) {
|
filterFn(val, update, abort) {
|
||||||
console.log('filterFn(' + val + ')');
|
|
||||||
if (val === '') {
|
|
||||||
update(() => {
|
|
||||||
this.getAccounts('');
|
|
||||||
//this.options = stringOptions
|
|
||||||
|
|
||||||
// here you have access to "ref" which
|
|
||||||
// is the Vue reference of the QSelect
|
|
||||||
})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
update(() => {
|
update(() => {
|
||||||
this.getAccounts(val);
|
this.getAccounts(val);
|
||||||
//const needle = val.toLowerCase()
|
|
||||||
//this.options = this.options.filter(v => v.label.toLowerCase().indexOf(needle) > -1)
|
|
||||||
})
|
})
|
||||||
// console.log('filterFn(' + val + ')');
|
}
|
||||||
// if (this.loading) {
|
},
|
||||||
// console.log('return');
|
watch: {
|
||||||
// return
|
model: {
|
||||||
// }
|
handler: function (newVal) {
|
||||||
// const needle = val.toLowerCase()
|
if(newVal !== undefined) {
|
||||||
// this.options = this.stringOptions.filter(v => v.label.toLowerCase().indexOf(needle) > -1);
|
this.$emit('update:source', newVal);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
deep: true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
|
|
||||||
</style>
|
|
||||||
|
@ -59,6 +59,7 @@
|
|||||||
<Split
|
<Split
|
||||||
:transaction="transaction"
|
:transaction="transaction"
|
||||||
:index="index"
|
:index="index"
|
||||||
|
:transaction-type="transactionType"
|
||||||
:disabled-input="disabledInput"
|
:disabled-input="disabledInput"
|
||||||
:has-submission-errors="hasSubmissionErrors[index]"
|
:has-submission-errors="hasSubmissionErrors[index]"
|
||||||
:submission-errors="submissionErrors[index]"
|
:submission-errors="submissionErrors[index]"
|
||||||
@ -112,6 +113,7 @@ import format from 'date-fns/format';
|
|||||||
import formatISO from 'date-fns/formatISO';
|
import formatISO from 'date-fns/formatISO';
|
||||||
import Post from "../../api/transactions/post";
|
import Post from "../../api/transactions/post";
|
||||||
import Split from "components/transactions/Split.vue";
|
import Split from "components/transactions/Split.vue";
|
||||||
|
import CalculateType from "src/support/transactions/calculate-type";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'Create',
|
name: 'Create',
|
||||||
@ -119,6 +121,7 @@ export default {
|
|||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
tab: 'split-0',
|
tab: 'split-0',
|
||||||
|
transactionType: 'unknown',
|
||||||
transactions: [],
|
transactions: [],
|
||||||
submissionErrors: [],
|
submissionErrors: [],
|
||||||
hasSubmissionErrors: [],
|
hasSubmissionErrors: [],
|
||||||
@ -165,7 +168,7 @@ export default {
|
|||||||
this.tab = 'split-' + index;
|
this.tab = 'split-' + index;
|
||||||
},
|
},
|
||||||
getSplitLabel: function (index) {
|
getSplitLabel: function (index) {
|
||||||
console.log('Get split label (' + index + ')');
|
//console.log('Get split label (' + index + ')');
|
||||||
if (this.transactions.hasOwnProperty(index) &&
|
if (this.transactions.hasOwnProperty(index) &&
|
||||||
null !== this.transactions[index].description &&
|
null !== this.transactions[index].description &&
|
||||||
this.transactions[index].description.length > 0) {
|
this.transactions[index].description.length > 0) {
|
||||||
@ -196,10 +199,9 @@ export default {
|
|||||||
},
|
},
|
||||||
updateTransaction: function (obj) {
|
updateTransaction: function (obj) {
|
||||||
const index = obj.index;
|
const index = obj.index;
|
||||||
const transaction = obj.transaction;
|
this.transactions[index] = obj.transaction;
|
||||||
console.log('Update transaction ' + index);
|
// TODO needs to update all splits if necessary and warn user about it.
|
||||||
console.log(transaction);
|
this.transactionType = (new CalculateType()).calculateType(this.transactions[0].source, this.transactions[0].destination);
|
||||||
this.transactions[index] = transaction;
|
|
||||||
},
|
},
|
||||||
processSuccess: function (response) {
|
processSuccess: function (response) {
|
||||||
console.log('process success');
|
console.log('process success');
|
||||||
|
69
frontend/src/support/transactions/calculate-type.js
vendored
Normal file
69
frontend/src/support/transactions/calculate-type.js
vendored
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
/*
|
||||||
|
* calculate-type.js
|
||||||
|
* Copyright (c) 2023 james@firefly-iii.org
|
||||||
|
*
|
||||||
|
* This file is part of Firefly III (https://github.com/firefly-iii).
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as
|
||||||
|
* published by the Free Software Foundation, either version 3 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
export default class CalculateType {
|
||||||
|
calculateType(source, destination) {
|
||||||
|
const srcEmpty = this.empty(source);
|
||||||
|
const dstEmpty = this.empty(destination);
|
||||||
|
// both are null or ''
|
||||||
|
if (srcEmpty && dstEmpty) {
|
||||||
|
return 'unknown';
|
||||||
|
}
|
||||||
|
|
||||||
|
// source has data, dest has not
|
||||||
|
if (typeof source === 'object' && null !== source && dstEmpty) {
|
||||||
|
if (source.type === 'Asset account' || source.type === 'Loan' || source.type === 'Debt' || source.type === 'Mortgage') {
|
||||||
|
return 'withdrawal';
|
||||||
|
}
|
||||||
|
if (source.type === 'Revenue account') {
|
||||||
|
return 'deposit';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// dst has data, source has not
|
||||||
|
if (typeof destination === 'object' && null !== destination && srcEmpty) {
|
||||||
|
if (destination.type === 'Asset account') {
|
||||||
|
return 'deposit';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// both have data:
|
||||||
|
if (!srcEmpty && !dstEmpty) {
|
||||||
|
if (source.type === 'Asset account' && destination.type === 'Expense account') {
|
||||||
|
return 'withdrawal';
|
||||||
|
}
|
||||||
|
if (source.type === destination.type) {
|
||||||
|
return 'transfer';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
console.error('Cannot handle');
|
||||||
|
console.log(source);
|
||||||
|
console.log(destination);
|
||||||
|
}
|
||||||
|
|
||||||
|
empty(value) {
|
||||||
|
if (null === value || '' === value) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (null !== value && typeof value === 'object') {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user