fix(server): 修复排课发布唯一约束冲突并更正默认时段模板
发布时按日期+起止时间匹配已有时段,避免幽灵预览重复 create;默认课表改为上午整点与下午 13:30 起每小时至 21:30。 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -7,6 +7,7 @@ import {
|
||||
TimeSlotSource,
|
||||
BookingStatus,
|
||||
DEFAULT_SLOT_CAPACITY,
|
||||
getDefaultTimeSlots,
|
||||
} from '@mp-pilates/shared'
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
@@ -508,6 +509,102 @@ describe('TimeSlotService', () => {
|
||||
expect(createData.capacity).toBe(4)
|
||||
})
|
||||
|
||||
it('updates materialized template rows when ghost preview is published without ids', async () => {
|
||||
const defaultSlots = getDefaultTimeSlots()
|
||||
const materialized = defaultSlots.map((slot, index) =>
|
||||
makeSlot({
|
||||
id: `slot-${index}`,
|
||||
startTime: slot.startTime,
|
||||
endTime: slot.endTime,
|
||||
source: TimeSlotSource.TEMPLATE,
|
||||
}),
|
||||
)
|
||||
mockPrisma.timeSlot.findMany
|
||||
.mockResolvedValueOnce([])
|
||||
.mockResolvedValueOnce(materialized)
|
||||
.mockResolvedValueOnce(materialized)
|
||||
mockPrisma.timeSlot.createMany.mockResolvedValueOnce({ count: defaultSlots.length })
|
||||
mockPrisma.timeSlot.update.mockImplementation(async (args: { where: { id: string } }) => {
|
||||
const row = materialized.find((s) => s.id === args.where.id)!
|
||||
return { ...row }
|
||||
})
|
||||
|
||||
await service.publishDaySlots({
|
||||
date,
|
||||
slots: defaultSlots.map((slot) => ({
|
||||
startTime: slot.startTime,
|
||||
endTime: slot.endTime,
|
||||
capacity: DEFAULT_SLOT_CAPACITY,
|
||||
})),
|
||||
})
|
||||
|
||||
expect(mockPrisma.timeSlot.createMany).toHaveBeenCalledTimes(1)
|
||||
expect(mockPrisma.timeSlot.create).not.toHaveBeenCalled()
|
||||
expect(mockPrisma.timeSlot.update).toHaveBeenCalledTimes(defaultSlots.length)
|
||||
})
|
||||
|
||||
it('reopens an existing row by time when admin re-adds a slot without existingSlotId', async () => {
|
||||
const existing = [
|
||||
makeSlot({
|
||||
id: 'slot-open',
|
||||
startTime: '09:30',
|
||||
endTime: '10:30',
|
||||
status: TimeSlotStatus.OPEN,
|
||||
}),
|
||||
]
|
||||
mockPrisma.timeSlot.findMany
|
||||
.mockResolvedValueOnce(existing)
|
||||
.mockResolvedValueOnce(existing)
|
||||
mockPrisma.timeSlot.update.mockResolvedValueOnce({
|
||||
...existing[0],
|
||||
status: TimeSlotStatus.OPEN,
|
||||
source: TimeSlotSource.MANUAL,
|
||||
capacity: 3,
|
||||
})
|
||||
|
||||
await service.publishDaySlots({
|
||||
date,
|
||||
slots: [{ startTime: '09:30', endTime: '10:30', capacity: 3 }],
|
||||
})
|
||||
|
||||
expect(mockPrisma.timeSlot.create).not.toHaveBeenCalled()
|
||||
const updateData = (mockPrisma.timeSlot.update.mock.calls[0][0] as {
|
||||
data: { status: string; source: string; capacity: number }
|
||||
}).data
|
||||
expect(updateData.status).toBe(TimeSlotStatus.OPEN)
|
||||
expect(updateData.source).toBe(TimeSlotSource.MANUAL)
|
||||
expect(updateData.capacity).toBe(3)
|
||||
})
|
||||
|
||||
it('reopens a CLOSED row when admin publishes the same time window as a new slot', async () => {
|
||||
const existing = [
|
||||
makeSlot({
|
||||
id: 'slot-closed',
|
||||
startTime: '11:00',
|
||||
endTime: '12:00',
|
||||
status: TimeSlotStatus.CLOSED,
|
||||
}),
|
||||
]
|
||||
mockPrisma.timeSlot.findMany
|
||||
.mockResolvedValueOnce(existing)
|
||||
.mockResolvedValueOnce(existing)
|
||||
mockPrisma.timeSlot.update.mockResolvedValueOnce({
|
||||
...existing[0],
|
||||
status: TimeSlotStatus.OPEN,
|
||||
})
|
||||
|
||||
await service.publishDaySlots({
|
||||
date,
|
||||
slots: [{ startTime: '11:00', endTime: '12:00', capacity: 2 }],
|
||||
})
|
||||
|
||||
expect(mockPrisma.timeSlot.create).not.toHaveBeenCalled()
|
||||
const updateData = (mockPrisma.timeSlot.update.mock.calls[0][0] as {
|
||||
data: { status: string }
|
||||
}).data
|
||||
expect(updateData.status).toBe(TimeSlotStatus.OPEN)
|
||||
})
|
||||
|
||||
it('returns the final state of the day ordered by startTime', async () => {
|
||||
const finalState = [
|
||||
makeSlot({ id: 'a', startTime: '09:00', endTime: '10:00' }),
|
||||
|
||||
Reference in New Issue
Block a user