mirror of
https://github.com/acedanger/finance.git
synced 2025-12-05 22:50:12 -08:00
transitioned from astro to react
This commit is contained in:
189
server/routes/transactions.ts
Normal file
189
server/routes/transactions.ts
Normal file
@@ -0,0 +1,189 @@
|
||||
import { Router } from 'express';
|
||||
import { accountService, transactionService } from '../data/db.service.js';
|
||||
import type { Transaction, TransactionStatus, TransactionType } from '../types.js';
|
||||
|
||||
const router = Router();
|
||||
|
||||
// Helper function to transform update data
|
||||
function transformUpdateData(updateData: Partial<Omit<Transaction, 'id'>>) {
|
||||
const typedUpdateData: {
|
||||
accountId?: string;
|
||||
date?: Date;
|
||||
description?: string;
|
||||
amount?: number;
|
||||
category?: string;
|
||||
status?: TransactionStatus;
|
||||
type?: TransactionType;
|
||||
notes?: string;
|
||||
tags?: string;
|
||||
} = {};
|
||||
|
||||
// Convert string date to Date object if provided
|
||||
if (updateData.date) {
|
||||
typedUpdateData.date =
|
||||
typeof updateData.date === 'string' ? new Date(updateData.date) : updateData.date;
|
||||
}
|
||||
|
||||
// Convert amount to number if provided
|
||||
if (updateData.amount !== undefined) {
|
||||
typedUpdateData.amount = Number(updateData.amount);
|
||||
}
|
||||
|
||||
// Copy other fields
|
||||
if (updateData.accountId) typedUpdateData.accountId = updateData.accountId;
|
||||
if (updateData.description) typedUpdateData.description = updateData.description;
|
||||
if (updateData.category !== undefined)
|
||||
typedUpdateData.category = updateData.category || undefined;
|
||||
if (updateData.status) typedUpdateData.status = updateData.status as TransactionStatus;
|
||||
if (updateData.type) typedUpdateData.type = updateData.type as TransactionType;
|
||||
if (updateData.notes !== undefined) typedUpdateData.notes = updateData.notes || undefined;
|
||||
if (updateData.tags !== undefined) typedUpdateData.tags = updateData.tags || undefined;
|
||||
|
||||
return typedUpdateData;
|
||||
}
|
||||
|
||||
// POST /api/transactions - Create new transaction
|
||||
// biome-ignore lint/suspicious/noExplicitAny: Express handler types require any for req/res
|
||||
router.post('/', async (req: any, res: any) => {
|
||||
try {
|
||||
const transaction = req.body as Omit<Transaction, 'id'>;
|
||||
|
||||
// Validate required fields
|
||||
if (
|
||||
!transaction.accountId ||
|
||||
!transaction.date ||
|
||||
!transaction.description ||
|
||||
transaction.amount === undefined
|
||||
) {
|
||||
return res.status(400).json({ error: 'Missing required fields' });
|
||||
}
|
||||
|
||||
// Validate account exists
|
||||
const account = await accountService.getById(transaction.accountId);
|
||||
if (!account) {
|
||||
return res.status(404).json({ error: 'Account not found' });
|
||||
}
|
||||
|
||||
// Convert string date to Date object if needed
|
||||
const transactionDate =
|
||||
typeof transaction.date === 'string' ? new Date(transaction.date) : transaction.date;
|
||||
|
||||
// Create new transaction with database service
|
||||
const newTransaction = await transactionService.create({
|
||||
accountId: transaction.accountId,
|
||||
date: transactionDate,
|
||||
description: transaction.description,
|
||||
amount: Number(transaction.amount),
|
||||
category: transaction.category || undefined,
|
||||
status: transaction.status as TransactionStatus,
|
||||
type: transaction.type as TransactionType,
|
||||
notes: transaction.notes || undefined,
|
||||
tags: transaction.tags || undefined,
|
||||
});
|
||||
|
||||
// Convert Decimal to number for response
|
||||
const response = {
|
||||
...newTransaction,
|
||||
amount: Number(newTransaction.amount),
|
||||
};
|
||||
|
||||
res.status(201).json(response);
|
||||
} catch (error) {
|
||||
console.error('Error creating transaction:', error);
|
||||
res.status(500).json({ error: 'Failed to create transaction' });
|
||||
}
|
||||
});
|
||||
|
||||
// GET /api/transactions/:id - Get single transaction
|
||||
// biome-ignore lint/suspicious/noExplicitAny: Express handler types require any for req/res
|
||||
router.get('/:id', async (req: any, res: any) => {
|
||||
try {
|
||||
const { id } = req.params;
|
||||
|
||||
if (!id) {
|
||||
return res.status(400).json({ error: 'Transaction ID is required' });
|
||||
}
|
||||
|
||||
const transaction = await transactionService.getById(id);
|
||||
|
||||
if (!transaction) {
|
||||
return res.status(404).json({ error: 'Transaction not found' });
|
||||
}
|
||||
|
||||
// Convert Decimal to number for response
|
||||
const response = {
|
||||
...transaction,
|
||||
amount: Number(transaction.amount),
|
||||
};
|
||||
|
||||
res.json(response);
|
||||
} catch (error) {
|
||||
console.error('Error fetching transaction:', error);
|
||||
res.status(500).json({ error: 'Failed to fetch transaction' });
|
||||
}
|
||||
});
|
||||
|
||||
// PUT /api/transactions/:id - Update transaction
|
||||
// biome-ignore lint/suspicious/noExplicitAny: Express handler types require any for req/res
|
||||
router.put('/:id', async (req: any, res: any) => {
|
||||
try {
|
||||
const { id } = req.params;
|
||||
|
||||
if (!id) {
|
||||
return res.status(400).json({ error: 'Transaction ID is required' });
|
||||
}
|
||||
|
||||
// Check if transaction exists
|
||||
const existingTransaction = await transactionService.getById(id);
|
||||
if (!existingTransaction) {
|
||||
return res.status(404).json({ error: 'Transaction not found' });
|
||||
}
|
||||
|
||||
const updateData = req.body as Partial<Omit<Transaction, 'id'>>;
|
||||
const typedUpdateData = transformUpdateData(updateData);
|
||||
|
||||
const updatedTransaction = await transactionService.update(id, typedUpdateData);
|
||||
|
||||
if (!updatedTransaction) {
|
||||
return res.status(404).json({ error: 'Transaction not found or could not be updated' });
|
||||
}
|
||||
|
||||
// Convert Decimal to number for response
|
||||
const response = {
|
||||
...updatedTransaction,
|
||||
amount: Number(updatedTransaction.amount),
|
||||
};
|
||||
|
||||
res.json(response);
|
||||
} catch (error) {
|
||||
console.error('Error updating transaction:', error);
|
||||
res.status(500).json({ error: 'Failed to update transaction' });
|
||||
}
|
||||
});
|
||||
|
||||
// DELETE /api/transactions/:id - Delete transaction
|
||||
// biome-ignore lint/suspicious/noExplicitAny: Express handler types require any for req/res
|
||||
router.delete('/:id', async (req: any, res: any) => {
|
||||
try {
|
||||
const { id } = req.params;
|
||||
|
||||
if (!id) {
|
||||
return res.status(400).json({ error: 'Transaction ID is required' });
|
||||
}
|
||||
|
||||
// Check if transaction exists
|
||||
const existingTransaction = await transactionService.getById(id);
|
||||
if (!existingTransaction) {
|
||||
return res.status(404).json({ error: 'Transaction not found' });
|
||||
}
|
||||
|
||||
await transactionService.delete(id);
|
||||
|
||||
res.status(204).send();
|
||||
} catch (error) {
|
||||
console.error('Error deleting transaction:', error);
|
||||
res.status(500).json({ error: 'Failed to delete transaction' });
|
||||
}
|
||||
});
|
||||
|
||||
export default router;
|
||||
Reference in New Issue
Block a user