Mengapa Server Menentukan Harga Setiap Pesanan
Klien dapat menampilkan harga, tetapi server harus menghitung dan mengesahkan total akhir pesanan.
Klien adalah perangkat input, bukan otoritas penetapan harga
Saat kami membangun alur pemesanan, kami memperlakukan setiap nilai yang diterima dari browser, aplikasi seluler, integrasi, atau terminal POS sebagai input yang harus divalidasi. Ini mencakup harga satuan, diskon, jumlah pajak, biaya pengiriman, dan total pesanan.
Klien dapat menampilkan harga untuk membantu pelanggan memutuskan apa yang akan dibeli. Klien tidak dapat dipercaya untuk menentukan jumlah yang harus dibayar pelanggan. Klien dapat dimodifikasi, menjalankan versi lama, tidak terhubung ke data pricing terbaru, atau memanggil API secara langsung dengan request yang disusun secara manual.
Jika API menerima total yang diberikan klien sebagai nilai otoritatif, sebuah request dapat mengubah unit_price dari 100 menjadi 1 sebelum checkout. Tidak diperlukan kelemahan pada antarmuka visual. Server hanya menerima nilai yang seharusnya dihitung sendiri.
Apa yang seharusnya dikirim oleh klien
Kami merancang request checkout berdasarkan niat pembelian, bukan hasil finansial. Klien biasanya seharusnya mengirim:
- Pengenal produk atau SKU
- Varian, opsi, dan kuantitas yang dipilih
- Identitas pelanggan atau akun jika relevan
- Detail pengiriman atau pengambilan
- Kode promosi atau kupon yang diberikan pelanggan
- Token metode pembayaran atau referensi pembayaran
Server kemudian memuat data produk yang sedang berlaku dan menghitung jumlah yang harus dibayar. Kami dapat menerima informasi harga dari klien untuk perbandingan tampilan, diagnostik, atau deteksi keranjang yang kedaluwarsa, tetapi tidak pernah sebagai sumber kebenaran.
Sebagai contoh, klien dapat mengatakan, “keranjang menampilkan 24,00.” Server harus merespons dengan perhitungannya sendiri lalu melanjutkan atau menjelaskan bahwa harga telah berubah.
Pricing lebih dari sekadar harga produk
Harga akhir sering bergantung pada aturan yang tidak seharusnya diterapkan secara mandiri oleh klien. Bahkan katalog yang sederhana dapat memerlukan keputusan mengenai:
- Mata uang dan pembulatan khusus mata uang
- Wilayah pajak, apakah pajak termasuk harga, dan pengecualian pajak
- Kontrak atau pricing khusus pelanggan
- Ketersediaan item dan aturan substitusi
- Biaya pengiriman, biaya layanan, dan aturan nilai pesanan minimum
- Pengembalian dana, kredit, kartu hadiah, dan saldo nilai tersimpan
Jika aturan ini diduplikasi di aplikasi web, seluler, dan POS, aturan tersebut akan menyimpang. Salah satu kanal pada akhirnya menerapkan aturan lama, membulatkan secara berbeda, atau melewatkan suatu pengecualian. Kami menyimpan perhitungan di server agar setiap kanal menggunakan aturan pricing yang sama.
Tiered pricing memerlukan perhitungan yang otoritatif
Tiered pricing adalah alasan umum mengapa perhitungan di klien menjadi tidak andal. Harga dapat berubah berdasarkan kuantitas, kelompok pelanggan, status langganan, lokasi, tanggal, atau gabungan kuantitas dari beberapa produk.
Klien mungkin menampilkan harga lebih rendah setelah pelanggan menambahkan unit yang cukup untuk mencapai tier tertentu. Sebelum pesanan diterima, server tetap harus memverifikasi bahwa tier tersebut memenuhi syarat dan menghitungnya dari keadaan keranjang akhir.
Perhitungan juga harus menetapkan cakupannya secara jelas. Tier dapat berlaku per baris item, per SKU, per kategori, atau untuk seluruh pesanan. Ini adalah aturan bisnis, bukan detail presentasi. Kami menempatkannya dalam logika pricing di sisi server dan menyimpan referensi aturan yang dievaluasi bersama pesanan ketika auditabilitas diperlukan.
Promotion engine harus berjalan di tempat yang dapat dikendalikan
Logika promosi memiliki kebutuhan yang serupa. Promotion engine mungkin perlu mempertimbangkan tanggal kelayakan, batas penggunaan, segmen pelanggan, pengecualian, kombinasi produk, dan apakah promosi dapat digabungkan.
Kami tidak mengandalkan klien untuk memutuskan apakah kupon valid atau apakah dua penawaran dapat digabungkan. Server mengevaluasi promotion engine terhadap pesanan yang sedang dibuat. Server menentukan:
- Promosi mana yang memenuhi syarat.
- Kombinasi promosi mana yang menghasilkan hasil yang diizinkan.
- Bagaimana setiap diskon dialokasikan ke seluruh baris pesanan.
- Apakah batas penukaran masih tersedia.
Ini juga penting ketika checkout terjadi secara bersamaan. Jika sebuah promosi memiliki jumlah penukaran terbatas, server perlu mencadangkan atau menggunakan kelayakan tersebut dalam transaksi yang terkendali. Pemeriksaan di sisi klien hanya dapat menjadi perkiraan karena pesanan lain dapat memakai sisa ketersediaan promosi lebih dahulu.
Client trust adalah batas keamanan
Client trust tidak menjadi lebih baik dengan menyembunyikan field pada antarmuka, menonaktifkan tombol, atau menyamarkan JavaScript. Kontrol tersebut dapat meningkatkan kemudahan penggunaan, tetapi tidak melindungi aturan pricing.
Siapa pun yang dapat mengirim request pesanan dapat memeriksa, mengulang, mengubah, atau membuat request. Hal ini normal untuk aplikasi klien publik. Karena itu kami merancang API sebagai berikut:
- Mengautentikasi pelaku ketika pricing bergantung pada identitas.
- Mengotorisasi akses ke produk, lokasi, dan harga khusus pelanggan.
- Menghitung ulang setiap nilai moneter di server.
- Memvalidasi stok dan kelayakan promosi saat pesanan dibuat.
- Menggunakan idempotency key agar request yang diulang tidak membuat pesanan atau tagihan ganda.
- Mencatat input harga, aturan yang diterapkan, dan total hasil yang diperlukan untuk menjelaskan pesanan kemudian.
Tujuannya bukan untuk mencurigai pelanggan secara pribadi. Tujuannya adalah menempatkan otoritas finansial dalam sistem yang kami kendalikan, dapat kami perbarui secara konsisten, dan dapat kami audit.
Sistem POS mengikuti aturan yang sama
Terminal POS tetap merupakan klien. Terminal tersebut mungkin dioperasikan oleh staf, bukan konsumen, tetapi dapat offline, kedaluwarsa, salah konfigurasi, atau terintegrasi dengan perangkat keras lokal yang memiliki batasannya sendiri.
Untuk POS online, kami menggunakan API pricing sisi server yang sama seperti kanal lainnya. POS mengirim item yang dipindai dan konteks pelanggan, lalu server mengembalikan penawaran yang disahkan atau membuat pesanan dengan total yang telah dihitung.
Operasi POS offline memerlukan trade-off yang eksplisit. Jika penjualan harus tetap berjalan tanpa konektivitas, perangkat mungkin memerlukan price book yang disimpan secara lokal dan subset promosi. Kami memperlakukannya sebagai otoritas operasional sementara dengan pengamanan, bukan sebagai bukti bahwa total lokal selalu benar secara permanen.
Desain offline yang praktis mencakup:
- Price book berversi dengan tanggal berlaku
- Batas yang jelas atas promosi mana yang dapat berjalan offline
- Catatan audit lokal untuk setiap penjualan dan penggantian nilai
- Rekonsiliasi dengan server saat sinkronisasi
- Kebijakan yang ditetapkan untuk konflik, harga yang berubah, pengembalian dana, dan pembaruan inventaris
Server tetap menjadi catatan jangka panjang untuk pesanan dan status finansialnya, bahkan ketika POS harus membuat keputusan lokal sementara.
Buat penawaran terlebih dahulu, lalu buat pesanan
Kami sering memisahkan pratinjau harga dari pembuatan pesanan. Endpoint penawaran memungkinkan klien menampilkan hasil yang dihitung server sebelum pembayaran. Klien kemudian dapat mengirim item yang dipilih, konteks pelanggan, kode promosi, pengenal penawaran, dan token pembayaran untuk membuat pesanan.
Penawaran harus memiliki masa berlaku terbatas dan konteks yang cukup untuk mendeteksi perubahan. Server tetap harus memvalidasi ulang saat pembuatan pesanan, terutama untuk inventaris, penggunaan promosi, pajak, dan pricing yang sensitif terhadap waktu. Penawaran berguna untuk kejelasan; penawaran bukan alasan untuk melewati validasi akhir.
Setelah pesanan diterima, kami menyimpan snapshot pricing. Snapshot ini biasanya mencakup harga satuan yang digunakan, diskon, hasil pajak, mata uang, metode pembulatan jika relevan, serta pengenal aturan pricing atau promosi yang diterapkan. Perubahan katalog di kemudian hari tidak boleh menulis ulang makna historis dari pesanan yang sudah diterima.
Aturan desain
Klien memiliki pengalaman berbelanja: klien menampilkan harga, mengumpulkan pilihan, dan menjelaskan hasilnya. Server memiliki keputusan finansial: server menetapkan pricing, menerapkan tiered pricing, mengevaluasi promotion engine, memvalidasi kelayakan, dan mencatat total akhir.
Batas ini menjaga kanal web, seluler, integrasi, dan POS tetap selaras. Yang lebih penting, batas ini menjadikan harga sebuah pesanan sebagai hasil dari aturan bisnis yang terkendali, bukan klaim yang dibuat oleh perangkat yang mengirim request.