新增代理管理器与二级代理体系,完善信用额度/上下分上下文与冻结策略;代理端玩家与子代理管理增强;玩家端新增钱包详情页与交易筛选优化。 Co-authored-by: Cursor <cursoragent@cursor.com>
125 lines
3.7 KiB
TypeScript
125 lines
3.7 KiB
TypeScript
import {
|
||
settleSelection,
|
||
calculatePayout,
|
||
isQuarterHandicapOrTotal,
|
||
} from './domains/settlement/domain/settlement-calculator';
|
||
|
||
/**
|
||
* Agent credit & wallet integration scenarios (A001-A007)
|
||
* These tests validate business rules without DB dependency.
|
||
*/
|
||
describe('Agent Credit Rules', () => {
|
||
it('A001: deposit increases player balance and reduces agent available credit', () => {
|
||
const creditLimit = 10000;
|
||
const usedCredit = 1000;
|
||
const depositAmount = 500;
|
||
const newUsed = usedCredit + depositAmount;
|
||
expect(creditLimit - newUsed).toBe(8500);
|
||
});
|
||
|
||
it('A002: bet freeze does not change total balance or agent credit', () => {
|
||
const available = 1000;
|
||
const frozen = 0;
|
||
const stake = 100;
|
||
const totalBefore = available + frozen;
|
||
const totalAfter = (available - stake) + (frozen + stake);
|
||
expect(totalAfter).toBe(totalBefore);
|
||
});
|
||
|
||
it('A003: player lose releases agent credit', () => {
|
||
const usedBefore = 1000;
|
||
const stake = 100;
|
||
const usedAfter = usedBefore - stake;
|
||
expect(usedAfter).toBe(900);
|
||
});
|
||
|
||
it('A004: player win increases agent credit usage', () => {
|
||
const usedBefore = 1000;
|
||
const payout = 185;
|
||
const stake = 100;
|
||
const netGain = payout - stake;
|
||
const usedAfter = usedBefore + netGain;
|
||
expect(usedAfter).toBe(1085);
|
||
});
|
||
|
||
it('A005: negative credit blocks further deposit', () => {
|
||
const creditLimit = 1000;
|
||
const usedCredit = 1200;
|
||
const available = creditLimit - usedCredit;
|
||
expect(available).toBeLessThan(0);
|
||
const canDeposit = available > 0;
|
||
expect(canDeposit).toBe(false);
|
||
});
|
||
|
||
it('A006: level 1 allocating credit to level 2 reduces available', () => {
|
||
const available = 10000;
|
||
const allocate = 3000;
|
||
expect(available - allocate).toBe(7000);
|
||
});
|
||
|
||
it('A007: non-direct player deposit should be rejected', () => {
|
||
const agentId = BigInt(1);
|
||
const playerParentId = BigInt(2);
|
||
const canDeposit = agentId === playerParentId;
|
||
expect(canDeposit).toBe(false);
|
||
});
|
||
|
||
it('A008: admin deposit cannot exceed parent agent available credit', () => {
|
||
const creditLimit = 5000;
|
||
const usedCredit = 4800;
|
||
const depositAmount = 300;
|
||
const available = creditLimit - usedCredit;
|
||
expect(depositAmount).toBeGreaterThan(available);
|
||
const allowed = depositAmount <= available;
|
||
expect(allowed).toBe(false);
|
||
});
|
||
});
|
||
|
||
describe('Bet Validation Rules (B001-B010)', () => {
|
||
it('B003: odds version mismatch should reject', () => {
|
||
const submitted = BigInt(1);
|
||
const current = BigInt(2);
|
||
expect(submitted === current).toBe(false);
|
||
});
|
||
|
||
it('B007: same match legs allowed in parlay (2–5 legs)', () => {
|
||
const legs = [
|
||
{ matchId: '1', selectionId: 'a' },
|
||
{ matchId: '1', selectionId: 'b' },
|
||
];
|
||
expect(legs.length).toBeGreaterThanOrEqual(2);
|
||
expect(legs.length).toBeLessThanOrEqual(5);
|
||
});
|
||
|
||
it('B008: quarter line in parlay rejected', () => {
|
||
expect(isQuarterHandicapOrTotal(-0.25)).toBe(true);
|
||
expect(isQuarterHandicapOrTotal(-0.5)).toBe(false);
|
||
});
|
||
|
||
it('B009: more than 5 legs rejected', () => {
|
||
const legs = 6;
|
||
expect(legs > 5).toBe(true);
|
||
});
|
||
});
|
||
|
||
describe('Settlement payout accuracy', () => {
|
||
it('half win payout formula', () => {
|
||
const payout = calculatePayout(100, 1.85, 'HALF_WIN');
|
||
expect(payout.toNumber()).toBe(142.5);
|
||
});
|
||
|
||
it('half lose payout formula', () => {
|
||
const payout = calculatePayout(100, 1.85, 'HALF_LOSE');
|
||
expect(payout.toNumber()).toBe(50);
|
||
});
|
||
|
||
it('S004: 0-0 odd/even is even', () => {
|
||
const result = settleSelection({
|
||
marketType: 'FT_ODD_EVEN',
|
||
selectionCode: 'EVEN',
|
||
score: { htHome: 0, htAway: 0, ftHome: 0, ftAway: 0 },
|
||
});
|
||
expect(result).toBe('WIN');
|
||
});
|
||
});
|