Tutorial selanjutnya adalah mengintegrasikan Payment Gateway di Laravel, menggunakan Midtrans sebagai contoh (salah satu payment gateway populer di Indonesia).
Buka Midtrans Dashboard dan daftar akun
Setelah login, buat Project Baru untuk aplikasi Anda.
Di dashboard pilih enviroment sandbox, kemudian di menu pengaturan, Anda akan mendapatkan Server Key dan Client Key. Simpan ini untuk konfigurasi Laravel nanti.
Jalankan perintah berikut untuk menginstal library Midtrans menggunakan Composer:
composer require midtrans/midtrans-php
Buat file konfigurasi baru di config/midtrans.php dan tambahkan config server dan client sesuai di dashboard:
<?php
return [
'server_key' => env('MIDTRANS_SERVER_KEY', ''),
'client_key' => env('MIDTRANS_CLIENT_KEY', ''),
'is_production' => env('MIDTRANS_IS_PRODUCTION', false),
'is_sanitized' => env('MIDTRANS_IS_SANITIZED', true),
'is_3ds' => env('MIDTRANS_IS_3DS', true),
];
.envTambahkan server key dan client key dari dashboard Midtrans ke file .env:
MIDTRANS_SERVER_KEY=your_server_key
MIDTRANS_CLIENT_KEY=your_client_key
MIDTRANS_IS_PRODUCTION=false
MIDTRANS_IS_SANITIZED=true
MIDTRANS_IS_3DS=true
Di AppServiceProvider tambahkan inisialisasi Midtrans di dalam method boot:
use Midtrans\Config;
public function boot()
{
Config::$serverKey = config('midtrans.server_key');
Config::$isProduction = config('midtrans.is_production');
Config::$isSanitized = config('midtrans.is_sanitized');
Config::$is3ds = config('midtrans.is_3ds');
}
1. Tambahkan method Proses Pembayaran
Tambahkan method untuk memproses pembayaran:
use Midtrans\Snap;
use App\Models\Order;
public function process(Request $request)
{
$categories = Category::all();
$request->validate([
'address' => 'required|string',
'city' => 'required|string',
'state' => 'required|string',
'zip' => 'required|string',
'country' => 'required|string',
]);
$cart = session()->get('cart', []);
if (empty($cart)) {
return redirect()->route('cart.index')->withErrors('Cart is empty');
}
$totalAmount = array_reduce($cart, function ($sum, $item) {
return $sum + ($item['price'] * $item['quantity']);
}, 0);
Address::create([
'user_id' => Auth::id(),
'type' => 'billing', // Bisa ditambah pengaturan untuk shipping
'address' => $request->address,
'city' => $request->city,
'state' => $request->state,
'zip' => $request->zip,
'country' => $request->country,
]);
$order = Order::create([
'user_id' => Auth::id(),
'total' => $totalAmount,
'status' => 'pending',
]);
$orderId = $order->id; // ID yang baru saja di-insert
$grossAmount = $totalAmount; // Total harga
foreach ($cart as $productId => $item) {
OrderItem::create([
'order_id' => $order->id,
'product_id' => $productId,
'quantity' => $item['quantity'],
'price' => $item['price'],
]);
}
$params = [
'transaction_details' => [
'order_id' => $orderId,
'gross_amount' => $grossAmount,
],
'customer_details' => [
'first_name' => auth()->user()->name,
'email' => auth()->user()->email,
],
];
// Generate Snap Token
$snapToken = Snap::getSnapToken($params);
return view('frontend.payment', compact('snapToken','categories'));
//session()->forget('cart');
//return redirect()->route('checkout.success')->with('status', 'Order placed successfully');
}
2. Callback untuk Status Pembayaran
Tambahkan method untuk menangani callback dari Midtrans:
use Midtrans\Notification;
public function callback(Request $request)
{
$notification = new Notification();
$orderId = $notification->order_id;
$transactionStatus = $notification->transaction_status;
$order = Order::where('id', $orderId)->first();
if ($transactionStatus == 'capture' || $transactionStatus == 'settlement') {
$order->status = 'paid';
} elseif ($transactionStatus == 'pending') {
$order->status = 'pending';
} elseif ($transactionStatus == 'deny' || $transactionStatus == 'expire') {
$order->status = 'failed';
}
$order->save();
return response()->json(['status' => 'success']);
}
Secara total controller, checkout akan seperti berikut:
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Models\Order;
use App\Models\OrderItem;
use App\Models\Address;
use App\Models\Product;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Str;
use App\Models\Category;
use Midtrans\Snap;
use Midtrans\Notification;
class CheckoutController extends Controller
{
public function showCheckoutForm()
{
$categories = Category::all();
$cart = session()->get('cart', []);
$total = array_reduce($cart, function ($sum, $item) {
return $sum + ($item['price'] * $item['quantity']);
}, 0);
return view('frontend.checkout', compact('cart', 'total','categories'));
}
public function process(Request $request)
{
$categories = Category::all();
$request->validate([
'address' => 'required|string',
'city' => 'required|string',
'state' => 'required|string',
'zip' => 'required|string',
'country' => 'required|string',
]);
$cart = session()->get('cart', []);
if (empty($cart)) {
return redirect()->route('cart.index')->withErrors('Cart is empty');
}
$totalAmount = array_reduce($cart, function ($sum, $item) {
return $sum + ($item['price'] * $item['quantity']);
}, 0);
Address::create([
'user_id' => Auth::id(),
'type' => 'billing', // Bisa ditambah pengaturan untuk shipping
'address' => $request->address,
'city' => $request->city,
'state' => $request->state,
'zip' => $request->zip,
'country' => $request->country,
]);
$order = Order::create([
'user_id' => Auth::id(),
'total' => $totalAmount,
'status' => 'pending',
]);
$orderId = $order->id; // ID yang baru saja di-insert
$grossAmount = $totalAmount; // Total harga
foreach ($cart as $productId => $item) {
OrderItem::create([
'order_id' => $order->id,
'product_id' => $productId,
'quantity' => $item['quantity'],
'price' => $item['price'],
]);
}
$params = [
'transaction_details' => [
'order_id' => $orderId,
'gross_amount' => $grossAmount,
],
'customer_details' => [
'first_name' => auth()->user()->name,
'email' => auth()->user()->email,
],
];
// Generate Snap Token
$snapToken = Snap::getSnapToken($params);
return view('frontend.payment', compact('snapToken','categories'));
//session()->forget('cart');
//return redirect()->route('checkout.success')->with('status', 'Order placed successfully');
}
public function callback(Request $request)
{
$notification = new Notification();
$orderId = $notification->order_id;
$transactionStatus = $notification->transaction_status;
$order = Order::where('order_id', $orderId)->first();
if ($transactionStatus == 'capture' || $transactionStatus == 'settlement') {
$order->status = 'paid';
} elseif ($transactionStatus == 'pending') {
$order->status = 'pending';
} elseif ($transactionStatus == 'deny' || $transactionStatus == 'expire') {
$order->status = 'failed';
}
$order->save();
return response()->json(['status' => 'success']);
}
public function successsCheckout(){
$categories = Category::all();
return view('frontend.checkout-success', compact('categories'));
}
}
Tambahkan route untuk checkout:
Route::middleware('auth')->group(function () {
Route::get('/checkout', [CheckoutController::class, 'index'])->name('checkout.index');
Route::post('/checkout/process', [CheckoutController::class, 'process'])->name('checkout.process');
Route::post('/midtrans/callback', [CheckoutController::class, 'callback'])->name('midtrans.callback');
});
resources/views/frontend/payment.blade.php)Halaman untuk memuat Snap Midtrans:
@extends('layouts.frontend')
@section('content')
<div class="container">
<h1>Payment</h1>
<button id="pay-button" class="btn btn-primary">Pay Now</button>
</div>
<script src="https://app.sandbox.midtrans.com/snap/snap.js" data-client-key="{{ config('midtrans.client_key') }}"></script>
<script>
const payButton = document.getElementById('pay-button');
payButton.addEventListener('click', function() {
snap.pay('{{ $snapToken }}');
});
</script>
@endsection
Jika kita melakukan checkout dan pilih payment, akan muncul seperti berikut:
Selanjutnya kita testing untuk payment sandbox menggunakan simulator. klik link berikut:
Lalu input kode payment BCA di simulator seperti berikut:
Setelah itu akan muncul validasi seperti berikut:
Lalu klik pay. Jika berhasil, akan muncul seperti berikut:
Di snap, akan muncul payment success seperti berikut:
Kemudian jika kita check di sanbox dashboard midtrans, akan seperti berikut:
Selamat mencoba