import { Decimal } from '@prisma/client/runtime/library'; import type { PrismaService } from '../../../shared/prisma/prisma.service'; import type { WalletService } from '../../ledger/wallet.service'; export interface BetFlowFixtureIds { runId: string; operatorId: bigint; playerId: bigint; agentId?: bigint; matchId: bigint; marketId: bigint; homeSelectionId: bigint; homeOddsVersion: bigint; drawSelectionId: bigint; drawOddsVersion: bigint; awaySelectionId: bigint; awayOddsVersion: bigint; leagueId: bigint; homeTeamId: bigint; awayTeamId: bigint; } export async function createBetFlowFixture( prisma: PrismaService, wallet: WalletService, opts?: { initialBalance?: number; withAgent?: boolean }, ): Promise { const runId = `${Date.now()}_${Math.random().toString(36).slice(2, 8)}`; const operator = await prisma.user.create({ data: { username: `smoke_op_${runId}`, userType: 'ADMIN', auth: { create: { passwordHash: 'smoke-test' } }, }, }); const league = await prisma.league.create({ data: { code: `SMK_L_${runId}`, sportType: 'FOOTBALL', }, }); const homeTeam = await prisma.team.create({ data: { code: `SMK_H_${runId}`, sportType: 'FOOTBALL' }, }); const awayTeam = await prisma.team.create({ data: { code: `SMK_A_${runId}`, sportType: 'FOOTBALL' }, }); const startTime = new Date(Date.now() + 48 * 60 * 60 * 1000); const match = await prisma.match.create({ data: { sportType: 'FOOTBALL', leagueId: league.id, homeTeamId: homeTeam.id, awayTeamId: awayTeam.id, startTime, status: 'PUBLISHED', publishTime: new Date(), }, }); const market = await prisma.market.create({ data: { matchId: match.id, marketType: 'FT_1X2', period: 'FT', status: 'OPEN', selections: { create: [ { selectionCode: 'HOME', selectionName: 'Home', odds: new Decimal('2.00'), oddsVersion: BigInt(1), status: 'OPEN', sortOrder: 0, }, { selectionCode: 'DRAW', selectionName: 'Draw', odds: new Decimal('3.00'), oddsVersion: BigInt(1), status: 'OPEN', sortOrder: 1, }, { selectionCode: 'AWAY', selectionName: 'Away', odds: new Decimal('4.00'), oddsVersion: BigInt(1), status: 'OPEN', sortOrder: 2, }, ], }, }, include: { selections: true }, }); let agentId: bigint | undefined; if (opts?.withAgent) { const agent = await prisma.user.create({ data: { username: `smoke_ag_${runId}`, userType: 'AGENT', auth: { create: { passwordHash: 'smoke-test' } }, agentProfile: { create: { level: 1, creditLimit: new Decimal(100000) }, }, }, }); await prisma.agentClosure.create({ data: { ancestorId: agent.id, descendantId: agent.id, depth: 0 }, }); agentId = agent.id; } const player = await prisma.user.create({ data: { username: `smoke_pl_${runId}`, userType: 'PLAYER', parentId: agentId, auth: { create: { passwordHash: 'smoke-test' } }, wallet: { create: { currency: 'USD' } }, }, }); const balance = opts?.initialBalance ?? 1000; if (balance > 0) { await wallet.deposit(player.id, balance, operator.id, 'smoke test seed'); } const home = market.selections.find((s) => s.selectionCode === 'HOME')!; const draw = market.selections.find((s) => s.selectionCode === 'DRAW')!; const away = market.selections.find((s) => s.selectionCode === 'AWAY')!; return { runId, operatorId: operator.id, playerId: player.id, agentId, matchId: match.id, marketId: market.id, homeSelectionId: home.id, homeOddsVersion: home.oddsVersion, drawSelectionId: draw.id, drawOddsVersion: draw.oddsVersion, awaySelectionId: away.id, awayOddsVersion: away.oddsVersion, leagueId: league.id, homeTeamId: homeTeam.id, awayTeamId: awayTeam.id, }; } export async function teardownBetFlowFixture( prisma: PrismaService, fx: BetFlowFixtureIds, ): Promise { const bets = await prisma.bet.findMany({ where: { userId: fx.playerId }, select: { id: true }, }); const betIds = bets.map((b) => b.id); const batches = await prisma.settlementBatch.findMany({ where: { matchId: fx.matchId }, select: { id: true }, }); const batchIds = batches.map((b) => b.id); if (batchIds.length) { await prisma.settlementItem.deleteMany({ where: { batchId: { in: batchIds } } }); await prisma.settlementBatch.deleteMany({ where: { id: { in: batchIds } } }); } if (betIds.length) { await prisma.betSelection.deleteMany({ where: { betId: { in: betIds } } }); await prisma.bet.deleteMany({ where: { id: { in: betIds } } }); } await prisma.walletTransaction.deleteMany({ where: { userId: fx.playerId } }); await prisma.wallet.deleteMany({ where: { userId: fx.playerId } }); await prisma.matchScore.deleteMany({ where: { matchId: fx.matchId } }); const markets = await prisma.market.findMany({ where: { matchId: fx.matchId }, select: { id: true }, }); const marketIds = markets.map((m) => m.id); if (marketIds.length) { await prisma.marketSelection.deleteMany({ where: { marketId: { in: marketIds } } }); await prisma.market.deleteMany({ where: { id: { in: marketIds } } }); } await prisma.match.deleteMany({ where: { id: fx.matchId } }); if (fx.agentId) { await prisma.agentClosure.deleteMany({ where: { OR: [{ ancestorId: fx.agentId }, { descendantId: fx.agentId }] }, }); await prisma.agentProfile.deleteMany({ where: { userId: fx.agentId } }); await prisma.userAuth.deleteMany({ where: { userId: fx.agentId } }); await prisma.user.deleteMany({ where: { id: fx.agentId } }); } await prisma.userAuth.deleteMany({ where: { userId: { in: [fx.playerId, fx.operatorId] } }, }); await prisma.user.deleteMany({ where: { id: { in: [fx.playerId, fx.operatorId] } } }); await prisma.team.deleteMany({ where: { id: { in: [fx.homeTeamId, fx.awayTeamId] } } }); await prisma.league.deleteMany({ where: { id: fx.leagueId } }); }