feat: add Student-User association and activate all notification TODOs

This commit is contained in:
2026-07-05 23:42:22 +08:00
parent 9e6c136ef0
commit 9d9d4719b5
6 changed files with 116 additions and 10 deletions

View File

@@ -12,9 +12,13 @@ import {
Res,
Req,
} from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository, In } from 'typeorm';
import { BillsService } from './bills.service';
import { NotificationsService } from '../notifications/notifications.service';
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 { JwtAuthGuard } from '../auth/guards/jwt-auth.guard';
@@ -23,14 +27,14 @@ import { extractRequestInfo } from '../common/request-utils';
import { RequirePermission } from '../auth/decorators/permission.decorator';
import type { Response } from 'express';
@UseGuards(JwtAuthGuard)
@Controller('bills')
export class BillsController {
constructor(
private service: BillsService,
private exportService: BillsExportService,
private logService: OperationLogsService,
private readonly notificationsService: NotificationsService,
@InjectRepository(Student) private studentRepo: Repository<Student>,
@InjectRepository(Bill) private billRepo: Repository<Bill>,
) {}
@Post('generate')
@@ -47,7 +51,20 @@ export class BillsController {
ipAddress,
userAgent,
});
// TODO: Send notifications for bill_generated — studentId→userId mapping unavailable
// Send bill_generated notifications
try {
for (const bill of result.bills) {
const student = await this.studentRepo.findOne({ where: { id: bill.studentId } });
if (student?.userId) {
void this.notificationsService.create({
recipientIds: [student.userId],
type: NotificationType.BILL_GENERATED,
title: '新账单',
content: `您有一笔新账单,金额: ¥${bill.totalAmount}, 周期: ${dto.periodStart}~${dto.periodEnd}`,
});
}
}
} catch (_) { /* don't block response */ }
return result;
}
@@ -92,7 +109,18 @@ export class BillsController {
ipAddress,
userAgent,
});
// TODO: Send notification for bill_paid — bill.studentId→userId mapping unavailable
// 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;
}
@@ -110,7 +138,21 @@ export class BillsController {
ipAddress,
userAgent,
});
// TODO: Send notification for bill_paid (batch) — bill.studentId→userId mapping unavailable
// Send bill_paid notifications (batch)
try {
const bills = await this.billRepo.findBy({ id: In(body.ids) });
for (const bill of bills) {
const student = await this.studentRepo.findOne({ where: { id: bill.studentId } });
if (student?.userId) {
void this.notificationsService.create({
recipientIds: [student.userId],
type: NotificationType.BILL_PAID,
title: '账单已确认',
content: `账单 #${bill.id} 已确认收款,金额: ¥${bill.totalAmount}`,
});
}
}
} catch (_) { /* don't block response */ }
return result;
}

View File

@@ -8,6 +8,7 @@ import { PersonalExpense } from '../entities/personal-expense.entity';
import { Occupancy } from '../entities/occupancy.entity';
import { Room } from '../entities/room.entity';
import { Deposit } from '../entities/deposit.entity';
import { Student } from '../entities/student.entity';
import { BillsService } from './bills.service';
import { BillsExportService } from './bills-export.service';
import { BillsController } from './bills.controller';
@@ -22,6 +23,7 @@ import { BillsController } from './bills.controller';
Occupancy,
Room,
Deposit,
Student,
]),
NotificationsModule,
],