# Porting checkout produk publik

Tanggal: 17 Oktober 2026.

## Selesai

| Sumber `pos/` | Route CI4 (juga tersedia tanpa `.php`) | Handler |
| --- | --- | --- |
| `checkout.php` | `checkout.php` | `PublicCheckout::index` |
| `checkout_otp.php` | `checkout_otp.php` | `PublicCheckout::otp` |
| `checkout_success.php` | `checkout_success.php` | `PublicCheckout::success` |

Ketiga halaman terbuka untuk pengunjung, menggunakan sesi keranjang publik dan filter CSRF untuk POST. Respons tidak boleh disimpan cache. View mempertahankan ringkasan pesanan, informasi rekening toko, data pemesan, OTP/countdown, halaman sukses, tautan WhatsApp, dan laporan transfer.

`App\Libraries\PublicCheckout` mengelola pesanan dan transaksi. `CheckoutMessenger` mengirim satu kali melalui konfigurasi gateway global, tanpa mencatat isi OTP/respons gateway ke log aplikasi; TLS diverifikasi dan request dibatasi waktu. Tidak ada retry otomatis ketika hasil pengiriman tidak pasti. Kegagalan pengiriman ditampilkan di halaman OTP; pelanggan dapat membatalkan verifikasi dan mengulang setelah pembatasan waktu. Penerimaan gateway bukan bukti pesan sudah sampai.

## Perubahan dari sumber

- OTP enam digit berlaku 10 menit; database menyimpan hash di tabel challenge, bukan kode terbuka. Kolom kompatibilitas `online_orders.otp_code` diisi string kosong.
- Challenge diikat ke bukti acak dalam sesi; database menyimpan hash bukti. Mengirim ID/nomor order atau data pelanggan lewat POST tidak memberi akses pesanan lain.
- Maksimal lima percobaan OTP. Percobaan kelima yang salah mengakhiri challenge. Pengiriman dibatasi satu permintaan per menit dan lima per jam untuk pasangan toko/nomor telepon, dengan penguncian toko saat pemeriksaan.
- Submit ulang pesanan yang sama menggunakan challenge aktif yang sama tanpa membuat pesanan atau mengirim OTP lagi. Perubahan isi/data pemesan memerlukan pembatalan challenge sebelumnya; tautan tersedia di checkout.
- Konfirmasi mengunci toko, pesanan/challenge, dan produk dalam transaksi. Pesanan yang sudah dikonfirmasi dikembalikan tanpa membuat penjualan, mengurangi stok, atau mengirim pemberitahuan kedua.
- Produk harus aktif dan milik toko pesanan; stok harus mencukupi. Harga yang berubah mengharuskan pelanggan memperbarui keranjang dan memulai verifikasi baru. Tidak ada perubahan total diam-diam setelah pelanggan menerima ringkasan.
- Penjualan menyimpan snapshot harga, data telepon, item, waktu verifikasi, sumber `pasar`, status pesanan `belum bayar`, dan pembayaran `unpaid` (bila kolom tersedia). Produk `is_paused` mengikuti aturan pembekuan perubahan stok aplikasi.
- Data pelanggan disimpan setelah OTP benar, di dalam transaksi yang sama. Autofill data pelanggan publik melalui nomor telepon dihapus dari view; data pelanggan tidak dibuka sebelum verifikasi nomor.
- Bila toko tidak memiliki pengguna aktif, pesanan tidak dikonfirmasi tanpa penjualan. Kesalahan saat menyimpan penjualan/detail/stok membatalkan transaksi; detail database tidak ditampilkan ke pelanggan.
- Pengiriman OTP dan pemberitahuan pemilik berlangsung setelah commit. Kegagalan pemberitahuan tidak membatalkan pesanan yang sudah tersimpan.
- Laporan “Saya sudah transfer” hanya mengubah status menjadi `proses cek` dan mencatat history bila tabel tersedia. Tidak menandai pembayaran lunas. Laporan berulang tidak mengirim notifikasi lagi dan tidak menurunkan pesanan yang telah melewati status awal.

## Database dan deployment

Pada submit checkout, `schema()` membuat `online_orders` bila belum ada dan tabel baru `online_checkout_challenges`, memakai InnoDB. Tabel yang sudah ada tidak diubah oleh CREATE IF NOT EXISTS. Struktur `online_orders` lama harus memuat kolom sumber (termasuk `order_status`, `sale_id`, dan waktu OTP). Helper kompatibilitas kolom sales/snapshot dijalankan sebelum transaksi. Tidak ada DDL di tengah transaksi konfirmasi.

Tabel pesanan, challenge, toko, pelanggan, produk, sales, sale_details dan history harus mendukung transaksi/row lock (InnoDB). Siapkan hak DDL untuk pembuatan tabel/kolom kompatibilitas atau terapkan skemanya terlebih dahulu melalui proses deployment. Gunakan konfigurasi zona waktu PHP/aplikasi dan database yang sesuai untuk batas waktu OTP. Gateway global memakai konfigurasi WA aplikasi; tidak bergantung pada sesi toko kasir.

Pesanan OTP tertunda dari aplikasi lama tidak dapat dilanjutkan karena tidak mempunyai challenge/bukti sesi baru. Mulai ulang dari keranjang pada CI.

## Validasi

- **346 tes / 2.415 assertion lulus**, termasuk tambahan **29 tes / 105 assertion** checkout.
- Cakupan tambahan: route dan CSRF, total dari server, hash dan bukti sesi, duplikasi submit/konfirmasi, batas kirim, OTP salah/kedaluwarsa, perubahan harga/stok, rollback detail dan laporan transfer, toko tanpa pengguna, penyimpanan pelanggan, perpindahan state sesi, serta render ketiga halaman.
- Lint **355 file PHP** bersih. JavaScript ketiga view lulus `node --check`.
- Pengujian memakai koneksi database tiruan dan pengirim pengganti; belum menguji database aplikasi, konkurensi koneksi MySQL nyata, browser, atau pengiriman WhatsApp sebenarnya. Tidak ada pesanan/pesan nyata dibuat dalam validasi ini.

## Sisa porting

Tiga file checkout selesai; dari 17 file sebelumnya kini tersisa **14 file utama/publik**:

`booking_api.php`, `checkout_rental.php`, `checkout_rental_otp.php`, `checkout_rental_special.php`, `checkout_rental_success.php`, `forgot_password.php`, `order_meja.php`, `pricing.php`, `register.php`, `store_rental.php`, `store_rental_schedule.php`, `tracking.php`, `upgrade.php`, `web1.php`.

Tahap berikutnya katalog rental, jadwal, dan booking/checkout rental sebagai satu alur. Beranda pencarian publik (`web1.php`) dan tautan rental dari katalog belum selesai.

## Pembaruan katalog rental — 17 Oktober 2026

`store_rental.php` dan `store_rental_schedule.php` sudah diporting. Sisa terbaru **12 file**; lihat [PORTING_KATALOG_RENTAL.md](PORTING_KATALOG_RENTAL.md). Daftar 14 file di atas mencatat kondisi saat tahap checkout produk selesai.

## Status akhir — 17 Oktober 2026

Seluruh file PHP yang tersisa sudah diporting. Sisa terbaru **0**; lihat [PORTING_SELESAI.md](PORTING_SELESAI.md) dan [PORTING_INVENTARIS.md](PORTING_INVENTARIS.md). Angka sisa di atas adalah catatan historis tahap ini.
