Files
ezbookkeeping/src/store/transaction.js
T
2021-01-21 00:55:05 +08:00

368 lines
12 KiB
JavaScript

import transactionConstants from '../consts/transaction.js';
import services from '../lib/services.js';
import logger from '../lib/logger.js';
import utils from '../lib/utils.js';
import { getExchangedAmount } from "./exchangeRates.js";
import {
LOAD_TRANSACTION_LIST,
INIT_TRANSACTION_LIST_FILTER,
UPDATE_TRANSACTION_LIST_FILTER,
COLLAPSE_MONTH_IN_TRANSACTION_LIST,
SAVE_TRANSACTION_IN_TRANSACTION_LIST,
REMOVE_TRANSACTION_FROM_TRANSACTION_LIST,
UPDATE_TRANSACTION_LIST_INVALID_STATE,
UPDATE_ACCOUNT_LIST_INVALID_STATE,
UPDATE_TRANSACTION_OVERVIEW_INVALID_STATE,
UPDATE_TRANSACTION_STATISTICS_INVALID_STATE,
} from './mutations.js';
const emptyTransactionResult = {
items: [],
transactionsNextTimeId: 0
};
export function initTransactionListFilter(context, filter) {
context.commit(INIT_TRANSACTION_LIST_FILTER, filter);
}
export function updateTransactionListFilter(context, filter) {
context.commit(UPDATE_TRANSACTION_LIST_FILTER, filter);
}
export function loadTransactions(context, { reload, autoExpand, defaultCurrency }) {
let actualMaxTime = context.state.transactionsNextTimeId;
if (reload && context.state.transactionsFilter.maxTime > 0) {
actualMaxTime = context.state.transactionsFilter.maxTime * 1000 + 999;
} else if (reload && context.state.transactionsFilter.maxTime <= 0) {
actualMaxTime = 0;
}
return new Promise((resolve, reject) => {
services.getTransactions({
maxTime: actualMaxTime,
minTime: context.state.transactionsFilter.minTime * 1000,
type: context.state.transactionsFilter.type,
categoryId: context.state.transactionsFilter.categoryId,
accountId: context.state.transactionsFilter.accountId,
keyword: context.state.transactionsFilter.keyword
}).then(response => {
const data = response.data;
if (!data || !data.success || !data.result) {
if (reload) {
context.commit(LOAD_TRANSACTION_LIST, {
transactions: emptyTransactionResult,
reload: reload,
autoExpand: autoExpand,
defaultCurrency: defaultCurrency
});
if (!context.state.transactionListStateInvalid) {
context.commit(UPDATE_TRANSACTION_LIST_INVALID_STATE, true);
}
}
reject({ message: 'Unable to get transaction list' });
return;
}
context.commit(LOAD_TRANSACTION_LIST, {
transactions: data.result,
reload: reload,
autoExpand: autoExpand,
defaultCurrency: defaultCurrency
});
if (reload) {
if (context.state.transactionListStateInvalid) {
context.commit(UPDATE_TRANSACTION_LIST_INVALID_STATE, false);
}
}
resolve(data.result);
}).catch(error => {
logger.error('failed to load transaction list', error);
if (reload) {
context.commit(LOAD_TRANSACTION_LIST, {
transactions: emptyTransactionResult,
reload: reload,
autoExpand: autoExpand,
defaultCurrency: defaultCurrency
});
if (!context.state.transactionListStateInvalid) {
context.commit(UPDATE_TRANSACTION_LIST_INVALID_STATE, true);
}
}
if (error.response && error.response.data && error.response.data.errorMessage) {
reject({ error: error.response.data });
} else if (!error.processed) {
reject({ message: 'Unable to get transaction list' });
} else {
reject(error);
}
});
});
}
export function getTransaction(context, { transactionId }) {
return new Promise((resolve, reject) => {
services.getTransaction({
id: transactionId
}).then(response => {
const data = response.data;
if (!data || !data.success || !data.result) {
reject({ message: 'Unable to get transaction' });
return;
}
resolve(data.result);
}).catch(error => {
logger.error('failed to load transaction info', error);
if (error.response && error.response.data && error.response.data.errorMessage) {
reject({ error: error.response.data });
} else if (!error.processed) {
reject({ message: 'Unable to get transaction' });
} else {
reject(error);
}
});
});
}
export function saveTransaction(context, { transaction, defaultCurrency }) {
return new Promise((resolve, reject) => {
let promise = null;
if (!transaction.id) {
promise = services.addTransaction(transaction);
} else {
promise = services.modifyTransaction(transaction);
}
promise.then(response => {
const data = response.data;
if (!data || !data.success || !data.result) {
if (!transaction.id) {
reject({ message: 'Unable to add transaction' });
} else {
reject({ message: 'Unable to save transaction' });
}
return;
}
if (!transaction.id) {
if (!context.state.transactionListStateInvalid) {
context.commit(UPDATE_TRANSACTION_LIST_INVALID_STATE, true);
}
} else {
context.commit(SAVE_TRANSACTION_IN_TRANSACTION_LIST, {
transaction: data.result,
defaultCurrency: defaultCurrency
});
}
if (!context.state.accountListStateInvalid) {
context.commit(UPDATE_ACCOUNT_LIST_INVALID_STATE, true);
}
if (!context.state.transactionOverviewStateInvalid) {
context.commit(UPDATE_TRANSACTION_OVERVIEW_INVALID_STATE, true);
}
if (!context.state.transactionStatisticsStateInvalid) {
context.commit(UPDATE_TRANSACTION_STATISTICS_INVALID_STATE, true);
}
resolve(data.result);
}).catch(error => {
logger.error('failed to save transaction', error);
if (error.response && error.response.data && error.response.data.errorMessage) {
reject({ error: error.response.data });
} else if (!error.processed) {
if (!transaction.id) {
reject({ message: 'Unable to add transaction' });
} else {
reject({ message: 'Unable to save transaction' });
}
} else {
reject(error);
}
});
});
}
export function deleteTransaction(context, { transaction, defaultCurrency, beforeResolve }) {
return new Promise((resolve, reject) => {
services.deleteTransaction({
id: transaction.id
}).then(response => {
const data = response.data;
if (!data || !data.success || !data.result) {
reject({ message: 'Unable to delete this transaction' });
return;
}
if (beforeResolve) {
beforeResolve(() => {
context.commit(REMOVE_TRANSACTION_FROM_TRANSACTION_LIST, {
transaction: transaction,
defaultCurrency: defaultCurrency
});
});
} else {
context.commit(REMOVE_TRANSACTION_FROM_TRANSACTION_LIST, {
transaction: transaction,
defaultCurrency: defaultCurrency
});
}
if (!context.state.accountListStateInvalid) {
context.commit(UPDATE_ACCOUNT_LIST_INVALID_STATE, true);
}
if (!context.state.transactionOverviewStateInvalid) {
context.commit(UPDATE_TRANSACTION_OVERVIEW_INVALID_STATE, true);
}
if (!context.state.transactionStatisticsStateInvalid) {
context.commit(UPDATE_TRANSACTION_STATISTICS_INVALID_STATE, true);
}
resolve(data.result);
}).catch(error => {
logger.error('failed to delete transaction', error);
if (error.response && error.response.data && error.response.data.errorMessage) {
reject({ error: error.response.data });
} else if (!error.processed) {
reject({ message: 'Unable to delete this transaction' });
} else {
reject(error);
}
});
});
}
export function collapseMonthInTransactionList(context, { month, collapse }) {
context.commit(COLLAPSE_MONTH_IN_TRANSACTION_LIST, {
month: month,
collapse: collapse
});
}
export function noTransaction(state) {
for (let i = 0; i < state.transactions.length; i++) {
const transactionMonthList = state.transactions[i];
for (let j = 0; j < transactionMonthList.items.length; j++) {
if (transactionMonthList.items[j]) {
return false;
}
}
}
return true;
}
export function hasMoreTransaction(state) {
return state.transactionsNextTimeId > 0;
}
export function fillTransactionObject(state, transaction) {
if (!transaction) {
return;
}
const transactionTime = utils.parseDateFromUnixTime(transaction.time);
transaction.day = utils.getDay(transactionTime);
transaction.dayOfWeek = utils.getDayOfWeek(transactionTime);
if (transaction.sourceAccountId) {
transaction.sourceAccount = state.allAccountsMap[transaction.sourceAccountId];
}
if (transaction.destinationAccountId) {
transaction.destinationAccount = state.allAccountsMap[transaction.destinationAccountId];
}
if (transaction.categoryId) {
transaction.category = state.allTransactionCategoriesMap[transaction.categoryId];
}
return transaction;
}
export function calculateMonthTotalAmount(state, transactionMonthList, defaultCurrency, accountId, incomplete) {
if (!transactionMonthList) {
return;
}
let totalExpense = 0;
let totalIncome = 0;
let hasUnCalculatedTotalExpense = false;
let hasUnCalculatedTotalIncome = false;
for (let i = 0; i < transactionMonthList.items.length; i++) {
const transaction = transactionMonthList.items[i];
let amount = transaction.sourceAmount;
let account = transaction.sourceAccount;
if (accountId && transaction.destinationAccount && transaction.destinationAccount.id === accountId) {
amount = transaction.destinationAmount;
account = transaction.destinationAccount;
}
if (!account) {
continue;
}
if (account.currency !== defaultCurrency) {
const balance = getExchangedAmount(state)(amount, account.currency, defaultCurrency);
if (!utils.isNumber(balance)) {
if (transaction.type === transactionConstants.allTransactionTypes.Expense) {
hasUnCalculatedTotalExpense = true;
} else if (transaction.type === transactionConstants.allTransactionTypes.Income) {
hasUnCalculatedTotalIncome = true;
}
continue;
}
amount = Math.floor(balance);
}
if (transaction.type === transactionConstants.allTransactionTypes.Expense) {
totalExpense += amount;
} else if (transaction.type === transactionConstants.allTransactionTypes.Income) {
totalIncome += amount;
} else if (transaction.type === transactionConstants.allTransactionTypes.Transfer && accountId) {
if (accountId === transaction.sourceAccountId) {
totalExpense += amount;
} else if (accountId === transaction.destinationAccountId) {
totalIncome += amount;
}
}
}
transactionMonthList.totalAmount = {
expense: totalExpense,
incompleteExpense: incomplete || hasUnCalculatedTotalExpense,
income: totalIncome,
incompleteIncome: incomplete || hasUnCalculatedTotalIncome
};
}