import express from 'express'; import { transactionService } from '../services/transactionService.js'; import { authenticate, requireTenant, requireAdmin } from '../middleware/auth.js'; import { validateRequest } from '../middleware/validation.js'; import { body, param, query } from 'express-validator'; import { logger } from '../utils/logger.js'; const router = express.Router(); // Get transactions router.get('/', authenticate, requireTenant, validateRequest([ query('type').optional().isIn(['payment', 'refund', 'adjustment', 'fee']), query('status').optional().isIn(['pending', 'processing', 'succeeded', 'failed', 'canceled']), query('startDate').optional().isISO8601(), query('endDate').optional().isISO8601(), query('limit').optional().isInt({ min: 1, max: 100 }), query('offset').optional().isInt({ min: 0 }) ]), async (req, res) => { try { const transactions = await transactionService.getTransactions( req.tenantId, req.query ); res.json({ success: true, transactions }); } catch (error) { logger.error('Get transactions error:', error); res.status(500).json({ success: false, error: 'Failed to get transactions' }); } } ); // Get transaction by ID router.get('/:id', authenticate, requireTenant, validateRequest([ param('id').isMongoId() ]), async (req, res) => { try { const transaction = await transactionService.getTransaction( req.tenantId, req.params.id ); if (!transaction) { return res.status(404).json({ success: false, error: 'Transaction not found' }); } res.json({ success: true, transaction }); } catch (error) { logger.error('Get transaction error:', error); res.status(500).json({ success: false, error: 'Failed to get transaction' }); } } ); // Create refund router.post('/:id/refund', authenticate, requireTenant, validateRequest([ param('id').isMongoId(), body('amount').optional().isFloat({ min: 0 }), body('reason').notEmpty(), body('metadata').optional().isObject() ]), async (req, res) => { try { const refund = await transactionService.createRefund( req.tenantId, req.params.id, { ...req.body, initiatedBy: req.user.id } ); res.status(201).json({ success: true, refund, message: 'Refund initiated successfully' }); } catch (error) { logger.error('Create refund error:', error); res.status(500).json({ success: false, error: 'Failed to create refund' }); } } ); // Get transaction summary router.get('/summary/:period', authenticate, requireTenant, validateRequest([ param('period').isIn(['daily', 'weekly', 'monthly', 'yearly']), query('startDate').optional().isISO8601(), query('endDate').optional().isISO8601() ]), async (req, res) => { try { const summary = await transactionService.getTransactionSummary( req.tenantId, req.params.period, { startDate: req.query.startDate, endDate: req.query.endDate } ); res.json({ success: true, summary }); } catch (error) { logger.error('Get transaction summary error:', error); res.status(500).json({ success: false, error: 'Failed to get transaction summary' }); } } ); // Export transactions router.get('/export/:format', authenticate, requireTenant, validateRequest([ param('format').isIn(['csv', 'pdf', 'excel']), query('startDate').optional().isISO8601(), query('endDate').optional().isISO8601() ]), async (req, res) => { try { const { filename, data } = await transactionService.exportTransactions( req.tenantId, req.params.format, { startDate: req.query.startDate, endDate: req.query.endDate } ); // Set appropriate headers based on format const contentType = { csv: 'text/csv', pdf: 'application/pdf', excel: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' }; res.setHeader('Content-Type', contentType[req.params.format]); res.setHeader('Content-Disposition', `attachment; filename="${filename}"`); res.send(data); } catch (error) { logger.error('Export transactions error:', error); res.status(500).json({ success: false, error: 'Failed to export transactions' }); } } ); // Admin: Create manual adjustment router.post('/adjustment', authenticate, requireAdmin, validateRequest([ body('tenantId').isMongoId(), body('type').isIn(['credit', 'debit']), body('amount').isFloat({ min: 0 }), body('currency').optional().isString(), body('reason').notEmpty(), body('metadata').optional().isObject() ]), async (req, res) => { try { const adjustment = await transactionService.createAdjustment({ ...req.body, createdBy: req.user.id }); res.status(201).json({ success: true, adjustment, message: 'Adjustment created successfully' }); } catch (error) { logger.error('Create adjustment error:', error); res.status(500).json({ success: false, error: 'Failed to create adjustment' }); } } ); export default router;