forked from wangziqi/gongxue-base
178 lines
5.4 KiB
TypeScript
178 lines
5.4 KiB
TypeScript
import {
|
|
Controller,
|
|
Get,
|
|
Post,
|
|
Put,
|
|
Delete,
|
|
Body,
|
|
Param,
|
|
Query,
|
|
UseGuards,
|
|
Request,
|
|
} from '@nestjs/common';
|
|
import { DepositsService } from './deposits.service';
|
|
import { NotificationsService } from '../notifications/notifications.service';
|
|
import { NotificationType } from '../entities/notification.entity';
|
|
import { CreateDepositDto, RefundDepositDto, CreateDepositWithInstallmentsDto } from './dto/deposit.dto';
|
|
import { JwtAuthGuard } from '../auth/guards/jwt-auth.guard';
|
|
import { OperationLogsService } from '../operation-logs/operation-logs.service';
|
|
import { extractRequestInfo } from '../common/request-utils';
|
|
import { RequirePermission } from '../auth/decorators/permission.decorator';
|
|
|
|
@UseGuards(JwtAuthGuard)
|
|
@Controller('deposits')
|
|
export class DepositsController {
|
|
constructor(
|
|
private service: DepositsService,
|
|
private logService: OperationLogsService,
|
|
private readonly notificationsService: NotificationsService,
|
|
) {}
|
|
|
|
@Get()
|
|
@RequirePermission('deposit:view')
|
|
findAll(@Query('studentId') studentId?: string, @Query('status') status?: string) {
|
|
return this.service.findAll({
|
|
studentId: studentId ? +studentId : undefined,
|
|
status: status || undefined,
|
|
});
|
|
}
|
|
|
|
@Get('pending-refunds')
|
|
@RequirePermission('deposit:edit')
|
|
findPendingRefunds() {
|
|
return this.service.findPendingRefunds();
|
|
}
|
|
|
|
@Get('stats')
|
|
@RequirePermission('deposit:view')
|
|
getStats() {
|
|
return this.service.getStats();
|
|
}
|
|
|
|
@Get(':id')
|
|
@RequirePermission('deposit:view')
|
|
findOne(@Param('id') id: string) {
|
|
return this.service.findOne(+id);
|
|
}
|
|
|
|
@Post()
|
|
@RequirePermission('deposit:create')
|
|
async create(@Body() dto: CreateDepositDto | CreateDepositWithInstallmentsDto, @Request() req: any) {
|
|
const { ipAddress, userAgent } = extractRequestInfo(req);
|
|
const result = await this.service.create(dto, req.user?.id);
|
|
await this.logService.log({
|
|
userId: req.user?.id,
|
|
username: req.user?.username,
|
|
module: '押金管理',
|
|
action: '收取押金',
|
|
targetId: result.id,
|
|
targetType: 'deposit',
|
|
detail: `学生${dto.studentId} ¥${dto.amount}`,
|
|
ipAddress,
|
|
userAgent,
|
|
});
|
|
// TODO: Send notification for deposit_due — studentId→userId mapping unavailable
|
|
return result;
|
|
}
|
|
|
|
@Post(':id/installments')
|
|
@RequirePermission('deposit:edit')
|
|
async addInstallment(
|
|
@Param('id') id: string,
|
|
@Body() body: { amount: number; dueDate: string },
|
|
) {
|
|
return this.service.addInstallment(+id, body.amount, body.dueDate);
|
|
}
|
|
|
|
@Put('installments/:installmentId')
|
|
@RequirePermission('deposit:edit')
|
|
async updateInstallment(
|
|
@Param('installmentId') installmentId: string,
|
|
@Body() body: { paidDate?: string; status?: string },
|
|
) {
|
|
return this.service.updateInstallment(+installmentId, body);
|
|
}
|
|
|
|
@Delete('installments/:installmentId')
|
|
@RequirePermission('deposit:delete')
|
|
async deleteInstallment(@Param('installmentId') installmentId: string) {
|
|
return this.service.deleteInstallment(+installmentId);
|
|
}
|
|
|
|
@Put(':id/refund')
|
|
@RequirePermission('deposit:edit')
|
|
async refund(@Param('id') id: string, @Body() dto: RefundDepositDto, @Request() req: any) {
|
|
const { ipAddress, userAgent } = extractRequestInfo(req);
|
|
const result = await this.service.refund(+id, dto, req.user?.id);
|
|
await this.logService.log({
|
|
userId: req.user?.id,
|
|
username: req.user?.username,
|
|
module: '押金管理',
|
|
action: '退还押金',
|
|
targetId: +id,
|
|
targetType: 'deposit',
|
|
detail: `退还¥${result.refundAmount}, 扣除¥${result.deductionAmount}`,
|
|
ipAddress,
|
|
userAgent,
|
|
});
|
|
// TODO: Send notification for deposit_refunded — studentId→userId mapping unavailable
|
|
return result;
|
|
}
|
|
|
|
@Post(':id/request-refund')
|
|
@RequirePermission('deposit:edit')
|
|
async requestRefund(@Param('id') id: string, @Request() req: any) {
|
|
const { ipAddress, userAgent } = extractRequestInfo(req);
|
|
const result = await this.service.requestRefund(+id);
|
|
await this.logService.log({
|
|
userId: req.user?.id,
|
|
username: req.user?.username,
|
|
module: '押金管理',
|
|
action: '申请退款',
|
|
targetId: +id,
|
|
targetType: 'deposit',
|
|
detail: '提交退款申请',
|
|
ipAddress,
|
|
userAgent,
|
|
});
|
|
return result;
|
|
}
|
|
|
|
@Put(':id/approve-refund')
|
|
@RequirePermission('deposit:approve')
|
|
async approveRefund(@Param('id') id: string, @Request() req: any) {
|
|
const { ipAddress, userAgent } = extractRequestInfo(req);
|
|
const result = await this.service.approveRefund(+id, req.user?.id);
|
|
await this.logService.log({
|
|
userId: req.user?.id,
|
|
username: req.user?.username,
|
|
module: '押金管理',
|
|
action: '审批退款',
|
|
targetId: +id,
|
|
targetType: 'deposit',
|
|
detail: `审批通过 → ${result.refundStatus}`,
|
|
ipAddress,
|
|
userAgent,
|
|
});
|
|
return result;
|
|
}
|
|
|
|
@Delete(':id')
|
|
@RequirePermission('deposit:delete')
|
|
async remove(@Param('id') id: string, @Request() req: any) {
|
|
const { ipAddress, userAgent } = extractRequestInfo(req);
|
|
const result = await this.service.remove(+id);
|
|
await this.logService.log({
|
|
userId: req.user?.id,
|
|
username: req.user?.username,
|
|
module: '押金管理',
|
|
action: '删除押金记录',
|
|
targetId: +id,
|
|
targetType: 'deposit',
|
|
ipAddress,
|
|
userAgent,
|
|
});
|
|
return result;
|
|
}
|
|
}
|