# 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": "", "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.