Files
budgeteer/web/src/stores/budget-account.ts
Jan Bader 4c6d21c2b4
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
Improve editing and creating of transactions
2022-02-27 21:15:46 +00:00

220 lines
8.3 KiB
TypeScript

import { defineStore } from "pinia"
import { GET, POST } from "../api";
import { useBudgetsStore } from "./budget";
import { useSessionStore } from "./session";
interface State {
Accounts: Map<string, Account>
CurrentAccountID: string | null
Categories: Map<string, Category>
Months: Map<number, Map<number, Map<string, Category>>>
Transactions: Map<string, Transaction>
Assignments: []
Reconciling: boolean
}
export interface Transaction {
ID: string
Date: Date
TransferAccount: string
CategoryGroup: string
Category: string
CategoryID: string | undefined
Memo: string
Status: string
GroupID: string
Payee: string
PayeeID: string | undefined
Amount: number
Reconciled: boolean
}
export interface Account {
ID: string
Name: string
OnBudget: boolean
ClearedBalance: number
WorkingBalance: number
ReconciledBalance: number
Transactions: string[]
}
export interface Category {
ID: string
Group: string
Name: string
AvailableLastMonth: number
Assigned: number
Activity: number
Available: number
}
export const useAccountStore = defineStore("budget/account", {
state: (): State => ({
Accounts: new Map<string, Account>(),
CurrentAccountID: null,
Months: new Map<number, Map<number, Map<string, Category>>>(),
Categories: new Map<string, Category>(),
Transactions: new Map<string, Transaction>(),
Assignments: [],
Reconciling: false,
}),
getters: {
AccountsList(state) {
return [...state.Accounts.values()];
},
AllCategoriesForMonth: (state) => (year: number, month: number) => {
const yearMap = state.Months.get(year);
const monthMap = yearMap?.get(month);
return [...monthMap?.values() || []];
},
CategoryGroupsForMonth(state) {
return (year: number, month: number) => {
const categories = this.AllCategoriesForMonth(year, month);
const categoryGroups = [];
let prev = undefined;
for (const category of categories) {
if (category.Group != prev)
categoryGroups.push({
Name: category.Group,
Expand: category.Group != "Hidden Categories",
});
prev = category.Group;
}
return categoryGroups;
}
},
CategoriesForMonthAndGroup(state) {
return (year: number, month: number, group: string) => {
const categories = this.AllCategoriesForMonth(year, month);
return categories.filter(x => x.Group == group);
}
},
CurrentAccount(state): Account | undefined {
if (state.CurrentAccountID == null)
return undefined;
return state.Accounts.get(state.CurrentAccountID);
},
ReconcilingBalance(state): number {
let reconciledBalance = this.CurrentAccount!.ReconciledBalance;
for (const transaction of this.TransactionsList) {
if (transaction.Reconciled)
reconciledBalance += transaction.Amount;
}
return reconciledBalance;
},
OnBudgetAccounts(state) {
return [...state.Accounts.values()].filter(x => x.OnBudget);
},
OnBudgetAccountsBalance(state): number {
return this.OnBudgetAccounts.reduce((prev, curr) => prev + Number(curr.ClearedBalance), 0);
},
OffBudgetAccounts(state) {
return [...state.Accounts.values()].filter(x => !x.OnBudget);
},
OffBudgetAccountsBalance(state): number {
return this.OffBudgetAccounts.reduce((prev, curr) => prev + Number(curr.ClearedBalance), 0);
},
TransactionsList(state): Transaction[] {
return this.CurrentAccount!.Transactions.map(x => {
return this.Transactions.get(x)!
});
},
},
actions: {
async SetCurrentAccount(budgetid: string, accountid: string) {
if (budgetid == null)
return
this.CurrentAccountID = accountid;
const account = this.CurrentAccount;
if (account == undefined)
return
useSessionStore().setTitle(account.Name);
await this.FetchAccount(account);
},
AddTransaction(account: Account, transaction: any) {
transaction.Date = new Date(transaction.Date);
this.Transactions.set(transaction.ID, transaction);
},
async FetchAccount(account: Account) {
const result = await GET("/account/" + account.ID + "/transactions");
const response = await result.json();
account.Transactions = [];
for (const transaction of response.Transactions) {
this.AddTransaction(account, transaction);
account.Transactions.push(transaction.ID);
}
},
async FetchMonthBudget(budgetid: string, year: number, month: number) {
const result = await GET("/budget/" + budgetid + "/" + year + "/" + month);
const response = await result.json();
if (response.Categories == undefined || response.Categories.length <= 0)
return;
this.addCategoriesForMonth(year, month, response.Categories);
},
async EditAccount(accountid: string, name: string, onBudget: boolean) {
const result = await POST("/account/" + accountid, JSON.stringify({ name: name, onBudget: onBudget }));
const response = await result.json();
useBudgetsStore().MergeBudgetingData(response);
},
addCategoriesForMonth(year: number, month: number, categories: Category[]): void {
this.$patch((state) => {
const yearMap = state.Months.get(year) || new Map<number, Map<string, Category>>();
const monthMap = yearMap.get(month) || new Map<string, Category>();
for (const category of categories) {
monthMap.set(category.ID, category);
}
yearMap.set(month, monthMap);
state.Months.set(year, yearMap);
});
},
SetReconciledForAllTransactions(value: boolean) {
for (const transaction of this.TransactionsList) {
if (transaction.Status == "Reconciled")
continue;
transaction.Reconciled = value;
}
},
async SubmitReconcilation(reconciliationTransactionAmount: number) {
const account = this.CurrentAccount!;
const reconciledTransactions = this.TransactionsList.filter(x => x.Reconciled);
for (const transaction of reconciledTransactions) {
account.ReconciledBalance += transaction.Amount;
transaction.Status = "Reconciled";
transaction.Reconciled = false;
}
const result = await POST("/account/" + this.CurrentAccountID + "/reconcile", JSON.stringify({
transactionIDs: reconciledTransactions.map(x => x.ID),
reconciliationTransactionAmount: reconciliationTransactionAmount.toString(),
}));
const response = await result.json();
const recTrans = response.ReconciliationTransaction;
if (recTrans) {
this.AddTransaction(account, recTrans);
account.Transactions.unshift(recTrans.ID);
}
console.log("Reconcile: " + response.message);
},
logout() {
this.$reset()
},
async saveTransaction(payload: string) {
const result = await POST("/transaction/new", payload);
const response = await result.json();
this.AddTransaction(this.CurrentAccount!, response);
this.CurrentAccount?.Transactions.unshift(response.ID);
},
async editTransaction(transactionid: string, payload: string) {
const result = await POST("/transaction/" + transactionid, payload);
const response = await result.json();
this.AddTransaction(this.CurrentAccount!, response);
}
}
})