feat: 增强后台设置校验、代理权限控制与财务审计能力
This commit is contained in:
185
tests/Feature/FinancialChainAuditCommandTest.php
Normal file
185
tests/Feature/FinancialChainAuditCommandTest.php
Normal file
@@ -0,0 +1,185 @@
|
||||
<?php
|
||||
|
||||
use App\Models\Player;
|
||||
use App\Models\PlayerWallet;
|
||||
use App\Models\WalletTxn;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
uses(RefreshDatabase::class);
|
||||
|
||||
beforeEach(function (): void {
|
||||
Schema::create('players', function (Blueprint $table): void {
|
||||
$table->id();
|
||||
$table->string('site_code');
|
||||
$table->string('site_player_id');
|
||||
$table->string('username')->nullable();
|
||||
$table->string('nickname')->nullable();
|
||||
$table->string('default_currency')->default('NPR');
|
||||
$table->string('funding_mode')->default('wallet');
|
||||
$table->smallInteger('status')->default(0);
|
||||
$table->timestamps();
|
||||
});
|
||||
|
||||
Schema::create('player_wallets', function (Blueprint $table): void {
|
||||
$table->id();
|
||||
$table->foreignId('player_id');
|
||||
$table->string('wallet_type');
|
||||
$table->string('currency_code');
|
||||
$table->bigInteger('balance')->default(0);
|
||||
$table->bigInteger('frozen_balance')->default(0);
|
||||
$table->smallInteger('status')->default(0);
|
||||
$table->integer('version')->default(0);
|
||||
$table->timestamps();
|
||||
});
|
||||
|
||||
Schema::create('wallet_txns', function (Blueprint $table): void {
|
||||
$table->id();
|
||||
$table->string('txn_no');
|
||||
$table->foreignId('player_id');
|
||||
$table->foreignId('wallet_id');
|
||||
$table->string('biz_type');
|
||||
$table->string('biz_no')->nullable();
|
||||
$table->smallInteger('direction');
|
||||
$table->bigInteger('amount');
|
||||
$table->bigInteger('balance_before');
|
||||
$table->bigInteger('balance_after');
|
||||
$table->string('status');
|
||||
$table->string('external_ref_no')->nullable();
|
||||
$table->string('idempotent_key')->nullable();
|
||||
$table->string('remark')->nullable();
|
||||
$table->timestamps();
|
||||
});
|
||||
|
||||
Schema::create('transfer_orders', function (Blueprint $table): void {
|
||||
$table->id();
|
||||
$table->string('transfer_no');
|
||||
$table->foreignId('player_id');
|
||||
$table->string('direction');
|
||||
$table->string('currency_code');
|
||||
$table->bigInteger('amount');
|
||||
$table->string('idempotent_key');
|
||||
$table->string('status');
|
||||
$table->timestamps();
|
||||
});
|
||||
|
||||
Schema::create('player_credit_accounts', function (Blueprint $table): void {
|
||||
$table->foreignId('player_id')->primary();
|
||||
$table->bigInteger('credit_limit')->default(0);
|
||||
$table->bigInteger('used_credit')->default(0);
|
||||
$table->bigInteger('frozen_credit')->default(0);
|
||||
$table->timestamps();
|
||||
});
|
||||
|
||||
Schema::create('credit_ledger', function (Blueprint $table): void {
|
||||
$table->id();
|
||||
$table->string('owner_type');
|
||||
$table->unsignedBigInteger('owner_id');
|
||||
$table->bigInteger('amount');
|
||||
$table->string('reason');
|
||||
$table->string('ref_type')->nullable();
|
||||
$table->unsignedBigInteger('ref_id')->nullable();
|
||||
$table->timestamps();
|
||||
});
|
||||
|
||||
Schema::create('ticket_items', function (Blueprint $table): void {
|
||||
$table->id();
|
||||
});
|
||||
|
||||
Schema::create('settlement_bills', function (Blueprint $table): void {
|
||||
$table->id();
|
||||
$table->string('bill_type')->default('player');
|
||||
$table->bigInteger('net_amount')->default(0);
|
||||
$table->bigInteger('paid_amount')->default(0);
|
||||
$table->bigInteger('unpaid_amount')->default(0);
|
||||
$table->json('meta_json')->nullable();
|
||||
});
|
||||
|
||||
Schema::create('payment_records', function (Blueprint $table): void {
|
||||
$table->id();
|
||||
$table->foreignId('settlement_bill_id');
|
||||
$table->bigInteger('amount');
|
||||
$table->string('status');
|
||||
$table->timestamp('confirmed_at')->nullable();
|
||||
});
|
||||
});
|
||||
|
||||
test('financial chain audit passes for consistent wallet ledger', function (): void {
|
||||
$player = Player::query()->create([
|
||||
'site_code' => 'main',
|
||||
'site_player_id' => 'financial-audit-ok',
|
||||
'username' => 'financial_audit_ok',
|
||||
'nickname' => null,
|
||||
'default_currency' => 'NPR',
|
||||
'status' => 0,
|
||||
]);
|
||||
|
||||
$wallet = PlayerWallet::query()->create([
|
||||
'player_id' => $player->id,
|
||||
'wallet_type' => 'lottery',
|
||||
'currency_code' => 'NPR',
|
||||
'balance' => 1000,
|
||||
'frozen_balance' => 0,
|
||||
'status' => 0,
|
||||
'version' => 1,
|
||||
]);
|
||||
|
||||
WalletTxn::query()->create([
|
||||
'txn_no' => 'WX_financial_audit_ok',
|
||||
'player_id' => $player->id,
|
||||
'wallet_id' => $wallet->id,
|
||||
'biz_type' => 'manual_seed',
|
||||
'biz_no' => 'manual_seed_ok',
|
||||
'direction' => 1,
|
||||
'amount' => 1000,
|
||||
'balance_before' => 0,
|
||||
'balance_after' => 1000,
|
||||
'status' => 'posted',
|
||||
'idempotent_key' => 'financial-audit-ok',
|
||||
]);
|
||||
|
||||
$this->artisan('lottery:audit-financial-chain')
|
||||
->expectsOutputToContain('Financial chain audit passed.')
|
||||
->assertExitCode(0);
|
||||
});
|
||||
|
||||
test('financial chain audit reports wallet balance drift', function (): void {
|
||||
$player = Player::query()->create([
|
||||
'site_code' => 'main',
|
||||
'site_player_id' => 'financial-audit-bad',
|
||||
'username' => 'financial_audit_bad',
|
||||
'nickname' => null,
|
||||
'default_currency' => 'NPR',
|
||||
'status' => 0,
|
||||
]);
|
||||
|
||||
$wallet = PlayerWallet::query()->create([
|
||||
'player_id' => $player->id,
|
||||
'wallet_type' => 'lottery',
|
||||
'currency_code' => 'NPR',
|
||||
'balance' => 900,
|
||||
'frozen_balance' => 0,
|
||||
'status' => 0,
|
||||
'version' => 1,
|
||||
]);
|
||||
|
||||
WalletTxn::query()->create([
|
||||
'txn_no' => 'WX_financial_audit_bad',
|
||||
'player_id' => $player->id,
|
||||
'wallet_id' => $wallet->id,
|
||||
'biz_type' => 'manual_seed',
|
||||
'biz_no' => 'manual_seed_bad',
|
||||
'direction' => 1,
|
||||
'amount' => 1000,
|
||||
'balance_before' => 0,
|
||||
'balance_after' => 1000,
|
||||
'status' => 'posted',
|
||||
'idempotent_key' => 'financial-audit-bad',
|
||||
]);
|
||||
|
||||
$this->artisan('lottery:audit-financial-chain')
|
||||
->expectsOutputToContain('Financial chain audit found')
|
||||
->expectsOutputToContain('[wallet_latest_mismatch]')
|
||||
->assertExitCode(1);
|
||||
});
|
||||
Reference in New Issue
Block a user