perf: 支持课程补录

This commit is contained in:
richarjiang
2026-09-08 15:08:29 +08:00
parent d1f193e13e
commit b4b3caac70
24 changed files with 1074 additions and 945 deletions

View File

@@ -53,6 +53,10 @@ const makeBooking = (
// ---------------------------------------------------------------------------
const mockPrisma = {
lessonSupplement: {
aggregate: jest.fn().mockResolvedValue({ _sum: { quantity: 0 } }),
groupBy: jest.fn().mockResolvedValue([]),
},
user: {
findUnique: jest.fn(),
findMany: jest.fn(),
@@ -374,6 +378,13 @@ describe('UserService', () => {
expect(result.totalBookings).toBe(2)
})
it('adds ten active historical classes only to lifetime total', async () => {
mockPrisma.booking.findMany.mockResolvedValue([makeBooking(dateInMonth(1), '09:00', '10:00')])
mockPrisma.lessonSupplement.aggregate.mockResolvedValueOnce({ _sum: { quantity: 10 } })
expect(await service.getStats('user-1')).toEqual({ totalBookings: 11, totalDays: 1, monthBookings: 1, monthDays: 1, monthHours: 1 })
expect(mockPrisma.lessonSupplement.aggregate).toHaveBeenCalledWith({ where: { userId: 'user-1', revokedAt: null }, _sum: { quantity: true } })
})
it('counts distinct dates for totalDays', async () => {
mockPrisma.booking.findMany.mockResolvedValue([
makeBooking(dateInMonth(1), '09:00', '10:00'),
@@ -436,6 +447,16 @@ describe('UserService', () => {
})
})
it('batch-adds supplements to member-list completed counts without inflating reservations', async () => {
mockPrisma.user.findMany.mockResolvedValue([makeUser({ memberships: [] })])
mockPrisma.user.count.mockResolvedValue(1)
mockPrisma.booking.groupBy.mockResolvedValue([{ userId: 'user-1', status: BookingStatus.COMPLETED, _count: { id: 3 } }])
mockPrisma.lessonSupplement.groupBy.mockResolvedValueOnce([{ userId: 'user-1', _sum: { quantity: 10 } }])
const result = await service.getMembers(1, 20)
expect(result.items[0]).toMatchObject({ totalBookings: 3, completedBookings: 13 })
expect(mockPrisma.lessonSupplement.groupBy).toHaveBeenCalledWith({ by: ['userId'], where: { userId: { in: ['user-1'] }, revokedAt: null }, _sum: { quantity: true } })
})
describe('getMemberDetail', () => {
const cardType = {
id: 'ct-1',
@@ -490,6 +511,7 @@ describe('UserService', () => {
},
])
mockPrisma.lessonSupplement.aggregate.mockResolvedValueOnce({ _sum: { quantity: 10 } })
const result = await service.getMemberDetail('user-1')
expect(result.user.userId).toBe('user-1')
@@ -498,7 +520,7 @@ describe('UserService', () => {
expect(result.memberships[0].cardType.name).toBe('10次卡')
expect(result.stats).toEqual({
totalBookings: 5,
completedBookings: 3,
completedBookings: 13,
cancelledBookings: 1,
noShowBookings: 1,
})