Pada odoo, jika kita sedang mengedit suatu dokumen, kemudian melakukan klik pada sebuah tombol, walaupun itu bukan tombol Save, odoo akan langsung menyimpan dokumen tersebut, baru kemudian method dari tombol yang telah kita klik tadi dieksekusi oleh odoo. Dokumen tersebut akan berubah ke mode readonly, artinya kita tidak bisa mengedit lagi dokumen tersebut. Jika kita ingin mengubahnya, misal karena ada beberapa informasi yang salah kita harus klik tombol Edit.
Pada beberapa skenario, hal ini kadang terasa agak kurang user friendly, karena kadang kita memerlukan sebuah tombol untuk membantu user menginput beberapa data secara otomatis, tetapi data tersebut belum tentu perlu untuk disimpan oleh user. Misal untuk generate data berdasar kondisi tertentu, seperti membuat order line dari daftar produk-produk yang pernah dipesan oleh customer. Ketika daftar produk telah ditambah ke sales order, bukan berarti user ingin agar datanya langsung disimpan bukan ? Bisa jadi user hanya ingin agar odoo memberikan semacam rekomendasi, nanti user bisa memilih rekomendasi yang diberikan odoo disimpan atau tidak.
Tentu saja ketika data telah tersimpan user masih bisa mengubah data tersebut dengan menekan tombol Edit, tetapi user experience-nya akan jadi lebih baik jika daftar rekomendasi produk yang pernah dipesan customer berhasil digenerate tetapi dokumen tersebut tetap di edit mode, sehingga user bisa mereview dokumen sebelum klik tombol Save untuk benar-benar menyimpan dokumen tersebut.
Yang lebih mengganggu lagi, adalah saat dokumen tersebut dibuka di sebuah dialog/modal. Saat kita mengklik sebuah tombol di dialog/modal, dokumen tersebut akan langsung tersimpan kemudian dialog/modal tersebut akan di tutup oleh odoo. Memang sih kita bisa mengatur lewat python agar dokumen tersebut segera dibuka lagi, tetapi akan terjadi jeda sebelum dokumen tadi berhasil tampil lagi.
Saya sebenarnya sudah mencoba untuk memperbaiki masalah ini sejak odoo masih versi 12 (saya mulai bekerja sebagai programmer odoo ketika odoo masih versi 10/11). Tetapi karena tidak ada urgensinya, saya belum menerima laporan client komplain akan masalah ini, saya hanya mengerjakannya sebagai bagian dari aktivitas nge-blog saya. Sampai beberapa minggu sebelum tulisan ini ditulis, saat odoo sudah versi 14, saya masih belum menemukan solusinya.
Akhirnya setelah saya membuat beberapa widget di tempat kerja untuk odoo versi 14, dan menulis beberapa artikel tentang pemrograman javascript pada odoo di blog ini, saya mendapatkan sebuah inspirasi.
Solusi yang dapat saya temukan adalah untuk mengoverride method javascript yang dipanggil odoo ketika user klik pada sebuah tombol. Jika tombol tersebut ditandai dengan atribute tertentu maka saya akan membuat odoo untuk mentrigger fungsi onchange dan mencegah odoo untuk mengeksekusi fungsi Save. Jika tidak ditandai dengan attribute tersebut maka tombol tersebut akan dieksekusi secara normal.
Hasilnya adalah sebuh module yang saya beri nama button_no_save. Silakan download di sini. Saya juga telah membuat sebuah module demo untuk mendemonstrasikan cara kerja module button_no_save tersebut, baik di dokumen normal maupun dokumen yang dibuka di sebuah dialog/modal. Silakan download di sini
Bagaimana cara menggunakan module tersebut ?
Pertama anda harus mendownload module button_no_save di atas, kemudian install di server odoo anda. Kemudian buat sebuah field dengan tipe Char sebagai trigger saat tombol yang anda inginkan tidak membuat odoo menyimpan dokumen saat diklik.
trigger_field = fields.Char()
Lalu buat sebuah method dengan decorator @api.onchange(). Di mode edit saat sebuah tombol yang anda tandai dengan attribute custom yang dikenali oleh module button_no_save di klik, module button_no_save akan mentrigger fungsi onchange sehingga method ini seharusnya akan dieksekusi.
@api.onchange('trigger_field') def onchange_trigger_field(self): print('This method will be called in edit mode')
Lalu buat sebuah button dengan type object kemudian masukkan method di atas sebagai value dari attribute name.
<button name="onchange_trigger_field" string="Compute Result" type="object" />
Saat anda mengklik tombol Compute Result baik di edit maupun readonly mode, odoo akan mengeksekusi method onchange_trigger_field di atas.
Jika anda ingin agar odoo memanggil method yang berbeda di edit dan readonly mode, anda harus membuat method kedua yang tidak ditandai dengan decorator @api.onchange kemudian masukkan nama method tersebut sebagai value dari attribute name dari tombol yang anda buat. Ingat !!! Method yang ditandai dengan decorator @api.onchange bersifat mandatory, karena jika anda tidak menulisnya, module button_no_save akan gagal untuk mentrigger fungsi onchange di edit mode.
@api.onchange('trigger_field') def onchange_trigger_field(self): print('This method will be called in edit mode') def recompute_total(self): print('This method will be called in readonly mode')
<button name="recompute_total" string="Compute Result" type="object" />
Dari kode diatas, jika anda mengklik tombol Compute Result di edit mode odoo akan mengeksekusi method onchange_trigger_field, sedangkan jika anda mengklik tombol tesebut di readonly mode odoo akan mengeksekusi method recompute_total. Kenapa saya membuat module button_no_save bisa mengeksekusi method yang berbeda di edit dan readonly mode ? Karena di edit mode, saat method yang ditandai dengan decorator @api.onchange di eksekusi tidak semua record dari model anda sudah tersimpan di database, sehingga record tersebut ada kemungkinan tidak memiliki database id, id dari record tersebut bernilai False. Jika tombol diklik di readonly mode, sudah dipastikan semua record dari model anda sudah tersimpan di database, sehingga semua record memiliki database id. Oleh karena itu saya membuat module button_no_save dapat mengeksekusi method yang berbeda baik di edit mode atau readonly mode, untuk jaga-jaga barangkali anda menginginkan logic yang berbeda di kedua mode itu.
Selanjutnya masukkan field trigger yang telah anda buat ke form/view odoo, pastikan untuk membuat field itu invisible, karena field itu akan menyimpan tanggal dan jam kapan user mengklik tombol yang anda buat, agar tidak membingungkan user.
<field name="trigger_field" invisible="1" />
Langkah terakhir, tambah attribute triggeronchange dengan value nama field trigger anda di tombol yang telah anda buat.
<button name="recompute_total" string="Compute Result" type="object" triggeronchange="trigger_field" />
Berikut ini adalah screenshot saat user mengklik tombol yang ditandai dengan attribute triggeronchange di form normal.
Terlihat di tab Network dari developer tools, odoo telah memanggil fungsi onchange. Form/dokumen juga tidak berubah ke readonly mode, sehingga user masih bisa mengedit dokumen dan mereview-nya kembali, sebelum benar-benar yakin untuk mengklik tombol Save untuk menyimpan dokumen.
Berikut ini adalah screenshot saat user mengklik tombol yang ditandai dengan attribute triggeronchange di form/dokumen yang dibuka di sebuah dialog/modal.
Terlihat di tab Network dari developer tools, odoo telah memanggil fungsi onchange. Dialog/modal juga tidak ditutup oleh odoo, sehingga user masih bisa mengedit dokumen.
Kedua screenshot di atas adalah screenshot module demo dari module button_no_save. Saya sangat menyarankan anda untuk mendownload module tersebut untuk mencobanya di server odoo anda, untuk mengetahui module button_no_save adalah module yang anda butuhkan atau tidak.