Tutorial selanjutnya adalah mengintegrasikan Payment Gateway di Laravel, menggunakan Midtrans sebagai contoh (salah satu payment gateway populer di Indonesia).
Langkah 1: Buat Akun di Midtrans
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.
Langkah 2: Instalasi Library Midtrans
Install Library Midtrans
Jalankan perintah berikut untuk menginstal library Midtrans menggunakan Composer:
composer require midtrans/midtrans-php
Langkah 3: Konfigurasi Midtrans di Laravel
Tambah Midtrans Config File
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),
];
Tambah Key di .env
Tambahkan 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
Tambahkan Service Provider
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');
}
Langkah 4: Edit Controller untuk Checkout
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'));
}
}
Langkah 5: Buat Route
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');
});
Langkah 6: Buat Views
Halaman Payment (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
Langkah 7: Testing Fitur
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