feat: add monthly card periods and apparatus lesson feedback
This commit is contained in:
@@ -84,6 +84,7 @@ const mockActiveMembership = {
|
||||
const mockDurationMembership = {
|
||||
...mockActiveMembership,
|
||||
id: 'mem-duration-001',
|
||||
expireDate: new Date('2100-01-01'),
|
||||
cardTypeId: mockDurationCardType.id,
|
||||
remainingTimes: null,
|
||||
cardType: mockDurationCardType,
|
||||
@@ -138,6 +139,7 @@ const mockStudioConfig = {
|
||||
|
||||
function buildTxMock(overrides: Record<string, unknown> = {}) {
|
||||
return {
|
||||
$queryRaw: jest.fn(),
|
||||
timeSlot: {
|
||||
findUnique: jest.fn(),
|
||||
update: jest.fn(),
|
||||
@@ -255,6 +257,54 @@ describe('BookingService', () => {
|
||||
|
||||
afterEach(() => jest.clearAllMocks())
|
||||
|
||||
describe('monthly period booking boundaries', () => {
|
||||
const planned = { ...mockLimitedDurationMembership, startDate:new Date('2099-12-30T00:00:00Z'),expireDate:new Date('2100-01-29T00:00:00Z'),status:MembershipStatus.SCHEDULED }
|
||||
it('lets a paid future period reserve only its own dates and keeps its quota separate',async()=>{
|
||||
const tx=buildTxMock()
|
||||
tx.timeSlot.findUnique.mockResolvedValue(mockOpenSlot)
|
||||
tx.booking.findUnique.mockResolvedValue(null)
|
||||
tx.membership.findUnique.mockResolvedValue(planned)
|
||||
tx.booking.create.mockResolvedValue(mockConfirmedBooking)
|
||||
;(prisma.$transaction as jest.Mock).mockImplementation(fn=>fn(tx))
|
||||
;(prisma.booking.findUnique as jest.Mock).mockResolvedValue({...mockConfirmedBooking,timeSlot:mockOpenSlot,membership:planned})
|
||||
;(prisma.user.findMany as jest.Mock).mockResolvedValue([])
|
||||
await service.createBooking(MOCK_USER_ID,{timeSlotId:MOCK_SLOT_ID,membershipId:planned.id})
|
||||
expect(tx.booking.create).toHaveBeenCalledWith(expect.objectContaining({data:expect.objectContaining({membershipId:planned.id})}))
|
||||
expect(tx.membership.update).not.toHaveBeenCalled()
|
||||
})
|
||||
it.each(['before','after'])('rejects a course %s the monthly period before writing a booking',async boundary=>{
|
||||
const tx=buildTxMock()
|
||||
const membership=boundary==='before'?{...planned,startDate:new Date('2100-01-01T00:00:00Z')}:{...planned,expireDate:new Date('2099-12-31T00:00:00Z')}
|
||||
tx.timeSlot.findUnique.mockResolvedValue(mockOpenSlot)
|
||||
tx.booking.findUnique.mockResolvedValue(null)
|
||||
tx.membership.findUnique.mockResolvedValue(membership)
|
||||
;(prisma.$transaction as jest.Mock).mockImplementation(fn=>fn(tx))
|
||||
await expect(service.createBooking(MOCK_USER_ID,{timeSlotId:MOCK_SLOT_ID,membershipId:membership.id})).rejects.toThrow('周期')
|
||||
expect(tx.booking.create).not.toHaveBeenCalled()
|
||||
})
|
||||
it('deducts a reserved future period without activating it ahead of time',async()=>{
|
||||
const tx=buildTxMock()
|
||||
tx.booking.findUnique.mockResolvedValue({...mockConfirmedBooking,status:BookingStatus.PENDING_CONFIRMATION,timeSlot:mockOpenSlot,membership:planned,membershipId:planned.id})
|
||||
tx.booking.update.mockResolvedValue(mockConfirmedBooking)
|
||||
;(prisma.$transaction as jest.Mock).mockImplementation(fn=>fn(tx))
|
||||
;(prisma.booking.findUnique as jest.Mock).mockResolvedValue({...mockConfirmedBooking,timeSlot:mockOpenSlot,membership:planned})
|
||||
;(prisma.user.findUnique as jest.Mock).mockResolvedValue(null)
|
||||
studioService.getInfo.mockResolvedValue(mockStudioConfig as never)
|
||||
await service.confirmBooking(MOCK_BOOKING_ID,MOCK_ADMIN_ID)
|
||||
expect(tx.membership.update).toHaveBeenCalledWith({where:{id:planned.id},data:{remainingTimes:4,status:MembershipStatus.SCHEDULED}})
|
||||
})
|
||||
it('rejects administrative arrangement outside the selected period',async()=>{
|
||||
const tx=buildTxMock()
|
||||
tx.timeSlot.findUnique.mockResolvedValue(mockOpenSlot)
|
||||
tx.user.findUnique.mockResolvedValue({id:MOCK_USER_ID})
|
||||
tx.booking.findUnique.mockResolvedValue(null)
|
||||
tx.membership.findUnique.mockResolvedValue({...planned,startDate:new Date('2100-01-01T00:00:00Z')})
|
||||
;(prisma.$transaction as jest.Mock).mockImplementation(fn=>fn(tx))
|
||||
await expect(service.adminArrangeBooking(MOCK_ADMIN_ID,{userId:MOCK_USER_ID,timeSlotId:MOCK_SLOT_ID,membershipId:planned.id})).rejects.toThrow('周期')
|
||||
expect(tx.timeSlot.updateMany).not.toHaveBeenCalled()
|
||||
})
|
||||
})
|
||||
|
||||
describe('confirmBooking', () => {
|
||||
it('sends booking confirmed subscription message after admin confirmation', async () => {
|
||||
const tx = buildTxMock({
|
||||
|
||||
Reference in New Issue
Block a user