/** * Transactions Controller * * REST API endpoints for payment transactions */ import { Router, Request, Response, NextFunction } from 'express'; import { DataSource } from 'typeorm'; import { TransactionsService } from '../services'; import { ProcessPaymentDto, ProcessRefundDto, SendReceiptDto, TransactionFilterDto } from '../dto'; // Extend Request to include tenant info interface AuthenticatedRequest extends Request { tenantId?: string; userId?: string; } export class TransactionsController { public router: Router; private service: TransactionsService; constructor(dataSource: DataSource) { this.router = Router(); this.service = new TransactionsService(dataSource); this.initializeRoutes(); } private initializeRoutes(): void { // Stats this.router.get('/stats', this.getStats.bind(this)); // Payment processing this.router.post('/charge', this.processPayment.bind(this)); this.router.post('/refund', this.processRefund.bind(this)); // Transaction queries this.router.get('/', this.getAll.bind(this)); this.router.get('/:id', this.getById.bind(this)); // Actions this.router.post('/:id/receipt', this.sendReceipt.bind(this)); } /** * GET /payment-transactions/stats * Get transaction statistics */ private async getStats(req: AuthenticatedRequest, res: Response, next: NextFunction): Promise { try { const filter: Partial = { branchId: req.query.branchId as string, startDate: req.query.startDate ? new Date(req.query.startDate as string) : undefined, endDate: req.query.endDate ? new Date(req.query.endDate as string) : undefined, }; const stats = await this.service.getStats(req.tenantId!, filter as TransactionFilterDto); res.json({ data: stats }); } catch (error) { next(error); } } /** * POST /payment-transactions/charge * Process a payment */ private async processPayment(req: AuthenticatedRequest, res: Response, next: NextFunction): Promise { try { const dto: ProcessPaymentDto = req.body; const result = await this.service.processPayment(req.tenantId!, req.userId!, dto); if (result.success) { res.status(201).json({ data: result }); } else { res.status(400).json({ data: result }); } } catch (error) { next(error); } } /** * POST /payment-transactions/refund * Process a refund */ private async processRefund(req: AuthenticatedRequest, res: Response, next: NextFunction): Promise { try { const dto: ProcessRefundDto = req.body; const result = await this.service.processRefund(req.tenantId!, req.userId!, dto); if (result.success) { res.json({ data: result }); } else { res.status(400).json({ data: result }); } } catch (error) { next(error); } } /** * GET /payment-transactions * Get transactions with filters */ private async getAll(req: AuthenticatedRequest, res: Response, next: NextFunction): Promise { try { const filter: TransactionFilterDto = { branchId: req.query.branchId as string, userId: req.query.userId as string, status: req.query.status as any, sourceType: req.query.sourceType as any, terminalProvider: req.query.terminalProvider as string, startDate: req.query.startDate ? new Date(req.query.startDate as string) : undefined, endDate: req.query.endDate ? new Date(req.query.endDate as string) : undefined, limit: req.query.limit ? parseInt(req.query.limit as string) : 20, offset: req.query.offset ? parseInt(req.query.offset as string) : 0, }; const result = await this.service.findAll(req.tenantId!, filter); res.json(result); } catch (error) { next(error); } } /** * GET /payment-transactions/:id * Get transaction by ID */ private async getById(req: AuthenticatedRequest, res: Response, next: NextFunction): Promise { try { const transaction = await this.service.findById(req.params.id, req.tenantId!); if (!transaction) { res.status(404).json({ error: 'Transaction not found' }); return; } res.json({ data: transaction }); } catch (error) { next(error); } } /** * POST /payment-transactions/:id/receipt * Send receipt for transaction */ private async sendReceipt(req: AuthenticatedRequest, res: Response, next: NextFunction): Promise { try { const dto: SendReceiptDto = req.body; const result = await this.service.sendReceipt(req.params.id, req.tenantId!, dto); if (result.success) { res.json({ success: true }); } else { res.status(400).json({ success: false, error: result.error }); } } catch (error) { next(error); } } }