feat: 支持管理员消息推送
This commit is contained in:
@@ -5,7 +5,7 @@ import {
|
||||
ForbiddenException,
|
||||
NotFoundException,
|
||||
} from '@nestjs/common'
|
||||
import { BookingStatus, CardTypeCategory, MembershipStatus, TimeSlotStatus } from '@mp-pilates/shared'
|
||||
import { BookingStatus, CardTypeCategory, MembershipStatus, TimeSlotStatus, UserRole } from '@mp-pilates/shared'
|
||||
import { BookingService } from '../booking.service'
|
||||
import { PrismaService } from '../../prisma/prisma.service'
|
||||
import { MembershipService } from '../../membership/membership.service'
|
||||
@@ -152,7 +152,7 @@ describe('BookingService', () => {
|
||||
let service: BookingService
|
||||
let prisma: jest.Mocked<PrismaService>
|
||||
let studioService: jest.Mocked<StudioService>
|
||||
let subscriptionMessageService: { sendBookingConfirmedMessage: jest.Mock }
|
||||
let subscriptionMessageService: { sendBookingConfirmedMessage: jest.Mock; sendAdminBookingCreatedMessage: jest.Mock }
|
||||
|
||||
beforeEach(async () => {
|
||||
const module: TestingModule = await Test.createTestingModule({
|
||||
@@ -179,6 +179,7 @@ describe('BookingService', () => {
|
||||
},
|
||||
user: {
|
||||
findUnique: jest.fn(),
|
||||
findMany: jest.fn(),
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -200,6 +201,7 @@ describe('BookingService', () => {
|
||||
provide: SubscriptionMessageService,
|
||||
useValue: {
|
||||
sendBookingConfirmedMessage: jest.fn(),
|
||||
sendAdminBookingCreatedMessage: jest.fn(),
|
||||
},
|
||||
},
|
||||
],
|
||||
@@ -284,6 +286,7 @@ describe('BookingService', () => {
|
||||
timeSlot: mockOpenSlot,
|
||||
membership: mockActiveMembership,
|
||||
})
|
||||
;(prisma.user.findMany as jest.Mock).mockResolvedValue([])
|
||||
|
||||
const result = await service.createBooking(MOCK_USER_ID, dto)
|
||||
|
||||
@@ -323,6 +326,7 @@ describe('BookingService', () => {
|
||||
timeSlot: nearFullSlot,
|
||||
membership: mockActiveMembership,
|
||||
})
|
||||
;(prisma.user.findMany as jest.Mock).mockResolvedValue([])
|
||||
|
||||
await service.createBooking(MOCK_USER_ID, dto)
|
||||
|
||||
@@ -353,6 +357,7 @@ describe('BookingService', () => {
|
||||
timeSlot: mockOpenSlot,
|
||||
membership: mockDurationMembership,
|
||||
})
|
||||
;(prisma.user.findMany as jest.Mock).mockResolvedValue([])
|
||||
|
||||
await service.createBooking(MOCK_USER_ID, durationDto)
|
||||
|
||||
@@ -379,12 +384,61 @@ describe('BookingService', () => {
|
||||
timeSlot: mockOpenSlot,
|
||||
membership: mockMembershipNoTimes,
|
||||
})
|
||||
;(prisma.user.findMany as jest.Mock).mockResolvedValue([])
|
||||
|
||||
await service.createBooking(MOCK_USER_ID, dto)
|
||||
|
||||
expect(tx.membership.update).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('sends admin booking created subscription message to admins with remaining count', async () => {
|
||||
const tx = buildTxMock()
|
||||
tx.timeSlot.findUnique.mockResolvedValue(mockOpenSlot)
|
||||
tx.booking.findFirst.mockResolvedValue(null)
|
||||
tx.membership.findUnique.mockResolvedValue(mockActiveMembership)
|
||||
tx.booking.create.mockResolvedValue({
|
||||
...mockConfirmedBooking,
|
||||
status: BookingStatus.PENDING_CONFIRMATION,
|
||||
})
|
||||
|
||||
;(prisma.$transaction as jest.Mock).mockImplementation((fn) => fn(tx))
|
||||
;(prisma.booking.findUnique as jest.Mock).mockResolvedValue({
|
||||
...mockConfirmedBooking,
|
||||
status: BookingStatus.PENDING_CONFIRMATION,
|
||||
timeSlot: mockOpenSlot,
|
||||
membership: mockActiveMembership,
|
||||
})
|
||||
;(prisma.user.findMany as jest.Mock).mockResolvedValue([
|
||||
{ openid: 'admin-openid-1' },
|
||||
])
|
||||
;(prisma.user.findUnique as jest.Mock).mockResolvedValue({ nickname: 'Alice', phone: '13800000000' })
|
||||
studioService.getInfo.mockResolvedValue({
|
||||
...mockStudioConfig,
|
||||
name: 'FocusCore Pilates',
|
||||
})
|
||||
subscriptionMessageService.sendAdminBookingCreatedMessage.mockResolvedValue(true)
|
||||
|
||||
await service.createBooking(MOCK_USER_ID, dto)
|
||||
|
||||
expect(prisma.user.findMany).toHaveBeenCalledWith({
|
||||
where: {
|
||||
role: UserRole.ADMIN,
|
||||
adminBookingSubscriptionCount: { gt: 0 },
|
||||
},
|
||||
select: {
|
||||
openid: true,
|
||||
},
|
||||
})
|
||||
expect(subscriptionMessageService.sendAdminBookingCreatedMessage).toHaveBeenCalledWith({
|
||||
openid: 'admin-openid-1',
|
||||
bookingId: MOCK_BOOKING_ID,
|
||||
bookingContent: 'Alice已预约',
|
||||
bookingTime: '2099-12-31 09:00',
|
||||
courseName: 'FocusCore Pilates',
|
||||
bookingPeriod: '2099-12-31 09:00~10:00',
|
||||
})
|
||||
})
|
||||
|
||||
it('throws BadRequestException when slot is FULL', async () => {
|
||||
const fullDto = { timeSlotId: mockFullSlot.id, membershipId: MOCK_MEMBERSHIP_ID }
|
||||
|
||||
|
||||
Reference in New Issue
Block a user