docs: integration guides for mobile customer, POS, EnakGame and backoffice

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>
This commit is contained in:
efrilm
2026-10-08 11:10:05 +07:00
co-authored by Claude Opus 5.5
parent 1bb071aec6
commit b5d2cd491a
5 changed files with 2161 additions and 1 deletions
+142
View File
@@ -0,0 +1,142 @@
# 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.