First attempt at "create transaction"-form for v2 users.

This commit is contained in:
James Cole
2023-10-08 16:11:04 +02:00
parent 2ea9369f99
commit 1fe36044f1
56 changed files with 901 additions and 130 deletions

View File

@@ -259,7 +259,7 @@ export default () => ({
init() {
// console.log('accounts init');
Promise.all([getVariable('viewRange', '1M'), getVariable('autoConversion', false), getVariable('language', 'en-US')]).then((values) => {
Promise.all([getVariable('viewRange', '1M'), getVariable('autoConversion', false), getVariable('language', 'en_US')]).then((values) => {
//console.log('accounts after promises');
this.autoConversion = values[1];
afterPromises = true;

View File

@@ -175,11 +175,12 @@ export default () => ({
init() {
// console.log('budgets init');
Promise.all([getVariable('autoConversion', false), getVariable('language', 'en-US')]).then((values) => {
Promise.all([getVariable('autoConversion', false), getVariable('language', 'en_US')]).then((values) => {
i18n = new I18n();
i18n.locale = values[1];
loadTranslations(i18n, values[1]).then(() => {
const locale = values[1].replace('-', '_');
i18n.locale = locale;
loadTranslations(i18n, locale).then(() => {
this.autoConversion = values[0];
afterPromises = true;
if (false === this.loading) {

View File

@@ -130,11 +130,12 @@ export default () => ({
init() {
// console.log('piggies init');
apiData = [];
Promise.all([getVariable('autoConversion', false), getVariable('language', 'en-US')]).then((values) => {
Promise.all([getVariable('autoConversion', false), getVariable('language', 'en_US')]).then((values) => {
i18n = new I18n();
i18n.locale = values[1];
loadTranslations(i18n, values[1]).then(() => {
const locale = values[1].replace('-', '_');
i18n.locale = locale;
loadTranslations(i18n, locale).then(() => {
// console.log('piggies after promises');
afterPromises = true;
this.autoConversion = values[0];

View File

@@ -350,12 +350,13 @@ export default () => ({
init() {
// console.log('sankey init');
transactions = [];
Promise.all([getVariable('autoConversion', false), getVariable('language', 'en-US')]).then((values) => {
Promise.all([getVariable('autoConversion', false), getVariable('language', 'en_US')]).then((values) => {
this.autoConversion = values[0];
autoConversion = values[0];
i18n = new I18n();
i18n.locale = values[1];
loadTranslations(i18n, values[1]).then(() => {
const locale = values[1].replace('-', '_');
i18n.locale = locale;
loadTranslations(i18n, locale).then(() => {
// some translations:
translations.all_money = i18n.t('firefly.all_money');
translations.category = i18n.t('firefly.category');

View File

@@ -274,14 +274,15 @@ export default () => ({
init() {
console.log('subscriptions init');
Promise.all([getVariable('autoConversion', false), getVariable('language', 'en-US')]).then((values) => {
Promise.all([getVariable('autoConversion', false), getVariable('language', 'en_US')]).then((values) => {
console.log('subscriptions after promises');
this.autoConversion = values[0];
afterPromises = true;
i18n = new I18n();
i18n.locale = values[1];
loadTranslations(i18n, values[1]).then(() => {
const locale = values[1].replace('-', '_');
i18n.locale = locale;
loadTranslations(i18n, locale).then(() => {
if (false === this.loading) {
this.startSubscriptions();
}

View File

@@ -41,7 +41,7 @@ export default () => ({
defaultRange: {
start: null, end: null
},
language: 'en-US',
language: 'en_US',
init() {
// console.log('Dates init');

View File

@@ -25,14 +25,135 @@ import {parseFromEntries} from "./shared/parse-from-entries.js";
import formatMoney from "../../util/format-money.js";
import Autocomplete from "bootstrap5-autocomplete";
import Post from "../../api/v2/model/transaction/post.js";
import {getVariable} from "../../store/get-variable.js";
import {I18n} from "i18n-js";
import {loadTranslations} from "../../support/load-translations.js";
let i18n;
const urls = {
description: '/api/v2/autocomplete/transaction-descriptions',
account: '/api/v2/autocomplete/accounts',
};
let transactions = function () {
return {
count: 0,
totalAmount: 0,
transactionType: 'unknown',
showSuccessMessage: false,
showErrorMessage: false,
entries: [],
filters: {
source: [],
destination: [],
},
detectTransactionType() {
const sourceType = this.entries[0].source_account.type ?? 'unknown';
const destType = this.entries[0].destination_account.type ?? 'unknown';
if ('unknown' === sourceType && 'unknown' === destType) {
this.transactionType = 'unknown';
console.warn('Cannot infer transaction type from two unknown accounts.');
return;
}
// transfer: both are the same and in strict set of account types
if (sourceType === destType && ['Asset account', 'Loan', 'Debt', 'Mortgage'].includes(sourceType)) {
this.transactionType = 'transfer';
console.log('Transaction type is detected to be "' + this.transactionType + '".');
return;
}
// withdrawals:
if ('Asset account' === sourceType && ['Expense account', 'Debt', 'Loan', 'Mortgage'].includes(destType)) {
this.transactionType = 'withdrawal';
console.log('Transaction type is detected to be "' + this.transactionType + '".');
return;
}
if ('Asset account' === sourceType && 'unknown' === destType) {
this.transactionType = 'withdrawal';
console.log('Transaction type is detected to be "' + this.transactionType + '".');
return;
}
if (['Debt', 'Loan', 'Mortgage'].includes(sourceType) && 'Expense account' === destType) {
this.transactionType = 'withdrawal';
console.log('Transaction type is detected to be "' + this.transactionType + '".');
return;
}
// deposits:
if ('Revenue account' === sourceType && ['Asset account', 'Debt', 'Loan', 'Mortgage'].includes(destType)) {
this.transactionType = 'deposit';
console.log('Transaction type is detected to be "' + this.transactionType + '".');
return;
}
if (['Debt', 'Loan', 'Mortgage'].includes(sourceType) && 'Asset account' === destType) {
this.transactionType = 'deposit';
console.log('Transaction type is detected to be "' + this.transactionType + '".');
return;
}
console.warn('Unknown account combination between "' + sourceType + '" and "' + destType + '".');
},
selectSourceAccount(item, ac) {
const index = parseInt(ac._searchInput.attributes['data-index'].value);
document.querySelector('#form')._x_dataStack[0].$data.entries[index].source_account =
{
id: item.id,
name: item.name,
type: item.type,
};
console.log('Changed source account into a known ' + item.type.toLowerCase());
},
changedAmount(e) {
const index = parseInt(e.target.dataset.index);
this.entries[index].amount = parseFloat(e.target.value);
this.totalAmount = 0;
for (let i in this.entries) {
if (this.entries.hasOwnProperty(i)) {
this.totalAmount = this.totalAmount + parseFloat(this.entries[i].amount);
}
}
console.log('Changed amount to ' + this.totalAmount);
},
selectDestAccount(item, ac) {
const index = parseInt(ac._searchInput.attributes['data-index'].value);
document.querySelector('#form')._x_dataStack[0].$data.entries[index].destination_account =
{
id: item.id,
name: item.name,
type: item.type,
};
console.log('Changed destination account into a known ' + item.type.toLowerCase());
},
changeSourceAccount(item, ac) {
if (typeof item === 'undefined') {
const index = parseInt(ac._searchInput.attributes['data-index'].value);
let source = document.querySelector('#form')._x_dataStack[0].$data.entries[index].source_account;
if (source.name === ac._searchInput.value) {
console.warn('Ignore hallucinated source account name change to "' + ac._searchInput.value + '"');
return;
}
document.querySelector('#form')._x_dataStack[0].$data.entries[index].source_account =
{
name: ac._searchInput.value,
};
console.log('Changed source account into a unknown account called "' + ac._searchInput.value + '"');
}
},
changeDestAccount(item, ac) {
if (typeof item === 'undefined') {
const index = parseInt(ac._searchInput.attributes['data-index'].value);
let destination = document.querySelector('#form')._x_dataStack[0].$data.entries[index].destination_account;
if (destination.name === ac._searchInput.value) {
console.warn('Ignore hallucinated destination account name change to "' + ac._searchInput.value + '"');
return;
}
document.querySelector('#form')._x_dataStack[0].$data.entries[index].destination_account =
{
name: ac._searchInput.value,
};
console.log('Changed destination account into a unknown account called "' + ac._searchInput.value + '"');
}
},
// error and success messages:
showError: false,
@@ -40,62 +161,85 @@ let transactions = function () {
addedSplit() {
console.log('addedSplit');
const opts = {
onSelectItem: console.log,
};
var src = [];
for (let i = 0; i < 50; i++) {
src.push({
title: "Option " + i,
id: "opt" + i,
data: {
key: i,
},
});
}
Autocomplete.init("input.ac-source", {
server: urls.account,
serverParams: {
types: this.filters.source,
},
fetchOptions: {
headers: {
'X-CSRF-TOKEN': document.head.querySelector('meta[name="csrf-token"]').content
}
},
hiddenInput: true,
preventBrowserAutocomplete: true,
highlightTyped: true,
liveServer: true,
onChange: this.changeSourceAccount,
onSelectItem: this.selectSourceAccount,
onRenderItem: function (item, b, c) {
return item.name_with_balance + '<br><small class="text-muted">' + i18n.t('firefly.account_type_' + item.type) + '</small>';
}
});
Autocomplete.init("input.autocomplete", {
items: src,
Autocomplete.init("input.ac-dest", {
server: urls.account,
serverParams: {
types: this.filters.destination,
},
fetchOptions: {
headers: {
'X-CSRF-TOKEN': document.head.querySelector('meta[name="csrf-token"]').content
}
},
hiddenInput: true,
preventBrowserAutocomplete: true,
liveServer: true,
highlightTyped: true,
onSelectItem: this.selectDestAccount,
onChange: this.changeDestAccount,
onRenderItem: function (item, b, c) {
return item.name_with_balance + '<br><small class="text-muted">' + i18n.t('firefly.account_type_' + item.type) + '</small>';
}
});
this.filters.destination = [];
Autocomplete.init('input.ac-description', {
server: urls.description,
fetchOptions: {
headers: {
'X-CSRF-TOKEN': document.head.querySelector('meta[name="csrf-token"]').content
}
},
valueField: "id",
labelField: "title",
labelField: "description",
highlightTyped: true,
onSelectItem: console.log,
});
// setTimeout(() => {
// console.log('timed out');
// console.log(document.querySelector('input.autocomplete'));
// }, 1500);
},
init() {
console.log('init()');
this.addSplit();
Promise.all([getVariable('language', 'en_US')]).then((values) => {
i18n = new I18n();
const locale = values[0].replace('-', '_');
i18n.locale = locale;
loadTranslations(i18n, locale).then(() => {
this.addSplit();
});
// // We can use regular objects as source and customize label
// new Autocomplete(document.getElementById("autocompleteRegularInput"), {
// items: {
// opt_some: "Some",
// opt_value: "Value",
// opt_here: "Here is a very long element that should be truncated",
// opt_dia: "çaça"
// },
// onRenderItem: (item, label) => {
// return label + " (" + item.value + ")";
// },
// });
// new Autocomplete(document.getElementById("autocompleteDatalist"), opts);
//new Autocomplete(document.getElementById("autocompleteRemote"), opts);
// new Autocomplete(document.getElementById("autocompleteLiveRemote"), opts);
});
// source can never be expense account
this.filters.source = ['Asset account', 'Loan', 'Debt', 'Mortgage', 'Revenue account'];
// destination can never be revenue account
this.filters.destination = ['Expense account', 'Loan', 'Debt', 'Mortgage', 'Asset account'];
},
submitTransaction() {
this.detectTransactionType();
// todo disable buttons
let transactions = parseFromEntries(this.entries);
let transactions = parseFromEntries(this.entries, this.transactionType);
let submission = {
// todo process all options
group_title: null,

View File

@@ -32,7 +32,7 @@ export function createEmptySplit() {
let now = new Date();
let formatted = format(now, 'yyyy-MM-dd HH:mm');
return {
description: 'OK then',
description: '',
amount: '',
source_account: getAccount(),
destination_account: getAccount(),

View File

@@ -22,7 +22,7 @@
*
* @param entries
*/
export function parseFromEntries(entries) {
export function parseFromEntries(entries, transactionType) {
let returnArray = [];
for (let i in entries) {
if (entries.hasOwnProperty(i)) {
@@ -36,8 +36,16 @@ export function parseFromEntries(entries) {
current.amount = entry.amount;
current.date = entry.date;
// if ID is set:
if ('' !== entry.source_account.id.toString()) {
current.source_id = entry.source_account.id;
}
if ('' !== entry.destination_account.id.toString()) {
current.destination_id = entry.destination_account.id;
}
// TODO transaction type is hard coded:
current.type = 'withdrawal';
current.type = transactionType;
returnArray.push(current);

View File

@@ -22,6 +22,7 @@ let loaded = false;
async function loadTranslations(i18n, locale) {
if (false === loaded) {
locale = locale.replace('-', '_');
const response = await fetch(`./v2/i18n/${locale}.json`);
const translations = await response.json();
i18n.store(translations);