create([ 'username' => 'phase15_super', 'name' => 'Phase15', 'email' => null, 'password' => Hash::make('secret-strong'), 'status' => 0, ]); grantSuperAdminRole($admin); return $admin->createToken('test', ['*'], now()->addDay())->plainTextToken; } test('report job create list show and audit log index work for super admin', function (): void { AuditLogger::record('system', 0, 'bootstrap', 'test', null, null, null, null); $token = phase15SuperToken(); $this->withHeader('Authorization', 'Bearer '.$token) ->getJson('/api/v1/admin/audit-logs?per_page=5') ->assertOk() ->assertJsonPath('code', ErrorCode::Success->value); $create = $this->withHeader('Authorization', 'Bearer '.$token) ->postJson('/api/v1/admin/report-jobs', [ 'report_type' => 'wallet_txns_daily', 'export_format' => 'csv', 'filter_json' => ['currency_code' => 'NPR'], ]); $create->assertOk()->assertJsonPath('code', ErrorCode::Success->value); $id = (int) $create->json('data.id'); expect($id)->toBeGreaterThan(0); expect(ReportJob::query()->whereKey($id)->exists())->toBeTrue(); $this->withHeader('Authorization', 'Bearer '.$token) ->getJson('/api/v1/admin/report-jobs/'.$id) ->assertOk() ->assertJsonPath('data.report_type', 'wallet_txns_daily'); $this->withHeader('Authorization', 'Bearer '.$token) ->getJson('/api/v1/admin/report-jobs?per_page=10') ->assertOk() ->assertJsonPath('code', ErrorCode::Success->value); expect(AuditLog::query()->where('module_code', 'report_jobs')->exists())->toBeTrue(); }); test('reconcile job create with items and nested items index', function (): void { $token = phase15SuperToken(); $resp = $this->withHeader('Authorization', 'Bearer '.$token) ->postJson('/api/v1/admin/reconcile-jobs', [ 'reconcile_type' => 'wallet_transfer', 'period_start' => '2026-05-01T00:00:00Z', 'period_end' => '2026-05-02T00:00:00Z', 'items' => [ ['side_a_ref' => 'TO-1', 'side_b_ref' => 'MAIN-1', 'difference_amount' => 100, 'status' => 'mismatch'], ['side_a_ref' => 'TO-2', 'side_b_ref' => 'MAIN-2', 'difference_amount' => 0, 'status' => 'matched'], ], ]); $resp->assertOk(); $id = (int) $resp->json('data.id'); expect($id)->toBeGreaterThan(0); $job = ReconcileJob::query()->whereKey($id)->firstOrFail(); expect((int) $job->admin_user_id)->toBeGreaterThan(0); expect($job->items()->count())->toBe(2); $this->withHeader('Authorization', 'Bearer '.$token) ->getJson('/api/v1/admin/reconcile-jobs/'.$id.'/items') ->assertOk() ->assertJsonPath('data.meta.total', 2); }); test('admin without report permission receives 403 on report-jobs', function (): void { $role = AdminRole::query()->create(['slug' => 'auditor_test', 'name' => 'Auditor Test']); $ids = DB::table('admin_menu_actions') ->whereIn('permission_code', AdminPermissionBridge::menuActionCodesForLegacy('prd.audit.finance')) ->where('status', 1) ->pluck('id'); foreach ($ids as $mid) { DB::table('admin_role_menu_actions')->insert([ 'role_id' => $role->id, 'menu_action_id' => (int) $mid, ]); } $user = AdminUser::query()->create([ 'username' => 'auditor_only', 'name' => 'Auditor', 'email' => null, 'password' => Hash::make('pw-audit'), 'status' => 0, ]); $siteId = AdminUser::defaultAdminSiteId(); $user->roles()->sync([ (int) $role->id => [ 'site_id' => $siteId, 'granted_at' => now(), ], ]); $token = $user->createToken('test', ['*'], now()->addDay())->plainTextToken; $this->withHeader('Authorization', 'Bearer '.$token) ->getJson('/api/v1/admin/audit-logs') ->assertOk(); $this->withHeader('Authorization', 'Bearer '.$token) ->postJson('/api/v1/admin/report-jobs', ['report_type' => 'x']) ->assertStatus(403) ->assertJsonPath('code', ErrorCode::AdminForbidden->value); });