Files
lotteryLaravel/e2e/tests/api/18.settlement-permissions.spec.ts
kang 3f29229499
Some checks failed
lotterLaravel CI / test (push) Has been cancelled
lotterLaravel E2E / e2e-api (push) Has been cancelled
fix: 部分收付累计释额并扩展结算 E2E 与 CI
账期收付改为按累计已付同步 credit_ledger,修复多笔 partial_paid 与坏账核销重复释额;新增 API E2E(占成、权限、部分收付/坏账)与 GitHub Actions e2e-api job。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-22 09:48:01 +08:00

152 lines
5.4 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* E2E结算收付权限 — 站点财务可收付/坏账;绑定代理不可坏账核销。
*/
import { test, expect } from '@playwright/test';
import {
adminCtxOf,
adminLoginWithAccount,
adminLoginViaBypass,
fetchOpenDrawNo,
openSettlementPeriod,
playerLoginViaBypass,
setupCreditPlayer,
setupSiteOperator,
} from './_helper';
import { runWalletDrawSettlement } from './helpers/draw-settlement';
const DEFAULT_PASS = process.env.E2E_PLAYER_PASSWORD ?? '12345678';
test('站点财务可 confirm + 收付;绑定代理不可坏账核销', async () => {
test.setTimeout(360_000);
const credit = await setupCreditPlayer({
credit_limit: 100_000,
username: `e2e_perm_${Date.now()}`,
});
const finance = await setupSiteOperator({
username: `e2e_fin_${Date.now()}`,
password: DEFAULT_PASS,
role_slug: 'site_finance',
});
const drawNo = await fetchOpenDrawNo();
const winNumber = `5${String(Date.now()).slice(-3)}`;
const superSession = await adminLoginViaBypass();
const superAdmin = await adminCtxOf(superSession.accessToken);
const periodId = await openSettlementPeriod(superAdmin, credit.admin_site_id);
const playerSession = await playerLoginViaBypass({
site_code: credit.site_code,
username: credit.username,
password: credit.password,
});
await runWalletDrawSettlement({
adminToken: superSession.accessToken,
playerToken: playerSession.access_token,
drawNo,
betNumber: winNumber,
betAmount: 10_000,
expectWalletIncrease: false,
});
const close = await superAdmin.post(`/api/v1/admin/settlement-periods/${periodId}/close`);
expect(close.ok()).toBeTruthy();
const bills = await superAdmin.get(
`/api/v1/admin/settlement-bills?settlement_period_id=${periodId}&size=20`,
);
const billsBody = (await bills.json()) as any;
const playerBill = billsBody.data.items.find(
(b: any) => b.bill_type === 'player' && Number(b.owner_id) === credit.player_id,
);
expect(playerBill).toBeTruthy();
const billId = Number(playerBill.id);
const unpaid = Number(playerBill.unpaid_amount);
expect(unpaid).toBeGreaterThan(0);
const financeSession = await adminLoginWithAccount(finance.username, finance.password);
const financeAdmin = await adminCtxOf(financeSession.accessToken);
const me = await financeAdmin.get('/api/v1/admin/auth/me');
expect(me.ok()).toBeTruthy();
const meBody = (await me.json()) as any;
expect(meBody.data.admin.account_kind).toBe('site_finance');
const confirm = await financeAdmin.post(`/api/v1/admin/settlement-bills/${billId}/confirm`);
expect(confirm.ok(), `site_finance confirm status=${confirm.status()}`).toBeTruthy();
expect((await confirm.json()).code).toBe(0);
const pay = await financeAdmin.post(`/api/v1/admin/settlement-bills/${billId}/payments`, {
data: { amount: unpaid, method: 'e2e_finance', remark: 'site finance payment' },
});
expect(pay.ok(), `site_finance payment status=${pay.status()}`).toBeTruthy();
expect((await pay.json()).data.bill.status).toBe('settled');
await financeAdmin.dispose();
const credit2 = await setupCreditPlayer({
credit_limit: 100_000,
username: `e2e_perm2_${Date.now()}`,
});
const periodId2 = await openSettlementPeriod(superAdmin, credit2.admin_site_id);
const drawNo2 = await fetchOpenDrawNo();
const player2 = await playerLoginViaBypass({
site_code: credit2.site_code,
username: credit2.username,
password: credit2.password,
});
await runWalletDrawSettlement({
adminToken: superSession.accessToken,
playerToken: player2.access_token,
drawNo: drawNo2,
betNumber: `4${String(Date.now()).slice(-3)}`,
betAmount: 10_000,
expectWalletIncrease: false,
});
const close2 = await superAdmin.post(`/api/v1/admin/settlement-periods/${periodId2}/close`);
expect(close2.ok()).toBeTruthy();
const bills2 = await superAdmin.get(
`/api/v1/admin/settlement-bills?settlement_period_id=${periodId2}&size=20`,
);
const bill2 = ((await bills2.json()) as any).data.items.find(
(b: any) => b.bill_type === 'player' && Number(b.owner_id) === credit2.player_id,
);
expect(bill2).toBeTruthy();
await superAdmin.post(`/api/v1/admin/settlement-bills/${bill2.id}/confirm`);
const agentSession = await adminLoginWithAccount('e2e_leaf_agent', DEFAULT_PASS);
const agentAdmin = await adminCtxOf(agentSession.accessToken);
const agentMe = (await (await agentAdmin.get('/api/v1/admin/auth/me')).json()) as any;
expect(agentMe.data.admin.account_kind).toBe('agent_operator');
const badDebt = await agentAdmin.post(
`/api/v1/admin/settlement-bills/${bill2.id}/bad-debt-write-off`,
{ data: { reason: 'e2e should deny' } },
);
expect([403, 404]).toContain(badDebt.status());
const financeBadDebt = await setupSiteOperator({
username: `e2e_fin_bd_${Date.now()}`,
password: DEFAULT_PASS,
role_slug: 'site_finance',
});
const finance2 = await adminLoginWithAccount(financeBadDebt.username, DEFAULT_PASS);
const finance2Ctx = await adminCtxOf(finance2.accessToken);
const writeOff = await finance2Ctx.post(
`/api/v1/admin/settlement-bills/${bill2.id}/bad-debt-write-off`,
{ data: { reason: 'e2e uncollectible' } },
);
expect(writeOff.ok(), `site_finance bad debt status=${writeOff.status()}`).toBeTruthy();
expect((await writeOff.json()).code).toBe(0);
await agentAdmin.dispose();
await finance2Ctx.dispose();
await superAdmin.dispose();
});