fix: 老师代约只允许已发布课表,去掉临时加开时段

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
richarjiang
2026-09-07 17:21:19 +08:00
parent f5c7b7eaac
commit 86ad9ee64f
5 changed files with 25 additions and 335 deletions

View File

@@ -1318,100 +1318,5 @@ describe('BookingService', () => {
)
expect(tx.booking.create).not.toHaveBeenCalled()
})
it('reuses an existing slot when arranging by date and time', async () => {
const tx = buildTxMock()
stubArrangeSuccess(tx)
await service.adminArrangeBooking(MOCK_ADMIN_ID, {
userId: MOCK_USER_ID,
membershipId: MOCK_MEMBERSHIP_ID,
date: '2099-12-31',
startTime: '09:00',
endTime: '10:00',
})
expect(tx.timeSlot.findUnique).toHaveBeenCalledWith(
expect.objectContaining({
where: {
date_startTime_endTime: {
date: new Date('2099-12-31T00:00:00.000Z'),
startTime: '09:00',
endTime: '10:00',
},
},
}),
)
expect(tx.timeSlot.create).not.toHaveBeenCalled()
expect(tx.booking.create).toHaveBeenCalled()
})
it('creates a manual slot when arranging a missing date and time', async () => {
const tx = buildTxMock()
const createdSlot = { ...mockOpenSlot, id: 'slot-manual-001', source: 'MANUAL' }
tx.timeSlot.findUnique
.mockResolvedValueOnce(null)
.mockResolvedValueOnce({ ...createdSlot, bookedCount: 1 })
tx.timeSlot.create.mockResolvedValue(createdSlot)
tx.user.findUnique.mockResolvedValue({ id: MOCK_USER_ID })
tx.booking.findUnique.mockResolvedValue(null)
tx.membership.findUnique.mockResolvedValue(mockActiveMembership)
tx.timeSlot.updateMany.mockResolvedValue({ count: 1 })
tx.booking.create.mockResolvedValue({
...mockConfirmedBooking,
timeSlotId: createdSlot.id,
status: BookingStatus.CONFIRMED,
})
tx.membership.update.mockResolvedValue({ ...mockActiveMembership, remainingTimes: 4 })
;(prisma.$transaction as jest.Mock).mockImplementation((fn) => fn(tx))
;(prisma.booking.findUnique as jest.Mock).mockResolvedValue({
...mockConfirmedBooking,
timeSlotId: createdSlot.id,
status: BookingStatus.CONFIRMED,
timeSlot: createdSlot,
membership: mockActiveMembership,
})
;(prisma.user.findUnique as jest.Mock).mockResolvedValue({ openid: 'openid-001' })
studioService.getInfo.mockResolvedValue({
...mockStudioConfig,
name: 'FocusCore Pilates',
})
subscriptionMessageService.sendBookingConfirmedMessage.mockResolvedValue(true)
await service.adminArrangeBooking(MOCK_ADMIN_ID, {
userId: MOCK_USER_ID,
membershipId: MOCK_MEMBERSHIP_ID,
date: '2099-12-31',
startTime: '09:00',
endTime: '10:00',
})
expect(tx.timeSlot.create).toHaveBeenCalledWith(
expect.objectContaining({
data: expect.objectContaining({
startTime: '09:00',
endTime: '10:00',
source: 'MANUAL',
}),
}),
)
})
it('rejects custom slots whose end time is not after start time', async () => {
const tx = buildTxMock()
;(prisma.$transaction as jest.Mock).mockImplementation((fn) => fn(tx))
await expect(
service.adminArrangeBooking(MOCK_ADMIN_ID, {
userId: MOCK_USER_ID,
membershipId: MOCK_MEMBERSHIP_ID,
date: '2099-12-31',
startTime: '23:00',
endTime: '00:00',
}),
).rejects.toThrow(BadRequestException)
expect(tx.timeSlot.findUnique).not.toHaveBeenCalled()
expect(tx.timeSlot.create).not.toHaveBeenCalled()
})
})
})