namespace App\Http\Controllers\Admin; use App\Http\Controllers\Controller; use App\Models\Transaction; use App\Services\VoteService; use Illuminate\Http\RedirectResponse; use Illuminate\View\View; use Symfony\Component\HttpFoundation\StreamedResponse; class TransactionController extends Controller { public function index(): View { return view('admin.transactions.index', [ 'transactions' => Transaction::with('nominee') ->when(request('status'), fn ($q, $s) => $q->where('status', $s)) ->when(request('search'), fn ($q, $s) => $q->where(fn ($w) => $w ->where('voter_email', 'like', "%{$s}%") ->orWhere('paystack_reference', 'like', "%{$s}%"))) ->latest() ->paginate(25) ->withQueryString(), ]); } /** Manual fallback: re-query Paystack when a webhook is missed. */ public function requery(Transaction $transaction, VoteService $votes): RedirectResponse { $votes->verifyAndCredit($transaction->paystack_reference); return back()->with('success', "Re-queried {$transaction->paystack_reference}. Status: {$transaction->refresh()->status}."); } public function export(): StreamedResponse { return response()->streamDownload(function () { $out = fopen('php://output', 'w'); fputcsv($out, ['Reference', 'Voter Name', 'Voter Email', 'Phone', 'Nominee', 'Votes', 'Amount', 'Status', 'Paid At']); Transaction::with('nominee')->where('status', 'success')->chunk(500, function ($rows) use ($out) { foreach ($rows as $t) { fputcsv($out, [$t->paystack_reference, $t->voter_name, $t->voter_email, $t->voter_phone, $t->nominee->farm_name, $t->vote_count, $t->amount_paid, $t->status, $t->paid_at]); } }); fclose($out); }, 'transactions-' . now()->toDateString() . '.csv'); } }