seed(AdminRbacAndUserSeeder::class); $this->artisan('lottery:admin-auth-sync')->assertExitCode(0); }); function reconcileScanToken(): string { $admin = AdminUser::query()->create([ 'username' => 'reconcile_scan_admin', 'name' => 'Reconcile Scan', 'email' => null, 'password' => Hash::make('secret-strong'), 'status' => 0, ]); grantSuperAdminRole($admin); return $admin->createToken('test', ['*'], now()->addDay())->plainTextToken; } test('manual reconcile job create runs wallet transfer detector scan', function (): void { $token = reconcileScanToken(); $admin = AdminUser::query()->where('username', 'reconcile_scan_admin')->firstOrFail(); $player = Player::query()->create([ 'site_code' => 'main', 'site_player_id' => 'manual-reconcile-1', 'username' => null, 'nickname' => null, 'default_currency' => 'NPR', 'status' => 0, ]); TransferOrder::query()->create([ 'transfer_no' => 'TO_manual_scan', 'player_id' => $player->id, 'direction' => 'out', 'currency_code' => 'NPR', 'amount' => 500, 'idempotent_key' => 'manual-scan-key', 'status' => 'pending_reconcile', 'external_request_payload' => null, 'external_response_payload' => null, 'external_ref_no' => null, 'fail_reason' => 'main_site_timeout', 'finished_at' => null, 'created_at' => now()->subHours(2), ]); $this->withHeader('Authorization', 'Bearer '.$token) ->postJson('/api/v1/admin/reconcile-jobs', [ 'reconcile_type' => 'wallet_transfer', 'date_from' => now()->subDay()->toDateString(), 'date_to' => now()->toDateString(), 'player_id' => $player->id, ]) ->assertOk() ->assertJsonPath('data.item_count', 1); $job = ReconcileJob::query()->latest('id')->firstOrFail(); expect($job->admin_user_id)->toBe($admin->id) ->and($job->items()->count())->toBe(1) ->and($job->items()->value('side_a_ref'))->toBe('TO_manual_scan'); }); test('manual reconcile job create returns zero items when scan finds nothing', function (): void { $token = reconcileScanToken(); $this->withHeader('Authorization', 'Bearer '.$token) ->postJson('/api/v1/admin/reconcile-jobs', [ 'reconcile_type' => 'wallet_transfer', 'date_from' => now()->subDay()->toDateString(), 'date_to' => now()->toDateString(), ]) ->assertOk() ->assertJsonPath('data.item_count', 0); });