Kali ini saya akan bercerita mengenai pengalaman saya menghadapi salah satu error yang aneh, unik, dan cukup memusingkan yang pernah saya alami selama berkarir sebagai sebagai Odoo developer. Selama hampir 5 tahun (saat artikel ini dibuat) saya baru menemui kasus ini sekali saja, dan baru saja terjadi beberapa bulan yang lalu. Kasusnya kira-kira seperti ini.
Anggaplah kita memiliki produk dengan nama “Stainless Steel Table” seperti pada gambar di bawah ini.
Di ERP (backend), jika kita mencari produk tersebut dengan keyword “Stainless”, “Steel”, atau “Table” produk tersebut ditemukan. Perhatikan beberapa gambar di bawah ini.
Hal aneh terjadi jika kita membuka halaman Point of Sale (POS). Perhatikan gambar di bawah ini.
Pada gambar di atas kita tidak melakukan pencarian dengan keyword apapun, maka produk akan tampil di halaman POS.
Jika kita mencari produk dengan keyword “Stainless” hasilnya seperti ini.
Jika kita mencari produk dengan keyword “Steel” atau “Table” hasilnya seperti ini.
Aneh kan ? Kenapa produk dengan nama “Stainless Steel Table” tiba-tiba jadi hilang dan tidak bisa di cari ?
Setelah menghabiskan waktu yang lumayan panjang, saya menemukan bahwa error ini terjadi karena nama produk tersebut mengandung line break atau new line. Saya menduga bahwa user menambahkan produk ini dengan cara import dari file spreadsheet, dan kebetulan nama produk di file tersebut mengandung line break atau new line. Saya tidak memiliki kesempatan untuk mewawancarai user secara langsung, sehingga saya tidak tahu alasan yang sebenarnya. Tetapi dari simulasi yang saya lakukan import dari file spreadsheet adalah alasan yang paling masuk akal.
Cara reproduce kasus ini kira-kira seperti ini: setelah kita mengetik kata “Stainless” pada kolom Name pada Libre Office tekan tombol CTRL + ENTER pada keyboard. Saya tidak tahu kalau di Microsoft Excel harus tekan tombol apa, coba googling dengan keyword excel insert new line in cell. Begitu juga dengan kata “Steel” dan “Table”. Kira-kira hasilnya akan seperti ini.
Setelah kita mengimport file spreadsheet tersebut, di database akan terlihat seperti pada gambar di bawah ini.
Dari gambar di atas terlihat jelas sekali antara produk yang namanya mengandung line break dan yang tidak. Sayangnya hal ini tidak terlihat jika kita melihat nama produk tersebut di Odoo, baik di backend atau POS, kecuali di PDF report.
Solusi untuk mengatasi error ini tentu saja dengan mengganti nama produk tersebut, agar tidak lagi mengandung line break atau new line. Atau dengan mengubah logic pencarian di Odoo POS. Saya akan membahasnya nanti, mari kita bahas mengapa hasil pencarian di Odoo backend dan Odoo POS berbeda terlebih dahulu.
Odoo POS didesain agar tetap bisa berjalan jika internet putus atau server down, sehingga system pencariannya murni dilakukan dengan Javascript dengan bantuan regex (regular expression). Sedangkan jika di backend system pencariannya dengan cara melalukan query ke database, sehingga hasil pencarian di 2 halaman ini berbeda.
Sekarang mari kita lihat kode yang menangani proses pencarian ini, silakan lihat method search_product_in_category di Odoo v13 ini. Saya menemukan error ini di Odoo v13, saya terus terang belum pernah mencobanya di Odoo v14 atau di Odoo v15. Tolong tulis komentar jika error ini juga terjadi di kedua versi tersebut, dan apakah solusi yang ditulis di artikel ini bisa diterapkan di sana atau tidak.
search_product_in_category: function(category_id, query){ try { query = query.replace(/[\[\]\(\)\+\*\?\.\-\!\&\^\$\|\~\_\{\}\:\,\\\/]/g,'.'); query = query.replace(/ /g,'.+'); var re = RegExp("([0-9]+):.*?"+utils.unaccent(query),"gi"); }catch(e){ return []; } var results = []; for(var i = 0; i < this.limit; i++){ var r = re.exec(this.category_search_string[category_id]); if(r){ var id = Number(r[1]); results.push(this.get_product_by_id(id)); }else{ break; } } return results; },
Dari kode di atas terlihat bahwa Odoo akan melakukan pencarian dengan regex pada variabel this.category_search_string. Sekarang mari kita lihat nilai dari variabel this.category_search_string ini dengan menambahkan kode console.log seperti pada kode di bawah ini.
search_product_in_category: function(category_id, query){ console.log(this.category_search_string[category_id]) try { query = query.replace(/[\[\]\(\)\+\*\?\.\-\!\&\^\$\|\~\_\{\}\:\,\\\/]/g,'.'); query = query.replace(/ /g,'.+'); var re = RegExp("([0-9]+):.*?"+utils.unaccent(query),"gi"); }catch(e){ return []; } var results = []; for(var i = 0; i < this.limit; i++){ var r = re.exec(this.category_search_string[category_id]); if(r){ var id = Number(r[1]); results.push(this.get_product_by_id(id)); }else{ break; } } return results; },
Hasilnya terlihat seperti ini.
21:cabinet with doors|e-com11 34:large meeting table|furn_6741|conference room table 53:stainless steel table 54:titanium chair
Text [21,34,53,54] di atas bisa kita simpulkan adalah id dari produk tersebut (id dari model product.product bukan model product.template). Silakan eksekusi query berikut untuk memastikannya.
select p_template.name, p_product.id from product_product as p_product join product_template as p_template on p_template.id = p_product.product_tmpl_id where p_product.id in (21,34,53,54);
Produk dengan nama “Stainless Steel Table” karena mengandung karakter line break atau new line nama produknya terpisah menjadi beberapa baris. Oleh karena itu saat kita melakukan pencarian dengan keyword “Stainless”, di baris tersebut masih terdapat id dari produk yang kita cari, sehingga produk tersebut muncul di hasil pencarian.
Sedangkan jika kita melakukan pencarian dengan keyword “Steel” atau “Table” di baris tersebut tidak terdapat id dari produk yang kita cari, sehingga produk tersebut tidak muncul di hasil pencarian.
Ada beberapa solusi yang dapat kita coba, salah satunya adalah dengan menghapus line break tersebut secara langsung di database, yaitu dengan cara menulis kode SQL. Secara pribadi saya lebih memilih untuk menghapusnya dengan kode Javascript, yaitu saat halaman POS dibuka. Dengan alasan: saya tidak perlu menulis perintah SQL lagi jika user menambah produk baru, atau memang penambahan line break tersebut disengaja oleh user, sehingga tampilan nama produk di PDF report seperti Delivery Slip tidak terlalu panjang.
Kita juga bisa meng-override method create dan write untuk menghapus line break ini. Atau abaikan saja, dan minta user untuk jualan pakai barcode scanner, karena error ini tidak terjadi jika kita melakukan pencarian produk dengan barcode scanner. Silakan bicarakan dengan team/client Anda, mana solusi yang paling ideal.
Berikut ini adalah kode yang saya gunakan untuk menghapus line break dengan Javascript saat POS dibuka.
odoo.define('remove_linebreak_in_product_name.pos_db', function (require) { "use strict"; var PosDB = require('point_of_sale.DB'); PosDB.include({ _product_search_string: function(product){ var result = this._super.apply(this, arguments); return result.replace(/(\r\n|\n|\r)/gm, ' ') + '\n'; }, }); });