144 lines
7.6 KiB
Markdown
144 lines
7.6 KiB
Markdown
# Migrasi printer_type ke printer_types
|
|||
|
|
|
||
|
|
1 Oktober 2026
|
||
|
|
|
||
|
|
## Ringkasan
|
||
|
|
|
||
|
|
`printer_type` (string) dihapus dan diganti `printer_types` (array string), sehingga satu produk bisa dicetak ke lebih dari satu printer. Contohnya "Paket Makan Minum" dengan `["kitchen", "bar"]` tercetak di kitchen dan bar sekaligus.
|
||
|
|
|
||
|
|
Ini breaking change. Setelah backend baru dirilis, client yang masih membaca `printer_type` tidak menerima printer apa pun. Karena itu app POS dan dashboard harus diupdate lebih dulu, lihat [Urutan rilis](#database-dan-urutan-rilis).
|
||
|
|
|
||
|
|
Yang perlu bertindak:
|
||
|
|
|
||
|
|
- **App POS**: baca `printer_types` dan cetak tiap item ke semua printer di dalamnya.
|
||
|
|
- **Dashboard admin**: ganti pilihan printer di form produk jadi multi-select yang mengirim `printer_types`.
|
||
|
|
|
||
|
|
## Perubahan response
|
||
|
|
|
||
|
|
`printer_type` hilang dari semua response dan digantikan `printer_types`, yang nilainya selalu array dan tidak pernah `null`.
|
||
|
|
|
||
|
|
| Endpoint | Letak field |
|
||
|
|
| --- | --- |
|
||
|
|
| `POST /api/v1/products`, `PUT /api/v1/products/:id`, `GET /api/v1/products`, `GET /api/v1/products/all`, `GET /api/v1/products/:id` | objek produk |
|
||
|
|
| `POST /api/v1/orders`, `GET /api/v1/orders`, `GET /api/v1/orders/:id`, `PUT /api/v1/orders/:id` | `order_items[]` |
|
||
|
|
| `POST /api/v1/orders/:id/add-items` | `added_items[]` dan `updated_order.order_items[]` |
|
||
|
|
| `POST /api/v1/self-order/orders`, `GET /api/v1/self-order/orders/:session_id` | `order_items[]` |
|
||
|
|
| `/api/v1/product-recipes` (semua yang mengembalikan recipe) | `product` |
|
||
|
|
| `/api/v1/inventory` | `product`, selalu `[]` karena produk di sini hanya berisi id dan nama |
|
||
|
|
|
||
|
|
Contoh satu item di `order_items[]`:
|
||
|
|
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"product_name": "Paket Makan Minum",
|
||
|
|
"printer_types": ["kitchen", "bar"],
|
||
|
|
"print_to_checker": true
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
Aturan nilainya:
|
||
|
|
|
||
|
|
- `printer_types: []` artinya produk tidak dicetak ke printer mana pun.
|
||
|
|
- Urutan printer sesuai yang disimpan admin, tanpa duplikat.
|
||
|
|
- Void, refund, payment, split bill, dan set customer tidak membawa data printer, sama seperti sebelumnya.
|
||
|
|
|
||
|
|
## Perubahan request produk
|
||
|
|
|
||
|
|
`POST /api/v1/products` dan `PUT /api/v1/products/:id` menerima `printer_types` sebagai pengganti `printer_type`. Kalau `printer_type` masih dikirim, field itu diabaikan tanpa error.
|
||
|
|
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"name": "Paket Makan Minum",
|
||
|
|
"category_id": "<uuid>",
|
||
|
|
"price": 25000,
|
||
|
|
"printer_types": ["kitchen", "bar"]
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
| Request | `printer_types` yang dikirim | Hasil |
|
||
|
|
| --- | --- | --- |
|
||
|
|
| Create | tidak dikirim | `["kitchen"]` |
|
||
|
|
| Create | `["kitchen", "bar"]` | `["kitchen", "bar"]` |
|
||
|
|
| Create | `[]` atau hanya string kosong | `["kitchen"]` |
|
||
|
|
| Update | tidak dikirim | tidak berubah |
|
||
|
|
| Update | `["bar"]` | `["bar"]`, seluruh daftar diganti |
|
||
|
|
| Update | `[]` | `[]`, produk tidak dicetak ke mana pun |
|
||
|
|
|
||
|
|
Sebelum disimpan, spasi di awal dan akhir tiap entri dibuang, lalu entri kosong dan duplikat dihapus. Urutan dipertahankan.
|
||
|
|
|
||
|
|
Tiap entri maksimal 50 karakter. Kalau lebih, request ditolak dengan error code `310` dan pesan `each printer_types entry cannot exceed 50 characters`.
|
||
|
|
|
||
|
|
## Migrasi app POS
|
||
|
|
|
||
|
|
App POS harus mengirim tiap item ke semua printer di `printer_types`, sehingga satu item bisa muncul di lebih dari satu tiket.
|
||
|
|
|
||
|
|
1. Ganti `printer_type` dengan `printer_types` (list string) di model order item dan produk.
|
||
|
|
2. Selama backend lama masih jalan, `printer_types` belum ada di response. Pakai `[printer_type]` kalau `printer_types` tidak ada, supaya app baru bisa dirilis sebelum backend.
|
||
|
|
3. Saat mencetak, kelompokkan item per printer dengan mengulang setiap entri `printer_types` milik item.
|
||
|
|
4. Item dengan `printer_types: []` tidak dicetak ke printer station mana pun.
|
||
|
|
5. `print_to_checker` tidak berubah dan tetap diperlakukan terpisah.
|
||
|
|
6. Untuk tambahan pesanan dari `POST /api/v1/orders/:id/add-items`, cetak dari `added_items[]`.
|
||
|
|
|
||
|
|
```text
|
||
|
|
tiket = {}
|
||
|
|
untuk setiap item di order_items:
|
||
|
|
printers = item.printer_types ?? [item.printer_type] // fallback hanya untuk backend lama
|
||
|
|
untuk setiap printer di printers:
|
||
|
|
tiket[printer].tambah(item)
|
||
|
|
untuk setiap (printer, items) di tiket:
|
||
|
|
cetak items ke printer
|
||
|
|
```
|
||
|
|
|
||
|
|
Perbaikan di `added_items[]`: sebelumnya field ini selalu berisi `product_name` dan printer kosong, serta `print_to_checker: true`. Sekarang isinya lengkap seperti item di `updated_order.order_items[]`, dengan urutan sesuai request. Kalau app selama ini mengakali dengan mencari item baru di `updated_order`, cara itu bisa diganti dengan `added_items[]` langsung.
|
||
|
|
|
||
|
|
## Migrasi dashboard
|
||
|
|
|
||
|
|
Form produk di dashboard harus memakai multi-select printer dan selalu mengirim daftar lengkapnya lewat `printer_types`.
|
||
|
|
|
||
|
|
1. Ganti dropdown printer tunggal dengan multi-select, misalnya checkbox, berisi pilihan printer yang sama.
|
||
|
|
2. Saat membuka form edit, isi pilihan dari `printer_types`. Selama backend lama masih jalan, pakai `[printer_type]` kalau `printer_types` tidak ada.
|
||
|
|
3. Saat menyimpan, kirim `printer_types` berisi semua printer yang dipilih.
|
||
|
|
4. Selama backend lama masih jalan, kirim juga `printer_type` berisi printer pertama. Backend lama hanya membaca `printer_type`, dan backend baru mengabaikannya.
|
||
|
|
5. Di daftar produk, tampilkan semua printer dari `printer_types`.
|
||
|
|
|
||
|
|
Backend tidak membatasi nilai printer. Nilainya harus sama persis dengan nama printer yang dikenal app POS, termasuk huruf besar dan kecilnya.
|
||
|
|
|
||
|
|
Create dengan `printer_types: []` tetap menghasilkan `["kitchen"]`. Produk tanpa printer dibuat dulu, lalu di-update dengan `printer_types: []`.
|
||
|
|
|
||
|
|
## Database dan urutan rilis
|
||
|
|
|
||
|
|
Migration `000099_add_printer_types_to_products` menambah kolom `products.printer_types` (JSONB, `NOT NULL`, default `["kitchen"]`), mengisinya dari `printer_type`, lalu menghapus kolom `printer_type` beserta index-nya.
|
||
|
|
|
||
|
|
- Produk dengan `printer_type` berisi nilai menjadi `[printer_type]`.
|
||
|
|
- Produk dengan `printer_type` `NULL` atau kosong menjadi `[]`.
|
||
|
|
|
||
|
|
Urutan rilis:
|
||
|
|
|
||
|
|
1. Rilis app POS baru, yang membaca `printer_types` dengan fallback ke `printer_type`, ke semua outlet.
|
||
|
|
2. Rilis dashboard baru, yang mengirim `printer_types` dan `printer_type`.
|
||
|
|
3. Jalankan migration `000099` tepat sebelum deploy backend baru. Di antara keduanya, backend lama gagal menyimpan produk karena kolom `printer_type` sudah tidak ada.
|
||
|
|
4. Setelah backend baru jalan, dashboard boleh berhenti mengirim `printer_type`, dan fallback di app POS boleh dihapus.
|
||
|
|
5. Atur produk multi-printer, misalnya "Paket Makan Minum" ke `["kitchen", "bar"]`.
|
||
|
|
|
||
|
|
Outlet yang masih memakai app POS lama setelah langkah 3 tidak menerima printer untuk semua item. Pastikan langkah 1 sudah selesai di semua outlet.
|
||
|
|
|
||
|
|
Rollback: jalankan down migration dan deploy backend lama bersamaan. Down migration membuat ulang kolom `printer_type` berisi printer pertama, lalu menghapus `printer_types`, jadi yang hilang hanya printer tambahan.
|
||
|
|
|
||
|
|
## Checklist
|
||
|
|
|
||
|
|
- [ ] App POS baru (dengan fallback) terpasang di semua outlet
|
||
|
|
- [ ] Dashboard baru mengirim `printer_types` dan `printer_type`
|
||
|
|
- [ ] Migration `000099` dan backend baru dirilis di staging
|
||
|
|
- [ ] Uji "Paket Makan Minum" dengan `["kitchen", "bar"]` tercetak di dua printer, saat order baru dan saat tambah pesanan
|
||
|
|
- [ ] Migration `000099` dan backend baru dirilis di production
|
||
|
|
- [ ] Dashboard berhenti mengirim `printer_type`
|
||
|
|
- [ ] Fallback `printer_type` di app POS dihapus
|
||
|
|
|
||
|
|
## FAQ
|
||
|
|
|
||
|
|
**Kenapa `printer_type` dihapus, bukan dipertahankan?** Supaya hanya ada satu sumber data printer. Dua field yang menyimpan hal yang sama bisa saling berbeda.
|
||
|
|
|
||
|
|
**Apakah kitchen dan bar menerima tiket yang sama?** Ya. Keduanya mencetak "Paket Makan Minum" lengkap dengan varian dan modifier-nya. Memecah isi paket per station butuh fitur bundle, yang di luar rilis ini.
|
||
|
|
|
||
|
|
**Apakah nilai printer dibatasi?** Tidak. Nilainya string bebas sampai 50 karakter, dan harus sama dengan nama printer di app POS.
|