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); });