Expand AC

This commit is contained in:
James Cole 2023-03-31 19:20:26 +02:00
parent c3b99c322d
commit 9939ed0aaf
No known key found for this signature in database
GPG Key ID: B49A324B7EAD6D80
5 changed files with 287 additions and 48 deletions

View File

@ -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: {

View 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>

View File

@ -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>

View File

@ -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');

View 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;
}
}