Introduce admin smoke-test suite with API probes, agent credit transaction history, and player cashback records; fix SmokeTestModule DI and polish admin/player UI assets. Co-authored-by: Cursor <cursoragent@cursor.com>
216 lines
6.3 KiB
TypeScript
216 lines
6.3 KiB
TypeScript
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<BetFlowFixtureIds> {
|
|
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<void> {
|
|
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 } });
|
|
}
|