Menguji Domain pada Odoo

Pada odoo Domain adalah list yang berisi ekspresi tertentu yang digunakan untuk memfilter suatu data dari database. Umumnya domain akan diterjemahkan oleh odoo menjadi ekspresi SQL untuk mengisi klausa where. Misal kita memiliki domain seperti dibawah ini.

[('state','=','draft')]

Domain diatas jika diterapkan pada model sale.order akan jadi expresi SQL seperti ini

WHERE (
	("sale_order"."state" = 'draft')
)

Domain bisa digunakan pada python untuk mencari data tertentu pada suatu model, atau pada field relational untuk membatasi pilihan dropdown. Bisa juga pada file xml, misal pada search view untuk membatasi data yang tampil pada list / tree view.

Domain juga bisa digunakan untuk mengatur attribute suatu field, misal untuk mengatur attribute readonly, yaitu untuk mengatur field agar bisa diedit atau tidak bisa diedit pada kondisi tertentu.

Sebagai programmer odoo memahami domain ini sangatlah vital. Sayangnya domain ini ditulis dalam Polish Notation. Dimana operator ditulis lebih dulu dari pada operand. Misal jika kita punya ekspresi 1 + 2, jika ditulis dalam Polish Notation akan jadi + 1 2. Bagi yang belum kenal Polish Notation hal ini sangat membingungkan, ini yang saya alami waktu awal-awal bekerja sebagai programmer odoo.

Oleh karena itu kita harus punya trick tersendiri untuk menulis domain ini.

Salah satu trick yang biasa saya gunakan adalah mengubah domain menjadi SQL, sehingga saya bisa menjalankannya di Postgre SQL langsung untuk melihat hasilnya. Dengan mengubah domain menjadi SQL saya bisa menganalisa domain yang saya tulis sudah menghasilkan query yang saya harapkan atau belum. Jika sudah tentu saya tinggal membandingkan hasil query dari SQL tersebut dengan hasil query original odoo, sudah sama atau tidak.

Saya membuat sebuah addon custom untuk melakukan pekerjaan diatas, dan saya sudah mengupload addon domain menjad SQL ini di Github, silakan download di sini. Kemudian install untuk mengikuti tutorial ini.

Sebelum menulis domain, pastikan kita sudah bisa membuat query yang benar. Kemudian ubah query tersebut menjadi domain. Selanjutnya dengan method get_query dari module domain_to_sql di atas, domain tersebut akan diubah menjadi SQL. Selanjutnya kita tinggal membandingkan SQL yang kita tulis sejak awal dengan SQL dari method get_query.

Tetapi cara diatas hanya perlu kita lakukan jika kondisi pada query yang kita buat terdapat operator OR. Jika tidak ada operator OR tidak perlu pusing-pusing, tulis saja domain langsung tanpa perlu membuat SQL di Postgre SQL atau menguji-nya dengan module domain_to_sql.

Misal kita memiliki SQL seperti ini

select id 
from sale_order 
where state = 'draft' and
partner_id = 10

Karena tidak terdapat operator OR kita bisa langsung menulis domain seperti dibawah ini, mengabaikan operator AND karena pada odoo default operator-nya adalah AND

[('state','=','draft'), ('partner_id','=',10)]

Sebagai contoh kasus misal kita ingin mencari Partner dengan nama mengandung kata agus atau Partner dengan alamat mengandung kata street 2 dan email mengandung kata gmail. Jika ditulis dalam bentuk SQL kita bisa menulisnya seperti ini

select id
from res_partner
where name ilike '%agus%' or
(street ilike '%street 2%' and email ilike '%gmail%')

Jika kita jalankan query diatas di PG Admin, hasilnya akan seperti ini

Hasil query postgresql di PG Admin

Lalu bagaimana cara mengubah SQL query diatas menjadi odoo domain ?

Dalam Polish Notation terdapat operator dan operand. Operator pada domain odoo hanya ada 2 yaitu AND dengan simbol ‘&’ dan OR dengan simbol ‘|’. Dalam SQL query diatas terdapat 2 operator yaitu OR dan AND.

Sedangkan operand adalah ekspresi yang terdiri dari 3 bagian untuk menentukan nilai True atau False. Dalam SQL query diatas terdapat tiga operand yaitu name ilike ‘%agus%’, street ilike ‘%street 2%’ dan email ilike ‘%gmail%’

Untuk membuat domain tulis semua operator dari SQL query diatas secara berurutan dalam sebuah array, seperti dibawah ini.

domain = ['|','&']

Kemudian tulis operand dalam bentuk tuple secara berurutan, seperti di bawah ini.

domain = ['|','&',('name','ilike','agus'),('street','ilike', 'street 2'), ('email', 'ilike', 'gmail')]

Kemudian panggil method get_query untuk melihat hasil SQL query dari domain diatas.

domain = ['|','&',('name','ilike','agus'),('street','ilike', 'Street 2'), ('email', 'ilike', 'gmail')]
query = self.env['res.partner'].get_query(domain)
print(query)

Hasilnya akan jadi seperti ini

SELECT "res_partner".id FROM "res_partner" WHERE (("res_partner"."active" = 'True')  AND  ((("res_partner"."name"::text ilike '%agus%')  AND  ("res_partner"."street"::text ilike '%Street 2%'))  OR  ("res_partner"."email"::text ilike '%gmail%')))

Dari kode diatas ternyata SQL query yang dihasilkan ditambah operand yang tidak kita tulis yaitu (“res_partner”.”active” = ‘True’). Odoo secara default hanya menampilkan data yang active saja, oleh karena itu operand diatas selalu muncul. Agar operand diatas tidak muncul, dalam artian kita mengabaikan status active atau non active suatu data, kita bisa menambahkan context active_test bernilai False seperti dibawah ini.

domain = ['|','&',('name','ilike','agus'),('street','ilike', 'Street 2'), ('email', 'ilike', 'gmail')]
query = self.env['res.partner'].with_context({'active_test': False}).get_query(domain)
print(query)

Sekarang kode diatas akan menghasilkan SQL query seperti ini

SELECT "res_partner".id FROM "res_partner" WHERE ((("res_partner"."name"::text ilike '%agus%')  AND  ("res_partner"."street"::text ilike '%Street 2%'))  OR  ("res_partner"."email"::text ilike '%gmail%'))

Terlihat operand (“res_partner”.”active” = ‘True’) sudah tidak tampil lagi. Tapi operator AND dan OR menghubungkan operand yang salah. Ini artinya domain yang kita tulis masih salah.

Jika hal ini terjadi coba geser-geser operator-nya. Mulai dari operator paling kanan yaitu operator AND, kira-kira akan jadi seperti ini.

domain = ['|', ('name','ilike','agus'), '&', ('street','ilike', 'Street 2'), ('email', 'ilike', 'gmail')]
query = self.env['res.partner'].with_context({'active_test': False}).get_query(domain)
print(query)

Hasilnya seperti ini

SELECT "res_partner".id FROM "res_partner" WHERE (("res_partner"."name"::text ilike '%agus%')  OR  (("res_partner"."street"::text ilike '%Street 2%')  AND  ("res_partner"."email"::text ilike '%gmail%')))

Sekarang posisi operator sudah benar. Kita tinggal membandingkan hasil query dari odoo lewat method search dengan hasil query yang pertama kali kita buat.

Jika kita memanggil method search seperti dibawah ini

domain = ['|', ('name','ilike','agus'), '&', ('street','ilike', 'Street 2'), ('email', 'ilike', 'gmail')]
query = self.env['res.partner'].with_context({'active_test': False}).get_query(domain)
print('query====')
print(query)

result = self.env['res.partner'].with_context({'active_test': False}).search(domain)
print('result====')
print(result)

Hasilnya akan terlihat seperti ini

Hasil perintah search pada odoo

Terlihat pada instalasi odoo saya, partner yang memenuhi kriteria dari domain di atas adalah partner dengan id 9 dan 11. Sama dengan hasil SQL query yang pertama kali kita buat. Jadi domain yang kita tulis sudah benar.

Tulisan Serupa

5 Replies to “Menguji Domain pada Odoo”

  1. maaf pak saya mau tanya kalau saya punya parent dan child class, dimana saya o2m dari parent ke child, sedang saya mau child itu beradasarkan field yang di pilih di parent,

    kira2 bagaimana menggunakan domainnya ?

    terima kasih banyak

  2. Ada pertanyaan lain Pak, saya sedang buat aplikasi report dinamis, dimana nanti bisa meng “inject” menu ke aplikasi lain. ini sudah berhasil, step selanjutnya saya membuat fields dinamis, artinya saya membuat semacam field mana2 saja yang akan saya tampilkan di dalam tree, ini belum berhasil. saya cuma berhasil menampilkan seluruh field dari model yang saya sebutkan.

    kalau bapak bisa mengajari saya bagaimana membuat tree dinamis dari model yang kita sebut, saya sudah membuat aplikasi nya untuk membuat report akan di inject kem menu apa, dari model apa, nah detail nya saya sebutkan atas model itu saya akan menampilkan field2 apa saja,

    ini yang belum bisa pak ? mohon arahan
    terima kasih

    1. FYI, semua view pada odoo, termasuk form, tree, dan template disimpan di model ir.ui.view, tepatnya di field arch_db. Untuk keperluan agan ada 2 cara yang mungkin bisa dilakukan. Pertama, saat module diinstall, atau saat klik tombol tertentu edit field arch_db di view terkait, tambahkan field-field dinamis milik agan. Cara kedua, dengan meng-override method bawaan ir.ui.view seperti read_template atau method lain yang return isi dari field arch_db. Sebelum nilainya di return ke browser ubah dulu nilainya dengan menambahkan field-field dinamis yang dibutuhkan.

      Note : saya belum pernah mencoba kedua cara diatas.

Leave a Reply

Your email address will not be published. Required fields are marked *