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>) { 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; // 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>; 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;