Integrasi Midtrans dan Laravel 8 Menggunakan Snap: Bagian 2

Sebelum melanjutnya membaca, silahkan baca bagian 1: Integrasi Midtrans dan Laravel 8 Menggunakan Snap: Bagian 1.

Di bagian 1, kita sudah berhasil mengintegrasikan interface atau tampilan pembayaran Midtrans menggunakan Snap. Sampai disana, customer sudah bisa melakukan pembayaran melalui berbagai channel pembayaran yang tersedia. Di posting ini, kita akan melanjutkan untuk membuat callback pembayaran.

Apa itu callback? Pada bagian 1, customer sudah dapat melakukan pembayaran. Misalnya menggunakan virtual account. Setelah customer berhasil melakukan pembayaran, Midtrans akan mengirim notifikasi ke web kita bahwa customer sudah melakukan pembayaran. Atau, jika customer tidak juga melakukan pembayaran sampai batas waktu yang ditentukan, Midtrans akan mengirim notifikasi bahwa transaksi sudah kadaluarsa. Tugas kita, adalah menerima notifikasi tersebut dan memproses notifikasi tersebut.

Misalnya, setelah customer berhasil membayar, kita akan menerima notifikasi berhasil. Dari notifikasi tersebut, kita bisa mengubah status pembayaran order dari yang sebelumnya menunggu pembayaran menjadi sudah dibayar. Dengan sistem ini, tidak perlu lagi melakukan konfirmasi dan mengubah status pembayaran secara manual.

Daftar Isi

Membuat Service Class

Sama seperti sebelumnya, logic utama akan kita pisahkan di service layer. Sebelumnya, kita sudah membuat file Midtrans.php, CreateSnapTokenService.php dan CallbackService.php, untuk callback akan kita tulis di file CallbackService.php

<?php

namespace App\Services\Midtrans;

use App\Models\Order;
use App\Services\Midtrans\Midtrans;
use Midtrans\Notification;

class CallbackService extends Midtrans
{
	protected $notification;
	protected $order;
	protected $serverKey;

	public function __construct()
	{
		parent::__construct();

		$this->serverKey = config('midtrans.server_key');
		$this->_handleNotification();
	}

	public function isSignatureKeyVerified()
	{
		return ($this->_createLocalSignatureKey() == $this->notification->signature_key);
	}

	public function isSuccess()
	{
		$statusCode = $this->notification->status_code;
		$transactionStatus = $this->notification->transaction_status;
		$fraudStatus = !empty($this->notification->fraud_status) ? ($this->notification->fraud_status == 'accept') : true;

		return ($statusCode == 200 && $fraudStatus && ($transactionStatus == 'capture' || $transactionStatus == 'settlement'));
	}

	public function isExpire()
	{
		return ($this->notification->transaction_status == 'expire');
	}

	public function isCancelled()
	{
		return ($this->notification->transaction_status == 'cancel');
	}

	public function getNotification()
	{
		return $this->notification;
	}

	public function getOrder()
	{
		return $this->order;
	}

	protected function _createLocalSignatureKey()
	{
		$orderId = $this->order->number;
		$statusCode = $this->notification->status_code;
		$grossAmount = $this->order->total_price;
		$serverKey = $this->serverKey;
		$input = $orderId . $statusCode . $grossAmount . $serverKey;
		$signature = openssl_digest($input, 'sha512');

		return $signature;
	}

	protected function _handleNotification()
	{
		$notification = new Notification();

		$orderNumber = $notification->order_id;
		$order = Order::where('number', $orderNumber)->first();

		$this->notification = $notification;
		$this->order = $order;
	}
}

Pada service tersebut, kita menangkap notifikasi yang dikirim Midtrans dengan method _handleNotification(), kemudian hasil notifikasi akan diolah kembali. Disini kita juga perlu membuat local signature key. Key ini merupakan kunci lokal supaya notifikasi dapat diterima. Saat mengirim notifikasi, Midtrans juga akan mengirim signature key, key tersebut akan dibandingkan dengan local signature key untuk memverifikasi apakah request tersebut valid atau tidak.

Membuat Controller Callback

Untuk menerima notifikasi, kita akan membuat controller khusus dengan nama PaymentCallbackController. Pada terminal, ketikkan perintah berikut:

php artisan make:controller PaymentCallbackController

Kemudian tulis kode berikut pada controller tadi.

<?php

namespace App\Http\Controllers;

use App\Models\Order;
use Illuminate\Http\Request;
use App\Services\Midtrans\CallbackService;

class PaymentCallbackController extends Controller
{
    public function receive()
    {
        $callback = new CallbackService;

        if ($callback->isSignatureKeyVerified()) {
            $notification = $callback->getNotification();
            $order = $callback->getOrder();

            if ($callback->isSuccess()) {
                Order::where('id', $order->id)->update([
                    'payment_status' => 2,
                ]);
            }

            if ($callback->isExpire()) {
                Order::where('id', $order->id)->update([
                    'payment_status' => 3,
                ]);
            }

            if ($callback->isCancelled()) {
                Order::where('id', $order->id)->update([
                    'payment_status' => 4,
                ]);
            }

            return response()
                ->json([
                    'success' => true,
                    'message' => 'Notifikasi berhasil diproses',
                ]);
        } else {
            return response()
                ->json([
                    'error' => true,
                    'message' => 'Signature key tidak terverifikasi',
                ], 403);
        }
    }
}

Di controller ini, kita harus memeriksa apakah signature key terverifikasi atau tidak. Selanjutnya, pada service callback kita memiliki 3 method, yaitu isSusscess() untuk memeriksa apakah transaksi berhasil, isExpire() untuk memeriksa apakah transaksi sudah kadaluarsa, isCancelled() untuk memeriksa apakah transaksi dibatalkan. Jika sukses, maka update data status order menjadi 2 (sudah dibayar), jika kadaluarsa, update data status order menjadi 3 (kadaluarsa), dan jika kadaluarsa maka update data status order menjadi 3. Kamu juga bisa menambah logic lain sesuai keperluan.

Catatan keamanan

Alur program yang saya buat cukup aman untuk digunakan. Bahkan jika siapapun mengetahui URL callback, orang tersebut tidak akan bisa “menembak” secara langsung, karena perlu menyertakan header authentikasi berupa signature key yang merupakan kombinasi dari ID Order, kode status, harga keseluruhan dan server key. Jadi, jangan biarkan siapapun mengetahui servey key Midtrans kamu.

Membuat Route

Setelah membuat controller, kita harus membuat route baru. Nantinya Midtrans akan mengirimkan post request ke route tersebut. Pada route web.php, tambahkan route berikut.

use App\Http\Controllers\PaymentCallbackController; // => letakkan dibagian atas

Route::post('payments/midtrans-notification', [PaymentCallbackController::class, 'receive']);

Midtrans akan mengirim notifikasi ke alamat: http://domainsaya.com/payments/midtrans-notification. Tapi disini kita tidak akan mendeploy untuk menguji coba, tapi akan menggunakan tunel.

Membuat pengecualian CSRF

Karena berada di route web, setiap post request akan dilindungi oleh CSRF. Artinya, route yang kita buat diatas tidak akan bisa diakses oleh Midtrans. Untuk itu, kita harus mengecualikan route tersebut dari proteksi CSRF. Pada file app/Http/Middleware/VerifyCsrfToken.php tambahkan route diatas untuk dikecualikan, sehingga akan menjadi seperti berikut.

protected $except = [
    'payments/midtrans-notification',
];

Jika sudah, selanjutnya adalah menguji.

Menginstal Ngrok untuk Tunelling

Karena Laravel kita masih ada di localhost (masih offline), tentu saja Midtrans tidak bisa mengirim pemberitahuan. Untuk itu, kita harus mengonlinekan Laravel tersebut. Caranya bisa dengan mengupload ke server supaya bisa online dan bisa diakses. Tapi disini saya tidak akan mengupload ke server, dan tetap menggunakan localhost. Caranya adalah menggunakan Ngrok.

Apa itu Ngrok? Ngrok adalah sebuah aplikasi tunelling yang dapat “mengonlinekan localhost”. Ngrok bisa membuat laravel kita di localhost (offline) menjadi online dan bisa diakses siapapun di internet, cukup dengan mengetikkan URL yang diberikan Ngrok. Karena itu, kita akan memanfaatkan Ngrok untuk menguji callback Midtrans.

Catatan

Ngrok hanya digunakan untuk pengujian secara offline, jika sudah siap digunakan dan diupload ke server, tidak ada konfigurasi apapun yang perlu diubah. Cukup ganti alamat tunel ngrok dengan domain kamu.

Download dan install Ngrok

Untuk mendownload, silahkan buka webiste ngrok.com dan navigasi ke halaman download. Kemudian download sesuai sistem operasi kamu. Untuk installasi, silahkan ikuti panduan di masing-masing sistem operasi. Jika di Windows, tinggal klik-klik saja seperti biasa.

Integrasi Midtrans dan Laravel 8 Menggunakan Snap: Bagian 2
Download ngrok di ngrok.com

Jika sudah, silahkan mendaftar untuk mendapatkan auth token. Jika sudah mendaftar, buka dasbor Ngrok untuk mendapatkan auth token.

Integrasi Midtrans dan Laravel 8 Menggunakan Snap: Bagian 2
Token auth Ngrok

Silahkan catat token tersebut. Kemudian pada CMD / terminal ketikkan perintah berikut

ngrok authtoken TOKEN_AUTH_NGROK
Integrasi Midtrans dan Laravel 8 Menggunakan Snap: Bagian 2
Token auth Ngrok

Jika berhasil, kita akan melanjutkan ke tahap berikutnya.

Membuat Server Lokal dan Tunel

Untuk membuat server lokal, kita akan menggunakan perintah artisan serve dari laravel dengan port 8080 (bukan 8000).

php artisan serve --port=8080

Maka akan terbuat server lokal baru dengan port 8080. (http://localhost:8080)

Membuat tunel ngrok

Untuk mengonlinkan localhost yang sebelumnya sudah dibuat, pada cmd ketikkan perintah berikut:

ngrok http 8080

Perintah tersebut akan memforward semua request ke port 8080, atau port Laravel yang tadi sudah dibuat. Jika berhasil akan seperti berikut.

Integrasi Midtrans dan Laravel 8 Menggunakan Snap: Bagian 2
Hasil tunelling ngrok

Silahkan catat URL forwarding yang diberikan Ngrok, cukup salah satu saja. Disini saya mendapatkan URL: http://b674-110-137-75-3.ngrok.io/. URL ini sudah bisa diakses siapapun di internet. URL ini yang nanti akan kita berikan kepada Midtrans untuk mengirim notifikasi. Untuk melihat riwayat request yang masuk, silahkan buka: http://localhost:4040/

Konfigurasi URL Notifikasi di Dasbor Midtrans

Buka dasbor Midtrans, pada bagian Pengaturan > Konfigurasi, pada bidang Payment Notification URL isikan seperti berikut.

Integrasi Midtrans dan Laravel 8 Menggunakan Snap: Bagian 2
Notifikasi URL Midtrans

Silahkan sesuaikan dengan URL ngrok kamu. Jika sudah, sekarang seharusnya sudah siap diuji.

Catatan

Ngrok hanya digunakan untuk pengujian secara offline, jika sudah siap digunakan dan diupload ke server, tidak ada konfigurasi apapun yang perlu diubah. Cukup ganti alamat tunel ngrok dengan domain kamu. Misalnya jika diupload di domain https://jurnalmms.web.id, cukup ganti ke: https://jurnalmms.web.id/payments/midtrans-notification

Melakukan Pengujian

Untuk menguji pembayaran, kita bisa memanfaatkan simulator yang disediakan Midtrans. Dengan simulator, kita bisa melakukan pembayaran tanpa harus melakukan pembayaran asli. Midtrans Mock bisa diakses disini.

Mendapatkan nomor rekening tujuan

Pertama, kita harus mendapatkan nomor rekening tujuan. Caranya buka halaman order, kemudian klik tombol “Bayar sekarang”, pilih channel pembayaran dan catat nomor rekening yang ditampilkan.

Integrasi Midtrans dan Laravel 8 Menggunakan Snap: Bagian 2
Nomor rekening untuk uji coba

Karena nomor tersebut adalah Virtual Account BRI, pada website Mock Payment Midtrans pilih “BRI Virtual Account” di dropdown Payment Page.

Integrasi Midtrans dan Laravel 8 Menggunakan Snap: Bagian 2
Mock Payment BRI Virtual Account

Kemudian pada kolom input masukkan nomor rekening yang didapatkan sebelumnya. Kemudian klik tombol Inquire. Dihalaman berikutnya klik tombol Pay untuk membayar. Jika sudah berhasil masuk ke halaman success page, artinya simulasi pembayaran sudah berhasil dilakukan.

Untuk melihat riwayat, silahkan buka http://localhost:4040 dan lihat riwayat request yang masuk melalui Ngrok.

Sampai disini, kita sudah berhasil menerima notifikasi dari Midtrans. Status pembayaran di database juga sudah akan berubah otomatis.

Saat mulai menguji, mungkin akan terdapat masalah signature key tidak terverifikasi. Salah satu cara mengatasinya, pastikan harga yang dibayar customer sama dengan kolom total_price yang ada di database.

Di posting bagian 3, kita akan mencatat riwayat notifikasi yang dikirimkan Midtrans. Terima kasih dan sampai jumpa.

Semua kode program dapat dilihat pada repository GitHub berikut:

https://github.com/mulyosyahidin/laravel-midtrans

8 thoughts on “Integrasi Midtrans dan Laravel 8 Menggunakan Snap: Bagian 2

  1. azwar

    assalamualikumpak saya mau menyakan tentang perbedaan environment sandbox dan environment production pada mitras karena kan bapak pake sanbox,tolong penjelasnaya pak terimaksih

    Reply
    1. Martin Mulyo Syahidin Post author

      Waalaikumsalam warrahmatullahi wabarakatuh.

      Untuk environment sandbox digunakan saat masih development / pengembangan, sedangkan env production saat sudah ready digunakan (siap menerima pembayaran). Saat menggunakan env sandbox, kita bisa melakukan pembayaran “dummy” menggunakan simulator pembayaran. Jadi yg sandbox digunakan saat pengembangan dan uji coba saja.

Tinggalkan Balasan

Alamat email Anda tidak akan dipublikasikan. Ruas yang wajib ditandai *