feat: Implement VNPAY callback redirection to frontend and add UUID/public code to transactions.
This commit is contained in:
@@ -12,6 +12,7 @@ use App\Models\Transaction;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Log as FacadesLog;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
class TransactionController extends Controller
|
||||
{
|
||||
@@ -26,8 +27,12 @@ class TransactionController extends Controller
|
||||
{
|
||||
$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,
|
||||
@@ -37,6 +42,7 @@ class TransactionController extends Controller
|
||||
$paymentUrl = $this->vnpayService->createPaymentUrl([
|
||||
'amount' => $request->amount,
|
||||
'transaction_ref' => $transRef,
|
||||
'transaction_uuid' => $uuid,
|
||||
]);
|
||||
|
||||
return response()->json([
|
||||
@@ -44,11 +50,27 @@ class TransactionController extends Controller
|
||||
'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));
|
||||
}
|
||||
|
||||
public function returnCallback(Request $request)
|
||||
{
|
||||
$data = $request->all();
|
||||
@@ -65,44 +87,11 @@ class TransactionController extends Controller
|
||||
$transaction = Transaction::where('trans', 'DEP' . $vnp_TxnRef)->first();
|
||||
|
||||
if (!$transaction) {
|
||||
return response()->json([
|
||||
'error' => true,
|
||||
'message' => 'Giao dịch không tồn tại',
|
||||
'debug' => [
|
||||
'vnp_TxnRef' => $vnp_TxnRef,
|
||||
'search_trans' => 'DEP' . $vnp_TxnRef,
|
||||
]
|
||||
], 404);
|
||||
return $this->redirectToFrontend('failed');
|
||||
}
|
||||
|
||||
if ($transaction->status == TransactionStatus::COMPLETED->value) {
|
||||
return response()->json([
|
||||
'error' => false,
|
||||
'message' => 'Giao dịch đã được xử lý trước đó',
|
||||
'data' => $transaction,
|
||||
]);
|
||||
}
|
||||
|
||||
$user = $request->user();
|
||||
|
||||
if (!$user) {
|
||||
return response()->json([
|
||||
'error' => true,
|
||||
'message' => 'Vui lòng đăng nhập',
|
||||
'debug' => [
|
||||
'transaction_found' => true,
|
||||
'trans' => $transaction->trans,
|
||||
'amount_db' => $transaction->amount,
|
||||
'amount_vnp' => $vnp_Amount,
|
||||
]
|
||||
], 401);
|
||||
}
|
||||
|
||||
if ($transaction->customer_id !== $user->id) {
|
||||
return response()->json([
|
||||
'error' => true,
|
||||
'message' => 'Giao dịch không thuộc về bạn',
|
||||
], 403);
|
||||
return $this->redirectToFrontend('success', $transaction->public_code);
|
||||
}
|
||||
|
||||
$verify = $this->vnpayService->verifyPayment($data);
|
||||
@@ -114,34 +103,18 @@ class TransactionController extends Controller
|
||||
]);
|
||||
|
||||
if (!$verify['isValid']) {
|
||||
return response()->json([
|
||||
'error' => true,
|
||||
'message' => 'Dữ liệu không hợp lệ',
|
||||
], 400);
|
||||
return $this->redirectToFrontend('failed', $transaction->public_code);
|
||||
}
|
||||
|
||||
if (!$verify['isSuccess']) {
|
||||
$transaction->update(['status' => TransactionStatus::FAILED->value]);
|
||||
|
||||
return response()->json([
|
||||
'error' => true,
|
||||
'message' => 'Thanh toán thất bại',
|
||||
'data' => $verify['data'],
|
||||
], 400);
|
||||
return $this->redirectToFrontend('failed', $transaction->public_code);
|
||||
}
|
||||
|
||||
$originalAmount = $transaction->amount * 100;
|
||||
if ($vnp_Amount != $originalAmount) {
|
||||
$transaction->update(['status' => TransactionStatus::FAILED->value]);
|
||||
return response()->json([
|
||||
'error' => true,
|
||||
'message' => 'Số tiền không khớp',
|
||||
'debug' => [
|
||||
'amount_db' => $transaction->amount,
|
||||
'amount_db_times_100' => $originalAmount,
|
||||
'amount_vnp' => $vnp_Amount,
|
||||
]
|
||||
], 400);
|
||||
return $this->redirectToFrontend('failed', $transaction->public_code);
|
||||
}
|
||||
|
||||
try {
|
||||
@@ -178,23 +151,11 @@ class TransactionController extends Controller
|
||||
DB::commit();
|
||||
} catch (\Exception $e) {
|
||||
DB::rollBack();
|
||||
return response()->json([
|
||||
'error' => true,
|
||||
'message' => 'Lỗi xử lý giao dịch: ' . $e->getMessage(),
|
||||
], 500);
|
||||
FacadesLog::error('Payment processing error: ' . $e->getMessage());
|
||||
return $this->redirectToFrontend('failed', $transaction->public_code);
|
||||
}
|
||||
|
||||
return response()->json([
|
||||
'error' => false,
|
||||
'message' => 'Thanh toán thành công',
|
||||
'data' => [
|
||||
'transaction' => $transaction->fresh(),
|
||||
'customer' => [
|
||||
'total' => $customer->total,
|
||||
'credit' => $customer->credit,
|
||||
],
|
||||
],
|
||||
]);
|
||||
return $this->redirectToFrontend('success', $transaction->public_code);
|
||||
}
|
||||
|
||||
public function getTransactions(Request $request)
|
||||
@@ -268,4 +229,53 @@ class TransactionController extends Controller
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
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)->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' => [
|
||||
'transaction' => [
|
||||
'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'),
|
||||
],
|
||||
'customer' => [
|
||||
'fullname' => $transaction->customer->fullname,
|
||||
'email' => $transaction->customer->email,
|
||||
'phone' => $transaction->customer->phone,
|
||||
'address' => $transaction->customer->address,
|
||||
],
|
||||
'balance' => [
|
||||
'total' => $transaction->customer->total,
|
||||
'credit' => $transaction->customer->credit,
|
||||
'total_formatted' => number_format($transaction->customer->total) . ' VNĐ',
|
||||
'credit_formatted' => number_format($transaction->customer->credit) . ' điểm',
|
||||
],
|
||||
],
|
||||
]);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user