feat: 支持会员卡合同在线签署

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
richarjiang
2026-10-28 12:24:22 +08:00
parent c04a9db627
commit ecea65f596
46 changed files with 4313 additions and 232 deletions

View File

@@ -161,6 +161,9 @@ function buildTxMock(overrides: Record<string, unknown> = {}) {
user: {
findUnique: jest.fn(),
},
membershipContract: {
findFirst: jest.fn().mockResolvedValue(null),
},
bookingStatusHistory: {
create: jest.fn(),
},
@@ -492,6 +495,21 @@ describe('BookingService', () => {
describe('createBooking', () => {
const dto = { timeSlotId: MOCK_SLOT_ID, membershipId: MOCK_MEMBERSHIP_ID }
it('blocks booking until the purchase contract is signed', async () => {
const tx = buildTxMock()
tx.timeSlot.findUnique.mockResolvedValue(mockOpenSlot)
tx.booking.findUnique.mockResolvedValue(null)
tx.membership.findUnique.mockResolvedValue(mockActiveMembership)
tx.membershipContract.findFirst.mockResolvedValue({ id: 'contract-1' })
;(prisma.$transaction as jest.Mock).mockImplementation((fn) => fn(tx))
await expect(service.createBooking(MOCK_USER_ID, dto)).rejects.toThrow('请先签署会员卡合同')
expect(tx.membershipContract.findFirst).toHaveBeenCalledWith(expect.objectContaining({
where: { membershipId: mockActiveMembership.id, status: 'PENDING_SIGN', requireBeforeBooking: true },
}))
expect(tx.booking.create).not.toHaveBeenCalled()
})
it('creates booking in pending confirmation status', async () => {
const tx = buildTxMock()
tx.timeSlot.findUnique.mockResolvedValue(mockOpenSlot)