feat: 优化微信订阅消息体系并新增约课取消通知与开课前1小时提醒

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
richarjiang
2026-09-10 16:20:13 +08:00
parent d32f592e54
commit 3e049d2c1d
26 changed files with 1268 additions and 44 deletions

View File

@@ -170,7 +170,12 @@ describe('BookingService', () => {
let service: BookingService
let prisma: jest.Mocked<PrismaService>
let studioService: jest.Mocked<StudioService>
let subscriptionMessageService: { sendBookingConfirmedMessage: jest.Mock; sendAdminBookingCreatedMessage: jest.Mock }
let subscriptionMessageService: {
sendBookingConfirmedMessage: jest.Mock
sendAdminBookingCreatedMessage: jest.Mock
sendBookingCancelledMessage: jest.Mock
sendClassReminderMessage: jest.Mock
}
let inviteService: { recordQualifiedTrialBooking: jest.Mock }
beforeEach(async () => {
@@ -223,6 +228,8 @@ describe('BookingService', () => {
useValue: {
sendBookingConfirmedMessage: jest.fn(),
sendAdminBookingCreatedMessage: jest.fn(),
sendBookingCancelledMessage: jest.fn(),
sendClassReminderMessage: jest.fn(),
},
},
{
@@ -1083,6 +1090,35 @@ describe('BookingService', () => {
}),
)
})
it('triggers sendBookingCancelledMessage when a booking is cancelled', async () => {
const futureDate = new Date(Date.now() + 86400000 * 2)
const futureSlot = { ...mockOpenSlot, date: futureDate, startTime: '14:00', endTime: '15:00' }
const ownBooking = {
...mockConfirmedBooking,
userId: MOCK_USER_ID,
timeSlot: futureSlot,
membership: mockActiveMembership,
}
;(prisma.booking.findUnique as jest.Mock).mockResolvedValue(ownBooking)
;(prisma.user.findUnique as jest.Mock).mockResolvedValue({ id: MOCK_USER_ID, openid: 'test-user-openid' } as any)
const tx = buildTxMock()
tx.booking.update.mockResolvedValue({ ...ownBooking, status: BookingStatus.CANCELLED, cancelledAt: new Date() })
tx.timeSlot.update.mockResolvedValue({ ...futureSlot, bookedCount: 0 })
tx.membership.update.mockResolvedValue({ ...mockActiveMembership, remainingTimes: 6 })
;(prisma.$transaction as jest.Mock).mockImplementation((fn) => fn(tx))
await service.cancelBooking(MEMBER_ACTOR, MOCK_BOOKING_ID)
expect(subscriptionMessageService.sendBookingCancelledMessage).toHaveBeenCalledWith(
expect.objectContaining({
openid: 'test-user-openid',
userId: MOCK_USER_ID,
bookingId: MOCK_BOOKING_ID,
courseName: 'Test Studio',
}),
)
})
})
// ─── getMyBookings ────────────────────────────────────────────────────────