D
P
0
← Semua artikel Read in English

WordPress & PHP di Produksi

Booking Sudah Dibayar Tapi Nyangkut di `approved`? `mark_booking_paid()` Cuma Kenal Satu Status Awal

· · 3 menit baca
Booking Sudah Dibayar Tapi Nyangkut di `approved`? `mark_booking_paid()` Cuma Kenal Satu Status Awal

Di sebuah platform booking penginapan, saya menambahkan alur baru: request-to-book. Sebelumnya tamu langsung pilih tanggal lalu bayar. Sekarang ada jalur kedua, tamu mengajukan permintaan, pemilik properti menyetujui dulu, baru tamu diminta membayar.

Alurnya jalan mulus sampai tahap terakhir. Tamu bayar, gateway bilang lunas, uangnya masuk. Tapi status booking-nya berhenti di approved. Tidak pernah pindah ke confirmed.

Gejalanya: lunas tapi belum jadi

Saya jalankan skenarionya pelan-pelan. Buat request, setujui dari sisi pemilik, lalu bayar sebagai tamu. Setelah pembayaran selesai, saya cek meta booking-nya:

_payment_status  = paid
_booking_status  = approved

Pembayaran benar-benar tercatat. Yang tidak terjadi cuma satu, transisi statusnya. Dan ini bukan masalah kosmetik, karena status booking-lah yang menentukan hampir semua hal setelahnya: apakah tamu dianggap punya reservasi sah, apakah tanggalnya terkunci sebagai booking final, dan bagaimana pemilik melihat daftar tamunya. Booking yang sudah dibayar tapi berdiri di approved itu berada di ruang antara yang tidak diakui siapa pun.

Tebakan pertama saya jelas: webhook pembayarannya tidak sampai. Tapi _payment_status sudah paid, jadi webhook-nya jelas datang dan handler-nya jelas jalan. Sesuatu di dalam handler itu yang memilih untuk tidak melakukan apa-apa.

Akar masalahnya: state machine yang cuma punya satu pintu masuk

Fungsi yang mengurus transisi setelah pembayaran adalah mark_booking_paid(). Fungsi itu ditulis waktu situsnya cuma punya satu jalur booking, yaitu bayar langsung. Di dunia lama itu, sebuah booking yang menunggu pembayaran selalu berstatus pending. Jadi kondisinya ditulis persis seperti asumsi itu:

// sebelum
if ( $status === 'pending' ) {
    confirm();
}

Satu status, satu pintu masuk. Selama request-to-book belum ada, tidak ada yang salah dengan baris itu.

Yang berubah adalah lifecycle-nya. Alur baru menyisipkan satu status di tengah, yaitu approved, yang artinya "pemilik sudah setuju, sekarang giliran tamu bayar". Jadi di jalur baru ini, status sebelum pembayaran bukan lagi pending, tapi approved.

Dan mark_booking_paid() tidak tahu apa-apa soal itu. Pembayaran masuk, fungsi dipanggil, statusnya dibaca, ternyata approved, kondisinya tidak terpenuhi, fungsi keluar tanpa bunyi. Tidak ada error, tidak ada log, tidak ada apa pun yang bilang "aku menolak transisi ini". Booking-nya cuma diam di tempat.

Ini pola yang khas waktu menambah state ke lifecycle yang sudah jalan. Kita sibuk memikirkan status barunya, memastikan dia bisa dibuat dan ditampilkan dengan benar, lalu lupa bahwa ada fungsi-fungsi lama di hilir yang menghardcode daftar status yang mereka terima. Fungsi itu tidak rusak. Dia cuma masih hidup di versi lifecycle sebelumnya.

Perbaikannya

Perbaikannya kecil, dan itu justru yang bikin lama ketemunya. Cukup ubah cara fungsi itu mengenali status yang layak dibayar, dari satu nilai jadi sebuah daftar:

// sesudah
if ( in_array( $status, array( 'pending', 'approved', '' ), true ) ) {
    confirm();
}

Tiga hal yang perlu dicatat dari baris itu.

Pertama, approved masuk daftar karena di alur request-to-book, itulah kondisi normal sebuah booking tepat sebelum dibayar. Bukan pengecualian, tapi jalur utama.

Kedua, string kosong ikut masuk. Itu untuk booking yang meta statusnya belum pernah terisi. Kalau tidak diakomodasi, booking semacam itu akan gagal dengan cara yang sama persis, lunas tapi tidak pernah confirmed.

Ketiga, in_array() dipakai dengan flag strict true. Tanpa itu, perbandingan longgar PHP bisa membuat nilai yang bukan string ikut lolos, dan di fungsi yang kerjanya memfinalkan pembayaran, kelonggaran semacam itu bukan hal yang Anda inginkan.

Setelah itu saya ulang lagi skenarionya dari nol: buat request, setujui, bayar. Hasilnya confirmed dan paid, seperti seharusnya. Jalur bayar langsung juga saya tes ulang karena kondisinya ikut berubah, dan pending tetap naik ke confirmed seperti sebelumnya.

Pelajaran