One guide per team, covering EnakPoint, EnakCoin, EnakGame and vouchers: - integration-mobile-customer.md: wallet, history (with the game and voucher ledger types), push, PIN, exchange, transfer, game list and webview, play history, voucher catalog, redeem and my vouchers. - integration-pos.md: linking customers to orders, earning, receipts, void/refund, and vouchers as a known gap (no POS endpoint to mark one used). - integration-enakgame.md: the Phaser client's side of a play: start with Idempotency-Key, complete, rewards, spin, expiry and refunds, retries. - integration-backoffice.md: loyalty settings and customer wallets, plus games, reward configs, spin setup, budgets, metrics and recommendations, events, vouchers and code import, analytics. The JS bridge between the app and the game is a proposal both teams still have to agree on. Replaces api-enakpoint.md, integration-enakpoint.md, mobile-customer-enakpoint.md, backoffice-enakpoint.md and enakgame-spin.md. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
143 lines
5.9 KiB
Markdown
143 lines
5.9 KiB
Markdown
# Integrasi POS: EnakPoint, EnakCoin & Voucher
|
||
|
||
**Untuk:** tim aplikasi POS (kasir) · **Base URL:** `/api/v1` · **Per:** 8 Okt 2026
|
||
|
||
Kamu mengerjakan aplikasi **POS** yang dipakai kasir di outlet. Dokumen ini menjelaskan
|
||
bagian program loyalitas yang menyentuh POS: mengaitkan customer ke order, menampilkan
|
||
EnakPoint dan EnakCoin yang didapat, void/refund, dan voucher. Jangan mengarang
|
||
endpoint, field, atau aturan yang tidak tertulis di sini; kalau ada yang kurang jelas,
|
||
tanyakan ke tim backend.
|
||
|
||
Dokumen ini menggantikan bagian POS di `integration-enakpoint.md` dan `api-enakpoint.md`.
|
||
|
||
---
|
||
|
||
## 1. Yang perlu diketahui kasir
|
||
|
||
| | EnakPoint (`POINT`) | EnakCoin (`COIN`) |
|
||
|---|---|---|
|
||
| Didapat dari | Belanja (order lunas), hasil tukar EnakCoin, koreksi admin | Belanja, hadiah game, koreksi admin |
|
||
| Dipakai untuk | **Ditukar ke voucher** di aplikasi customer | Main game, ditukar ke EnakPoint |
|
||
| Bisa membayar order | **Tidak** | **Tidak** |
|
||
|
||
- **EnakPoint bukan alat bayar.** Tidak ada payment method EnakPoint di POS, dan saldo
|
||
tidak bisa dicairkan. Customer menukar EnakPoint ke voucher di aplikasinya sendiri.
|
||
- Saldo berlaku di **semua outlet** organisasi. Berapa yang didapat per order diatur
|
||
**per outlet** oleh owner di backoffice.
|
||
- Semua jumlah bilangan bulat.
|
||
|
||
---
|
||
|
||
## 2. Mengaitkan customer ke order
|
||
|
||
Earning hanya terjadi bila order dikaitkan ke customer terdaftar. Order tanpa customer,
|
||
dengan **customer default (walk-in)**, atau dengan customer nonaktif tidak mendapat
|
||
apa-apa.
|
||
|
||
1. **Cari customer:** `GET /api/v1/customers?search=0812…&page=1&limit=20`
|
||
(cocok dengan nama, email, atau nomor HP). Abaikan customer dengan `is_default: true`.
|
||
2. **Kaitkan** dengan salah satu cara:
|
||
- saat membuat order: `POST /api/v1/orders` dengan `"customer_id": "…"`, atau
|
||
- setelah order dibuat: `PUT /api/v1/orders/:id/customer` dengan
|
||
`{ "customer_id": "…" }`.
|
||
|
||
**Kaitkan sebelum order lunas.** Earning dihitung saat order menjadi lunas penuh.
|
||
Customer yang dikaitkan setelah lunas tetap mendapat earning lewat job susulan yang
|
||
berjalan tiap 30 menit untuk order lunas 72 jam terakhir, tapi tidak langsung, sehingga
|
||
struk akan menulis 0.
|
||
|
||
---
|
||
|
||
## 3. Earning: yang didapat dari order
|
||
|
||
Earning berjalan otomatis di backend saat order lunas lewat jalur pembayaran mana pun
|
||
(`POST /payments`, update order, split bill). POS tidak memanggil apa-apa.
|
||
|
||
- **Basis** = `subtotal − discount_amount`, **sebelum pajak** dan biaya lain.
|
||
- Rumus per outlet (diatur owner): mode `PER_AMOUNT`
|
||
`floor(basis ÷ earn_per_amount) × earn_value`, atau mode `PERCENTAGE`
|
||
`floor(basis × earn_percent ÷ 100)`, dengan minimal belanja dan batas per order.
|
||
- Contoh: basis Rp 87.500, outlet memberi 1 EnakPoint per Rp 100 dan 1 EnakCoin per
|
||
Rp 25.000 → **875 EnakPoint** dan **3 EnakCoin**.
|
||
|
||
Response order (`GET /api/v1/orders/:id` dan response order lainnya) membawa:
|
||
|
||
```json
|
||
{ "points_earned": 875, "coins_earned": 3 }
|
||
```
|
||
|
||
Keduanya 0 bila order tidak mendapat apa-apa. **Cetak di struk**, mis. "Kamu mendapat
|
||
875 EnakPoint & 3 EnakCoin". Ambil nilainya setelah pembayaran terakhir berhasil; bila
|
||
masih 0 padahal customer sudah dikaitkan, earning akan menyusul (§2).
|
||
|
||
---
|
||
|
||
## 4. Void dan refund
|
||
|
||
Tidak ada langkah tambahan di POS. Saat order di-void atau direfund, backend menarik
|
||
kembali yang didapat dari order itu (mutasi `EARN_REVERSAL` di riwayat customer):
|
||
|
||
| Kejadian | Yang ditarik |
|
||
|---|---|
|
||
| Void | Semua EnakPoint dan EnakCoin dari order itu |
|
||
| Refund (sebagian atau penuh) | `floor(earned × total_refund ÷ basis)`, tidak pernah lebih dari yang didapat; refund berikutnya hanya menarik sisanya |
|
||
|
||
Bila saldo customer sudah terpakai, yang ditarik sebanyak yang ada. **Refund tidak
|
||
pernah diblokir** karena ini.
|
||
|
||
---
|
||
|
||
## 5. Voucher dari EnakPoint
|
||
|
||
Customer menukar EnakPoint ke voucher di aplikasi customer. Voucher yang didapat tampil
|
||
di menu "Voucher saya" di aplikasi itu, dengan nama, nilai (`face_value`), jenis, dan
|
||
bila ada, **kode** serta tanggal berlakunya.
|
||
|
||
> **Belum tersedia:** POS belum punya endpoint untuk **mengecek** atau **menandai
|
||
> voucher sudah dipakai**. Ini pekerjaan lanjutan di backend.
|
||
|
||
Sampai endpoint itu ada:
|
||
|
||
1. Kasir melihat voucher di layar aplikasi customer (nama, nilai, kode, masa berlaku).
|
||
2. Kasir memasukkan potongannya sebagai **diskon biasa** di order, sesuai jenisnya:
|
||
|
||
| `voucher_type` | Cara memasukkan |
|
||
|---|---|
|
||
| `FIXED_VALUE` | Diskon nominal sebesar `face_value` |
|
||
| `PERCENTAGE` | Diskon persen sesuai syarat voucher |
|
||
| `FREE_ITEM` | Item gratis sesuai syarat voucher |
|
||
| `MERCHANT_BENEFIT` | Sesuai syarat voucher |
|
||
|
||
3. Karena backend belum mencatat voucher terpakai, outlet perlu mencatat kode yang
|
||
sudah dipakai secara manual supaya voucher yang sama tidak dipakai dua kali.
|
||
|
||
Diskon dari voucher mengurangi basis earning seperti diskon lain (§3).
|
||
|
||
---
|
||
|
||
## 6. Yang sudah dihapus
|
||
|
||
Bayar dengan EnakPoint dihapus pada 7 Okt 2026. Jangan dipanggil atau ditampilkan lagi;
|
||
tidak ada penggantinya.
|
||
|
||
| Dihapus | Catatan |
|
||
|---|---|
|
||
| Payment method tipe `point` ("EnakPoint") | Tidak ada di daftar payment method |
|
||
| Field `points` dan `payment_code` di `POST /payments` | `amount` wajib seperti pembayaran lain |
|
||
| `GET /orders/:id/point-payment/preview` | – |
|
||
| Kode bayar dari aplikasi customer | – |
|
||
| `points_used`, `point_value` di response pembayaran | – |
|
||
| `point_amount`, `points_used`, `total_with_points`, `counts_as_cash_in` di laporan payment method | `summary.total_amount` adalah total semua method |
|
||
|
||
---
|
||
|
||
## 7. Checklist
|
||
|
||
- [ ] Kasir bisa mencari dan mengaitkan customer ke order sebelum pembayaran.
|
||
- [ ] Customer default (walk-in) tidak ditawarkan sebagai pemilik earning.
|
||
- [ ] Struk mencetak `points_earned` dan `coins_earned`.
|
||
- [ ] Tidak ada payment method EnakPoint dan tidak ada field pembayaran EnakPoint di
|
||
request.
|
||
- [ ] Void/refund tidak menampilkan langkah tambahan untuk EnakPoint/EnakCoin.
|
||
- [ ] SOP outlet untuk voucher manual (§5) sudah disepakati sampai endpoint POS tersedia.
|