Files
telegram-management-system/marketing-agent/services/billing-service/src/routes/transactions.js
你的用户名 237c7802e5
Some checks failed
Deploy / deploy (push) Has been cancelled
Initial commit: Telegram Management System
Full-stack web application for Telegram management
- Frontend: Vue 3 + Vben Admin
- Backend: NestJS
- Features: User management, group broadcast, statistics

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-04 15:37:50 +08:00

222 lines
5.5 KiB
JavaScript

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;