159 lines
4.3 KiB
TypeScript
159 lines
4.3 KiB
TypeScript
/**
|
|
* Account Service - API calls for account management
|
|
*/
|
|
|
|
import api from './api';
|
|
import type { Account, AccountFormInput, TransferFormInput, ApiResponse } from '../types';
|
|
|
|
/**
|
|
* Get all accounts
|
|
*/
|
|
export async function getAccounts(): Promise<Account[]> {
|
|
const response = await api.get<ApiResponse<Account[]>>('/accounts');
|
|
return response.data || [];
|
|
}
|
|
|
|
/**
|
|
* Get a single account by ID
|
|
*/
|
|
export async function getAccount(id: number): Promise<Account> {
|
|
const response = await api.get<ApiResponse<Account>>(`/accounts/${id}`);
|
|
if (!response.data) {
|
|
throw new Error('Account not found');
|
|
}
|
|
return response.data;
|
|
}
|
|
|
|
/**
|
|
* Create a new account
|
|
*/
|
|
export async function createAccount(data: AccountFormInput): Promise<Account> {
|
|
// Convert camelCase to snake_case for backend
|
|
const payload = {
|
|
name: data.name,
|
|
type: data.type,
|
|
balance: data.balance,
|
|
currency: data.currency,
|
|
icon: data.icon,
|
|
billing_date: data.billingDate,
|
|
payment_date: data.paymentDate,
|
|
};
|
|
const response = await api.post<ApiResponse<Account>>('/accounts', payload);
|
|
if (!response.data) {
|
|
throw new Error(response.error || 'Failed to create account');
|
|
}
|
|
return response.data;
|
|
}
|
|
|
|
/**
|
|
* Update an existing account
|
|
*/
|
|
export async function updateAccount(id: number, data: Partial<AccountFormInput>): Promise<Account> {
|
|
// Convert camelCase to snake_case for backend
|
|
const payload: Record<string, unknown> = {};
|
|
if (data.name !== undefined) payload.name = data.name;
|
|
if (data.type !== undefined) payload.type = data.type;
|
|
if (data.balance !== undefined) payload.balance = data.balance;
|
|
if (data.currency !== undefined) payload.currency = data.currency;
|
|
if (data.icon !== undefined) payload.icon = data.icon;
|
|
if (data.billingDate !== undefined) payload.billing_date = data.billingDate;
|
|
if (data.paymentDate !== undefined) payload.payment_date = data.paymentDate;
|
|
|
|
const response = await api.put<ApiResponse<Account>>(`/accounts/${id}`, payload);
|
|
if (!response.data) {
|
|
throw new Error(response.error || 'Failed to update account');
|
|
}
|
|
return response.data;
|
|
}
|
|
|
|
/**
|
|
* Delete an account
|
|
*/
|
|
export async function deleteAccount(id: number): Promise<void> {
|
|
await api.delete<ApiResponse<void>>(`/accounts/${id}`);
|
|
}
|
|
|
|
/**
|
|
* Transfer between accounts
|
|
*/
|
|
export async function transferBetweenAccounts(data: TransferFormInput): Promise<void> {
|
|
// Convert camelCase to snake_case for backend
|
|
const payload = {
|
|
from_account_id: data.fromAccountId,
|
|
to_account_id: data.toAccountId,
|
|
amount: data.amount,
|
|
note: data.note,
|
|
};
|
|
const response = await api.post<ApiResponse<void>>('/accounts/transfer', payload);
|
|
if (!response.success && response.error) {
|
|
throw new Error(response.error);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get accounts grouped by type
|
|
*/
|
|
export function groupAccountsByType(accounts: Account[] | undefined): Record<string, Account[]> {
|
|
if (!accounts || !Array.isArray(accounts)) {
|
|
return {};
|
|
}
|
|
return accounts.reduce(
|
|
(groups, account) => {
|
|
const type = account.type;
|
|
if (!groups[type]) {
|
|
groups[type] = [];
|
|
}
|
|
groups[type].push(account);
|
|
return groups;
|
|
},
|
|
{} as Record<string, Account[]>
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Calculate total balance for accounts
|
|
*/
|
|
export function calculateTotalBalance(accounts: Account[] | undefined): number {
|
|
if (!accounts || !Array.isArray(accounts)) {
|
|
return 0;
|
|
}
|
|
return accounts.reduce((total, account) => total + account.balance, 0);
|
|
}
|
|
|
|
/**
|
|
* Calculate total assets (positive balances)
|
|
*/
|
|
export function calculateTotalAssets(accounts: Account[] | undefined): number {
|
|
if (!accounts || !Array.isArray(accounts)) {
|
|
return 0;
|
|
}
|
|
return accounts
|
|
.filter((account) => account.balance > 0)
|
|
.reduce((total, account) => total + account.balance, 0);
|
|
}
|
|
|
|
/**
|
|
* Calculate total liabilities (negative balances)
|
|
*/
|
|
export function calculateTotalLiabilities(accounts: Account[] | undefined): number {
|
|
if (!accounts || !Array.isArray(accounts)) {
|
|
return 0;
|
|
}
|
|
return accounts
|
|
.filter((account) => account.balance < 0)
|
|
.reduce((total, account) => total + Math.abs(account.balance), 0);
|
|
}
|
|
|
|
export default {
|
|
getAccounts,
|
|
getAccount,
|
|
createAccount,
|
|
updateAccount,
|
|
deleteAccount,
|
|
transferBetweenAccounts,
|
|
groupAccountsByType,
|
|
calculateTotalBalance,
|
|
calculateTotalAssets,
|
|
calculateTotalLiabilities,
|
|
};
|