vnpayService = $vnpayService; $this->activityLogger = $activityLogger; } // ponytail: VNPay auto-deposit disabled — nạp tiền hiện dùng luồng thủ công (ManualDepositController). public function handle(DepositRequest $request) { return response()->json([ 'error' => true, 'message' => 'Nạp tiền qua VNPay hiện không khả dụng. Vui lòng sử dụng nạp tiền thủ công.', ], 410); // $user = $request->user(); // $transRef = time(); // $uuid = Str::uuid(); // $publicCode = 'DEP-' . now()->format('Ymd') . '-' . strtoupper(Str::random(6)); // // $transaction = Transaction::create([ // 'uuid' => $uuid, // 'public_code' => $publicCode, // 'trans' => 'DEP' . $transRef, // 'amount' => $request->amount, // 'customer_id' => $user->id, // 'status' => TransactionStatus::PENDING->value, // ]); // // $paymentUrl = $this->vnpayService->createPaymentUrl([ // 'amount' => $request->amount, // 'transaction_ref' => $transRef, // 'transaction_uuid' => $uuid, // ]); // // $this->activityLogger->log( // event: 'deposit_vnpay', // logName: 'Transaction', // description: "Customer {$user->email} tạo yêu cầu nạp tiền VNPay: " . number_format($request->amount) . ' VNĐ - Mã: ' . $publicCode, // subject: $transaction, // newValues: ['public_code' => $publicCode, 'amount' => $request->amount, 'type' => 'vnpay'], // ); // // return response()->json([ // 'error' => false, // 'message' => 'Tạo yêu cầu nạp tiền thành công', // 'data' => [ // 'transaction_id' => $transaction->trans, // 'transaction_uuid' => $uuid, // 'transaction_code' => $publicCode, // 'payment_url' => $paymentUrl, // ], // ]); } protected function redirectToFrontend(string $status = 'failed', ?string $transactionCode = null): \Illuminate\Http\RedirectResponse { $frontendUrl = config('vnpay.frontend_url', 'http://localhost:3000'); $url = $frontendUrl . '/nap-tien/return'; $params = ['status' => $status]; if ($transactionCode) { $params['code'] = $transactionCode; } return redirect()->away($url . '?' . http_build_query($params)); } // ponytail: VNPay auto-deposit disabled — nạp tiền hiện dùng luồng thủ công (ManualDepositController). public function returnCallback(Request $request) { return $this->redirectToFrontend('failed'); // $data = $request->all(); // // $vnp_TxnRef = $data['vnp_TxnRef'] ?? null; // $vnp_Amount = $data['vnp_Amount'] ?? 0; // // FacadesLog::info('VNPay callback received', [ // 'vnp_TxnRef' => $vnp_TxnRef, // 'vnp_Amount' => $vnp_Amount, // 'user' => $request->user() ? $request->user()->id : 'not authenticated', // ]); // // $transaction = Transaction::where('trans', 'DEP' . $vnp_TxnRef)->first(); // // if (!$transaction) { // return $this->redirectToFrontend('failed'); // } // // if ($transaction->status == TransactionStatus::COMPLETED->value) { // return $this->redirectToFrontend('success', $transaction->public_code); // } // // $verify = $this->vnpayService->verifyPayment($data); // // FacadesLog::info('VNPay callback debug', [ // 'isValid' => $verify['isValid'], // 'isSuccess' => $verify['isSuccess'] ?? false, // 'responseCode' => $data['vnp_ResponseCode'] ?? 'N/A', // ]); // // if (!$verify['isValid']) { // return $this->redirectToFrontend('failed', $transaction->public_code); // } // // if (!$verify['isSuccess']) { // $transaction->update(['status' => TransactionStatus::FAILED->value]); // return $this->redirectToFrontend('failed', $transaction->public_code); // } // // $originalAmount = $transaction->amount * 100; // if ($vnp_Amount != $originalAmount) { // $transaction->update(['status' => TransactionStatus::FAILED->value]); // return $this->redirectToFrontend('failed', $transaction->public_code); // } // // try { // DB::beginTransaction(); // // $transaction->update(['status' => TransactionStatus::COMPLETED->value]); // // $customer = Customer::find($transaction->customer_id); // // FacadesLog::info('Customer update debug', [ // 'customer_id' => $transaction->customer_id, // 'customer_found' => $customer ? true : false, // 'transaction_amount' => $transaction->amount, // 'current_total' => $customer->total ?? 'N/A', // 'current_credit' => $customer->credit ?? 'N/A', // ]); // // $customer->total += $transaction->amount; // $customer->credit += $transaction->amount / 100; // $customer->save(); // // FacadesLog::info('Customer after update', [ // 'new_total' => $customer->total, // 'new_credit' => $customer->credit, // ]); // // Log::create([ // 'agent' => 'api', // 'client_ip' => $request->ip(), // 'description' => 'Nạp tiền vào tài khoản: ' . number_format($transaction->amount) . ' VNĐ (+' . number_format($transaction->amount / 100) . ' credit)', // 'customer_id' => $transaction->customer_id, // ]); // // $this->activityLogger->log( // event: 'deposit_success', // logName: 'Transaction', // description: "Customer {$customer->email} nạp tiền VNPay thành công: " . number_format($transaction->amount) . ' VNĐ - Mã: ' . $transaction->public_code, // subject: $transaction, // newValues: ['amount' => $transaction->amount, 'new_total' => $customer->total, 'public_code' => $transaction->public_code], // ); // // DepositSuccessJob::dispatch([ // 'customer_email' => $customer->email, // 'customer_name' => $customer->fullname, // 'transaction_code' => $transaction->public_code, // 'amount' => $transaction->amount, // 'credit' => $transaction->amount / 100, // 'current_total' => $customer->total, // 'current_credit' => $customer->credit, // 'deposit_date' => now()->format('d/m/Y H:i:s'), // ]); // // DB::commit(); // } catch (\Exception $e) { // DB::rollBack(); // FacadesLog::error('Payment processing error: ' . $e->getMessage()); // return $this->redirectToFrontend('failed', $transaction->public_code); // } // // return $this->redirectToFrontend('success', $transaction->public_code); } public function getTransactions(Request $request) { $user = $request->user(); $transactions = Transaction::where('customer_id', $user->id) ->orderBy('created_at', 'desc') ->get(); return response()->json([ 'error' => false, 'message' => 'Lấy danh sách giao dịch thành công', 'data' => $transactions, ]); } public function verifyPayment(Request $request) { $transRef = $request->query('vnp_TxnRef'); if (!$transRef) { return response()->json([ 'error' => true, 'message' => 'Thiếu tham số vnp_TxnRef', ], 400); } $transaction = Transaction::where('trans', 'DEP' . $transRef) ->where('customer_id', $request->user()->id) ->first(); if (!$transaction) { return response()->json([ 'error' => true, 'message' => 'Giao dịch không tồn tại', ], 404); } return response()->json([ 'error' => false, 'message' => 'Lấy thông tin giao dịch thành công', 'data' => [ 'trans' => $transaction->trans, 'amount' => $transaction->amount, 'amount_vnp' => $transaction->amount * 100, 'status' => $transaction->status, 'status_label' => TransactionStatus::from($transaction->status)->label(), 'created_at' => $transaction->created_at, 'updated_at' => $transaction->updated_at, ], ]); } /** * GET /v1/client/payment-history — combined deposit transactions + order invoice payments */ public function getClientPaymentHistory(Request $request): JsonResponse { $user = $request->user(); $deposits = Transaction::where('customer_id', $user->id) ->orderByDesc('created_at') ->get() ->map(fn(Transaction $t) => [ 'type' => 'deposit', 'public_code' => $t->public_code, 'trans' => $t->trans, 'description' => $t->typeLabel(), 'direction' => $t->direction, 'amount' => (float) $t->amount, 'status' => $t->status, 'status_label' => TransactionStatus::from((int) $t->status)->label(), 'detail_key' => $t->uuid, 'created_at' => $t->created_at?->toISOString(), ]); $invoicePayments = Invoice::with(['order.orderItems.product']) ->where('customer_id', $user->id) ->orderByDesc('created_at') ->get() ->map(fn(Invoice $inv) => [ 'type' => 'order_payment', 'public_code' => $inv->invoice_number, 'trans' => null, 'description' => 'Thanh toán đơn hàng: ' . ($inv->order?->orderItems->first()?->product?->name ?? $inv->order?->order_num), 'direction' => 'debit', 'amount' => (float) $inv->total, 'status' => $inv->status, 'status_label' => \App\Enums\Invoice\InvoiceStatus::tryFrom((int) $inv->status)?->label() ?? '-', 'detail_key' => $inv->order?->order_num, 'created_at' => $inv->created_at?->toISOString(), ]); $combined = $deposits->concat($invoicePayments) ->sortByDesc('created_at') ->values(); return response()->json([ 'error' => false, 'message' => 'Lấy lịch sử thanh toán thành công', 'data' => $combined, ]); } public function getClientTransactionDetail(Request $request, string $uuid): JsonResponse { $transaction = Transaction::query() ->where('uuid', $uuid) ->where('customer_id', $request->user()->id) ->first(); if (! $transaction) { return response()->json(['error' => true, 'message' => 'Giao dịch không tồn tại'], 404); } return response()->json([ 'error' => false, 'data' => [ 'uuid' => $transaction->uuid, 'public_code' => $transaction->public_code, 'trans' => $transaction->trans, 'type' => $transaction->type, 'type_label' => $transaction->typeLabel(), 'direction' => $transaction->direction, 'amount' => (int) $transaction->amount, 'received_amount' => $transaction->received_amount !== null ? (int) $transaction->received_amount : null, 'status' => (int) $transaction->status, 'status_label' => TransactionStatus::from((int) $transaction->status)->label(), 'has_proof' => $transaction->proof_image !== null, 'created_at' => $transaction->created_at?->toISOString(), 'updated_at' => $transaction->updated_at?->toISOString(), ], ]); } public function getByPublicCode(Request $request) { $code = $request->query('code'); if (!$code) { return response()->json([ 'error' => true, 'message' => 'Thiếu mã giao dịch', ], 400); } $transaction = Transaction::where('public_code', $code) ->where('customer_id', $request->user()->id) ->first(); if (!$transaction) { return response()->json([ 'error' => true, 'message' => 'Giao dịch không tồn tại', ], 404); } return response()->json([ 'error' => false, 'message' => 'Lấy thông tin giao dịch thành công', 'data' => [ 'public_code' => $transaction->public_code, 'amount' => $transaction->amount, 'amount_formatted' => number_format($transaction->amount) . ' VNĐ', 'status' => $transaction->status, 'status_label' => TransactionStatus::from($transaction->status)->label(), 'created_at' => $transaction->created_at->format('Y-m-d H:i:s'), 'paid_at' => $transaction->updated_at->format('Y-m-d H:i:s'), ], ]); } }