fix: 修复批量更新账单状态功能
This commit is contained in:
@@ -7,6 +7,7 @@ import {
|
||||
Param,
|
||||
Body,
|
||||
Query,
|
||||
ParseIntPipe,
|
||||
UseGuards,
|
||||
Request,
|
||||
Res,
|
||||
@@ -20,7 +21,11 @@ import { NotificationType } from '../entities/notification.entity';
|
||||
import { Student } from '../entities/student.entity';
|
||||
import { Bill } from '../entities/bill.entity';
|
||||
import { BillsExportService } from './bills-export.service';
|
||||
import { GenerateBillsDto, UpdateBillStatusDto } from './dto/bill.dto';
|
||||
import {
|
||||
BatchUpdateBillStatusDto,
|
||||
GenerateBillsDto,
|
||||
UpdateBillStatusDto,
|
||||
} from './dto/bill.dto';
|
||||
import { JwtAuthGuard } from '../auth/guards/jwt-auth.guard';
|
||||
import { OperationLogsService } from '../operation-logs/operation-logs.service';
|
||||
import { extractRequestInfo } from '../common/request-utils';
|
||||
@@ -88,47 +93,15 @@ export class BillsController {
|
||||
|
||||
@Get(':id')
|
||||
@RequirePermission('bill:view')
|
||||
findOne(@Param('id') id: string) {
|
||||
return this.service.findOne(+id);
|
||||
}
|
||||
|
||||
@Put(':id/status')
|
||||
@RequirePermission('bill:confirm')
|
||||
async updateStatus(
|
||||
@Param('id') id: string,
|
||||
@Body() dto: UpdateBillStatusDto,
|
||||
@Request() req: any,
|
||||
) {
|
||||
const { ipAddress, userAgent } = extractRequestInfo(req);
|
||||
const result = await this.service.updateStatus(+id, dto);
|
||||
await this.logService.log({
|
||||
userId: req.user?.id,
|
||||
username: req.user?.username,
|
||||
module: '账单管理',
|
||||
action: '确认账单',
|
||||
targetId: +id,
|
||||
targetType: 'bill',
|
||||
ipAddress,
|
||||
userAgent,
|
||||
});
|
||||
// Send bill_paid notification
|
||||
try {
|
||||
const student = await this.studentRepo.findOne({ where: { id: result.studentId } });
|
||||
if (student?.userId) {
|
||||
void this.notificationsService.create({
|
||||
recipientIds: [student.userId],
|
||||
type: NotificationType.BILL_PAID,
|
||||
title: '账单已确认',
|
||||
content: `账单 #${result.id} 已确认收款,金额: ¥${result.totalAmount}`,
|
||||
});
|
||||
}
|
||||
} catch (_) { /* don't block response */ }
|
||||
return result;
|
||||
findOne(@Param('id', ParseIntPipe) id: number) {
|
||||
return this.service.findOne(id);
|
||||
}
|
||||
|
||||
// Static routes must be declared before /:id/status, otherwise "batch" is
|
||||
// treated as an id and converted to NaN by the parameterized route.
|
||||
@Put('batch/status')
|
||||
@RequirePermission('bill:confirm')
|
||||
async batchUpdateStatus(@Body() body: { ids: number[]; status: string }, @Request() req: any) {
|
||||
async batchUpdateStatus(@Body() body: BatchUpdateBillStatusDto, @Request() req: any) {
|
||||
const { ipAddress, userAgent } = extractRequestInfo(req);
|
||||
const result = await this.service.batchUpdateStatus(body.ids, body.status);
|
||||
await this.logService.log({
|
||||
@@ -158,17 +131,51 @@ export class BillsController {
|
||||
return result;
|
||||
}
|
||||
|
||||
@Put(':id/status')
|
||||
@RequirePermission('bill:confirm')
|
||||
async updateStatus(
|
||||
@Param('id', ParseIntPipe) id: number,
|
||||
@Body() dto: UpdateBillStatusDto,
|
||||
@Request() req: any,
|
||||
) {
|
||||
const { ipAddress, userAgent } = extractRequestInfo(req);
|
||||
const result = await this.service.updateStatus(id, dto);
|
||||
await this.logService.log({
|
||||
userId: req.user?.id,
|
||||
username: req.user?.username,
|
||||
module: '账单管理',
|
||||
action: '确认账单',
|
||||
targetId: id,
|
||||
targetType: 'bill',
|
||||
ipAddress,
|
||||
userAgent,
|
||||
});
|
||||
// Send bill_paid notification
|
||||
try {
|
||||
const student = await this.studentRepo.findOne({ where: { id: result.studentId } });
|
||||
if (student?.userId) {
|
||||
void this.notificationsService.create({
|
||||
recipientIds: [student.userId],
|
||||
type: NotificationType.BILL_PAID,
|
||||
title: '账单已确认',
|
||||
content: `账单 #${result.id} 已确认收款,金额: ¥${result.totalAmount}`,
|
||||
});
|
||||
}
|
||||
} catch (_) { /* don't block response */ }
|
||||
return result;
|
||||
}
|
||||
|
||||
@Delete(':id')
|
||||
@RequirePermission('bill:delete')
|
||||
async remove(@Param('id') id: string, @Request() req: any) {
|
||||
async remove(@Param('id', ParseIntPipe) id: number, @Request() req: any) {
|
||||
const { ipAddress, userAgent } = extractRequestInfo(req);
|
||||
const result = await this.service.remove(+id);
|
||||
const result = await this.service.remove(id);
|
||||
await this.logService.log({
|
||||
userId: req.user?.id,
|
||||
username: req.user?.username,
|
||||
module: '账单管理',
|
||||
action: '删除账单',
|
||||
targetId: +id,
|
||||
targetId: id,
|
||||
targetType: 'bill',
|
||||
ipAddress,
|
||||
userAgent,
|
||||
@@ -226,18 +233,18 @@ export class BillsController {
|
||||
|
||||
@Get('export/pdf/:id')
|
||||
@RequirePermission('bill:export-pdf')
|
||||
async exportPdf(@Param('id') id: string, @Res() res: Response, @Req() req: any) {
|
||||
async exportPdf(@Param('id', ParseIntPipe) id: number, @Res() res: Response, @Req() req: any) {
|
||||
const { ipAddress, userAgent } = extractRequestInfo(req);
|
||||
await this.logService.log({
|
||||
userId: req?.user?.id,
|
||||
username: req?.user?.username,
|
||||
module: '账单管理',
|
||||
action: '导出账单',
|
||||
targetId: +id,
|
||||
targetId: id,
|
||||
targetType: 'bill',
|
||||
ipAddress,
|
||||
userAgent,
|
||||
});
|
||||
return this.exportService.exportStudentPdf(+id, res);
|
||||
return this.exportService.exportStudentPdf(id, res);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { IsString, IsOptional } from 'class-validator';
|
||||
import { ArrayNotEmpty, IsArray, IsIn, IsInt, IsString } from 'class-validator';
|
||||
|
||||
export class GenerateBillsDto {
|
||||
@IsString()
|
||||
@@ -9,6 +9,13 @@ export class GenerateBillsDto {
|
||||
}
|
||||
|
||||
export class UpdateBillStatusDto {
|
||||
@IsString()
|
||||
@IsIn(['draft', 'confirmed', 'paid'])
|
||||
status: 'draft' | 'confirmed' | 'paid';
|
||||
}
|
||||
|
||||
export class BatchUpdateBillStatusDto extends UpdateBillStatusDto {
|
||||
@IsArray()
|
||||
@ArrayNotEmpty()
|
||||
@IsInt({ each: true })
|
||||
ids: number[];
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user