id) ->where('is_active', true) ->orderBy('created_at', 'desc') ->limit(20) ->get(); return response()->json([ 'success' => true, 'balance' => $user->total_balance, 'credit' => $user->total_credit, 'history' => $history ]); } public function topUp(Request $request) { // Check if Top Up is enabled globally if (!(\App\Models\SystemSetting::getValue('top_up_enabled', true))) { return ResponseHelper::returnError('Credit top-up is currently disabled by administrators.'); } $amount = (float) $request->input('amount'); $method = $request->input('method', 'GCASH'); if ($amount <= 0) { return ResponseHelper::returnError('Amount must be greater than zero'); } $user = User::find(Auth::id()); if (!$user) return ResponseHelper::returnUnauthorized(); // Start Transaction DB::beginTransaction(); try { // 1. Simulate Payment Success (in real life this would be a webhook/callback) $payment = PaymentProcessor::initiatePayment($amount, $method, $user->hashkey); if (!$payment['success']) { throw new \Exception('Payment initiation failed'); } // 2. Update User Balance $user->total_balance += $amount; $user->save(); // 3. Record in MemberLedger $ledger = new MemberLedger([ 'hashkey' => Str::random(64), 'user_id' => $user->id, 'amount' => $amount, 'transaction_type' => 'TOP_UP', 'flow' => 'IN', 'balance_after' => $user->total_balance, 'description' => "Credit Top-up via {$method}", 'reference_id' => $payment['transaction_id'], 'created_by' => $user->id, 'is_active' => true, ]); $ledger->save(); // 4. Record in GlobalTransaction (for compatibility with existing reports) $globalTxn = new GlobalTransaction([ 'hashkey' => Str::random(64), 'user_id' => $user->id, 'amount' => $amount, 'type' => ProductTransactionType::TOP_UP, 'status' => 'COMPLETED', 'description' => "Credit Top-up via {$method}", 'flow' => TransactionFlow::INCOME, 'created_by' => $user->id, ]); $globalTxn->save(); DB::commit(); return response()->json([ 'success' => true, 'message' => 'Top-up successful', 'balance' => $user->total_balance, 'transaction_id' => $payment['transaction_id'] ]); } catch (\Exception $e) { DB::rollBack(); return ResponseHelper::returnError('Top-up failed: ' . $e->getMessage()); } } public function transferCredit(Request $request) { $recipientHash = $request->input('recipient_hash'); $amount = (float) $request->input('amount'); if ($amount <= 0) return ResponseHelper::returnError('Invalid amount'); $sender = User::find(Auth::id()); if (!$sender) return ResponseHelper::returnUnauthorized(); if ($sender->total_balance < $amount) { return ResponseHelper::returnError('Insufficient balance'); } $recipient = User::where('hashkey', $recipientHash)->first(); if (!$recipient) return ResponseHelper::returnError('Recipient not found'); if ($sender->id === $recipient->id) { return ResponseHelper::returnError('Cannot transfer to yourself'); } DB::beginTransaction(); try { // Deduct from sender $sender->total_balance -= $amount; $sender->save(); // Add to recipient $recipient->total_balance += $amount; $recipient->save(); $txnRef = Str::random(12); // Record Ledger for Sender MemberLedger::create([ 'hashkey' => Str::random(64), 'user_id' => $sender->id, 'amount' => $amount, 'transaction_type' => 'TRANSFER_OUT', 'flow' => 'OUT', 'balance_after' => $sender->total_balance, 'description' => "Credit Transfer to {$recipient->fullname}", 'reference_id' => $txnRef, 'created_by' => $sender->id, ]); // Record Ledger for Recipient MemberLedger::create([ 'hashkey' => Str::random(64), 'user_id' => $recipient->id, 'amount' => $amount, 'transaction_type' => 'TRANSFER_IN', 'flow' => 'IN', 'balance_after' => $recipient->total_balance, 'description' => "Credit Transfer from {$sender->fullname}", 'reference_id' => $txnRef, 'created_by' => $sender->id, ]); DB::commit(); return response()->json(['success' => true, 'message' => 'Transfer successful']); } catch (\Exception $e) { DB::rollBack(); return ResponseHelper::returnError('Transfer failed'); } } public function searchUsers(Request $request) { $query = $request->input('q'); if (empty($query)) return response()->json(['success' => true, 'data' => []]); $users = User::where('fullname', 'like', "%{$query}%") ->orWhere('name', 'like', "%{$query}%") ->orWhere('mobile_number', 'like', "%{$query}%") ->where('id', '!=', Auth::id()) ->limit(10) ->get(['hashkey', 'fullname', 'name', 'mobile_number']); return response()->json(['success' => true, 'data' => $users]); } /** * GET the current QRPH payment code (available to all authenticated users for top-up display). */ public function getQrphCode(Request $request) { $raw = SystemSetting::getValue('qrph_payment_code', null); $imgHashkey = SystemSetting::getValue('qrph_payment_image_hashkey', null); if (empty($raw)) { return response()->json(['success' => true, 'qrph' => null, 'decoded' => null, 'image_url' => null]); } $decoded = QrphDecoder::decode($raw); $imageUrl = $imgHashkey ? "/RequestData/File/{$imgHashkey}" : null; return response()->json([ 'success' => true, 'qrph' => $raw, 'decoded' => $decoded, 'image_url' => $imageUrl, ]); } /** * SET the QRPH payment code — ULTIMATE only (enforced by route middleware). * Accepts optional image_hashkey from a prior /File/Upload/QrphPayment call. */ public function setQrphCode(Request $request) { $raw = trim($request->input('qrph_code', '')); $imgHashkey = trim($request->input('image_hashkey', '')); if (empty($raw)) { SystemSetting::setValue('qrph_payment_code', ''); SystemSetting::setValue('qrph_payment_image_hashkey', ''); return response()->json(['success' => true, 'message' => 'QRPH code cleared.']); } $decoded = QrphDecoder::decode($raw); SystemSetting::setValue('qrph_payment_code', $raw); if (!empty($imgHashkey)) { SystemSetting::setValue('qrph_payment_image_hashkey', $imgHashkey); } $imageUrl = $imgHashkey ? "/RequestData/File/{$imgHashkey}" : null; return response()->json([ 'success' => true, 'message' => 'QRPH code saved.', 'decoded' => $decoded, 'image_url' => $imageUrl, ]); } /** * Decode a QRPH string without saving — for preview before saving. */ public function decodeQrph(Request $request) { $raw = trim($request->input('qrph_code', '')); if (empty($raw)) { return ResponseHelper::returnError('No QR string provided.'); } return response()->json([ 'success' => true, 'decoded' => QrphDecoder::decode($raw), ]); } }