feat(admin+api): 代理停用默认、结算加固与冒烟配置探针

- 代理层级默认授信比例与停用冻结/禁登全局默认

- 结算预览去重、比分校验、串关当场判负与市场类型校验

- 站内信 Banner/公告自动通知开关;开发环境动态 API 端口

- 扩充 RBAC/结算/认证/返现单元测试与 agent skills
This commit is contained in:
2026-06-23 11:08:41 +08:00
parent fa06fee64c
commit ce84226219
47 changed files with 9284 additions and 118 deletions

View File

@@ -32,12 +32,30 @@ describe('AgentsService', () => {
},
};
const prisma = createPrismaMock(tx);
const prismaBase = {
...tx,
agentProfile: {
...tx.agentProfile,
update: jest.fn(),
},
user: {
...tx.user,
updateMany: jest.fn(),
},
};
const prisma = createPrismaMock(prismaBase) as typeof prismaBase & { $transaction: jest.Mock };
prisma.$transaction.mockImplementation(async (arg: unknown) => {
if (Array.isArray(arg)) {
return Promise.all(arg);
}
return (arg as (client: typeof tx) => Promise<unknown>)(tx);
});
const auth = {
hashPassword: jest.fn(),
};
const systemConfig = {
getAgentHierarchySettings: jest.fn(),
getAgentSuspendSettings: jest.fn(),
};
const network = {};
const credit = {
@@ -56,13 +74,20 @@ describe('AgentsService', () => {
credit as never,
);
systemConfig.getAgentHierarchySettings.mockResolvedValue({ maxAgentLevel: 3 });
systemConfig.getAgentHierarchySettings.mockResolvedValue({
maxAgentLevel: 3,
defaultSubAgentCreditRatio: 50,
});
systemConfig.getAgentSuspendSettings.mockResolvedValue({
suspendFreezeDirectPlayers: true,
suspendBlockPlayerLogin: true,
});
auth.hashPassword.mockResolvedValue('hashed-password');
tx.agentProfile.findUnique.mockResolvedValue({
prisma.agentProfile.findUnique.mockResolvedValue({
userId: parentAgentId,
level: 1,
creditLimit: new Decimal(1000),
usedCredit: new Decimal(0),
creditLimit: new Decimal(10000),
usedCredit: new Decimal(2000),
cashbackRate: new Decimal(10),
maxSingleDeposit: null,
maxDailyDeposit: null,
@@ -91,10 +116,41 @@ describe('AgentsService', () => {
password: 'secret',
level: 2,
parentAgentId,
creditLimit: 300,
});
expect(tx.agentProfile.create).toHaveBeenCalledWith(
expect.objectContaining({
data: expect.objectContaining({ creditLimit: 4000 }),
}),
);
expect(credit.recalculateUsedCredit).toHaveBeenCalledWith(parentAgentId);
expect(credit.recalculateUsedCredit).not.toHaveBeenCalledWith(createdAgentId);
});
it('applies global suspend defaults when suspending without explicit flags', async () => {
jest.spyOn(service, 'getAgentAdminDetail').mockResolvedValue({ userId: '10' } as never);
prisma.agentProfile.findUnique.mockResolvedValue({
userId: 10n,
user: { username: 'agent-a', locale: 'zh-CN' },
parentAgentId: null,
});
prisma.user.updateMany.mockResolvedValue({ count: 2 });
prisma.agentProfile.update.mockResolvedValue({});
prisma.user.update.mockResolvedValue({});
await service.updateAgentAdmin(10n, { status: 'SUSPENDED' });
expect(systemConfig.getAgentSuspendSettings).toHaveBeenCalled();
expect(prisma.user.updateMany).toHaveBeenCalledWith(
expect.objectContaining({
where: expect.objectContaining({ parentId: 10n, userType: 'PLAYER' }),
data: { status: 'SUSPENDED' },
}),
);
expect(prisma.agentProfile.update).toHaveBeenCalledWith(
expect.objectContaining({
data: expect.objectContaining({ blockDirectPlayerLogin: true }),
}),
);
});
});