Penggunaan Action Window Pada Odoo v15

ir.actions.act_window adalah action yang paling banyak digunakan saat kita membuat aplikasi dalam ekosistem Odoo. Jika kita memanggil action ini, Odoo secara otomatis akan menampilkan view suatu model, sehingga user dapat melakukan operasi CRUD pada model tersebut. Hal yang menarik adalah, kita tidak perlu membuat route, controller, atau kode javascript jika kita ingin membuat halaman CRUD berbasis ajax. Bahkan, jika perlu sebuah view-pun tidak dibutuhkan. Cukup dengan sebuah model, hak akses, sebuah action window, dan sebuah menuitem kita bisa membuat sebuah halaman CRUD. Route, controller, javascript, dan view akan ditangani oleh Odoo secara otomatis.

Membuat dan memanggil ir.actions.act_window

Ada beberapa cara yang dapat kita gunakan dalam membuat dan memanggil ir.actions.act_window, yang pertama adalah dengan menulisnya di sebuah file xml, kemudian kita sambungkan dengan sebuah menuitem. Sebagai contoh kasus anggaplah kita memiliki model seperti kode dibawah ini.

# -*- coding: utf-8 -*-
from odoo import api, fields, models, exceptions, _

class ModelOne(models.Model):
    _name = 'model.one'
    _description = 'Model One'

    name = fields.Char()
    description = fields.Text()
    detail_ids = fields.One2many('model.one.detail', 'header_id')

class ModelOneDetail(models.Model):
    _name = 'model.one.detail'
    _description = 'Model One Detail'

    name = fields.Char()
    value = fields.Float()
    header_id = fields.Many2one('model.one')

Setelah kita membuat hak akses untuk kedua model di atas (jika Anda kesulitan membuat hak akses silakan download source kode di akhir artikel ini), kita bisa membuat ir.actions.act_window dengan cara membuat sebuah record, yaitu dengan cara menulis kode xml dengan tag record.

Pada Odoo tag record digunakan untuk menambah sebuah baris/record/data pada table/model tertentu saat kita menginstall/mengupgrade sebuah module. Berikut ini adalah contoh cara menambah record pada Odoo dengan menggunakan tag record pada file xml.

<record id="id_or_primary_key" model="model_name">
	<!-- field list -->
    <field name="field_one">value_one</field>
    <field name="field_two">value_two</field>
</record>
  1. id

    id adalah teks bebas yang harus unik. Dalam satu module kita tidak boleh membuat id yang sama, anggap saja id ini sebagai primary key. Kita bisa menulis id dengan karakter apapun asalkan tidak mengandung spasi. Nantinya id ini bisa kita gunakan di file xml lain atau di python untuk manipulasi data.

  2. model

    model adalah table dimana data/record akan kita simpan. id dan model bersifat mandatory, kita wajib menulisnya.

  3. field list

    field list adalah daftar field/column dari model/table beserta valuenya. Bagian ini bersifat optional, tergantung model yang akan kita tuju. Jika field pada model yang kita tuju ditandai sebagai required kita wajib menulisnya. Pada model ir.actions.act_window satu-satunya field yang ditandai sebagai required adalah field res_model. Sehingga kita bisa membuat record ir.actions.act_window dengan kode di bawah ini.

<record id="action_model_one_1" model="ir.actions.act_window">
    <field name="res_model">model.one</field>
</record>

Kode di atas adalah kode minimal yang bisa kita tulis jika kita ingin membuat ir.actions.act_window di odoo v15 dengan tag record pada file xml. Perhatikan field res_model. Jika ir.actions.act_window di atas dipanggil, Odoo secara otomatis akan menampilkan view yang berkaitan dengan model model.one, sehingga user bisa melakukan operasi CRUD pada model tersebut.

Selanjutnya kita bisa menyambungkan ir.actions.act_window yang telah kita buat di atas dengan sebuah menuitem. Yaitu dengan cara memasukkan id dari ir.actions.act_window di atas sebagai value dari field action dari menuitem, seperti pada kode di bawah ini.

<menuitem id="menu_model_one_1"
    name="Menu 1"    
    action="action_model_one_1"
    parent="menu_model_one_root" />

Jika ir.actions.act_window ditulis di module/addon yang berbeda, kita harus menulis nama module sebelum id dari ir.actions.act_window yang akan kita panggil. Misal module_one.action_model_one_1.

Selanjutnya kita tinggal menginstall module yang telah kita buat. Berikut ini adalah tampilan dari Menu 1 yang memanggil ir.actions.act_window dengan id action_model_one_1 di atas.

action window dengan tampilan default pada odoo

Gambar di atas adalah tampilan default dari model model.one, karena kita belum membuat view apapun untuk model tersebut. Saya akan membahas bagaimana mengatur view dari ir.actions.act_window nanti.

Selain menggunakan tag record pada file xml kita juga bisa membuat ir.actions.act_window dengan file csv. Cara ini jarang digunakan, oleh karena itu Anda dapat mengabaikannya. Saya menulis cara ini hanya sebagai info tambahan saja.

Buat sebuah file dengan nama ir.actions.act_window.csv. Ingat, nama file harus sama persis, tidak boleh beda. Nama file ini fungsinya sama dengan attribute model jika kita menggunakan tag record pada file xml. Selanjutnya tulis daftar nama field yang akan kita isi valuenya pada baris pertama, seperti pada kode di bawah ini.

id,name,res_model

Kemudian tambahkan record mulai dari baris kedua dan seterusnya. Berikut ini kode lengkapnya.

id,name,res_model
action_model_one_2,Action From CSV,model.one

Pada kode di atas saya menambah field name untuk membedakannya dari ir.actions.act_window yang telah kita buat dengan file xml. Selanjutnya kita tinggal menggabungkan ir.actions.act_window di atas dengan sebuah menuitem. Sebenarnya kita juga bisa membuat menuitem dengan file csv, tetapi saya sedang malas melakukannya, silakan coba sendiri 🙂 Kali ini saya akan membuat menuitem dengan file xml saja, seperti pada kode di bawah ini.

<menuitem id="menu_model_one_2"
    name="Menu 2"    
    action="action_model_one_2"
    parent="menu_model_one_root" />

Berikut ini adalah tampilan saat kita masuk Menu 2. Perhatikan nama ir.actions.act_window pada bagian breadcrumb dan bandingkan dengan Menu 1.

action window dengan tampilan default pada odoo

Kita juga bisa membuat dan memanggil ir.actions.act_window dengan python dan javascript. Tetapi cara ini sedikit lebih kompleks, jadi saya akan membahasnya di bagian akhir dari artikel ini.

Mengatur tampilan ir.actions.act_window

Ada beberapa field dari model ir.actions.act_window yang dapat digunakan untuk mengatur tampilan. Yang pertama adalah field target. Berikut ini adalah opsi-opsinya.

  1. current

    Opsi ini adalah opsi default. Jika kita memanggil ir.actions.act_window yang menggunakan opsi ini dengan menuitem, tampilan pada layar termasuk tampilan breadcrumb akan direplace. Jika kita memanggilnya dengan python, tampilan layar akan direplace kecuali tampilan breadcrumb, sehingga kita bisa kembali ke tampilan sebelumnya dengan cara klik pada breadcrumb.

  2. new

    Opsi ini digunakan jika kita ingin menampilkan view dalam modal. Jika kita memanggil ir.actions.act_window dengan opsi ini, view yang baru akan ditampilkan di atas view yang lama, breadcrumb juga tidak berubah. Dengan opsi ini tampilan tidak bisa berubah mode, misal dari tree/list view ke form view. Berikut ini adalah contoh kode dan tampilannya.

    		<record id="action_model_one_new_window" model="ir.actions.act_window">
                <field name="name">Model One In Modal</field>
                <field name="res_model">model.one</field>
                <field name="target">new</field>
            </record>
    		
    action window dalam modal pada odoo
  3. inline

    Jika kita memanggil ir.actions.act_window dengan opsi ini breadcrumb, search view, tombol Save, tombol Edit dan tombol Discard akan hilang. Jika dilihat sekilas opsi ini seperti tidak ada gunanya. Saya sendiri belum pernah membuat ir.actions.act_window dengan opsi ini. Opsi ini digunakan saat kita membuka menu Settings >> General Settings. Pada menu tersebut, tombol Save dan tombol Edit masih terlihat karena form viewnya menambah kedua tombol tersebut secara manual. Berikut ini adalah contoh kode dan tampilannya.

            <record id="action_model_one_inline" model="ir.actions.act_window">
                <field name="name">Model One Inline</field>
                <field name="res_model">model.one</field>
                <field name="target">inline</field>
            </record>
            
    action window dengan opsi target inline pada odoo
  4. fullscreen

    Jika kita memanggil ir.actions.act_window dengan opsi ini navbar akan disembunyikan, sehingga kita tidak bisa mengakses menu lain, kita juga tidak bisa mengakses tombol Log Out. Berikut ini adalah contoh kode dan tampilannya.

            <record id="action_model_one_fullscreen" model="ir.actions.act_window">
                <field name="name">Model One Fullscreen</field>
                <field name="res_model">model.one</field>
                <field name="target">fullscreen</field>
            </record>
            
    action window dengan opsi target fullscreen pada odoo
  5. main

    Jika kita memanggil ir.actions.act_window dengan opsi ini breadcrumb akan direplace. Kita hanya bisa mengetahui perbedaan opsi ini dengan opsi current jika ir.actions.act_window dengan opsi ini dipanggil dengan kode javascript atau python. Jika dipanggil dengan menuitem tidak ada bedanya sama sekali. Saya akan mendemokannya di bagian akhir artikel ini. Berikut ini adalah contoh kodenya.

            <record id="action_model_one_main" model="ir.actions.act_window">
                <field name="name">Model One Main</field>
                <field name="res_model">model.one</field>
                <field name="target">main</field>
            </record>
            

Field selanjutnya dari model ir.actions.act_window yang bisa digunakan untuk mengatur tampilan adalah field view_mode. Field ini memiliki 7 opsi yang bisa digunakan salah satu saja atau dikombinasikan dengan opsi yang lain, yaitu dengan memisahkannya dengan koma. Pilihannya adalah : tree, form, graph, pivot, calendar, gantt, dan kanban. Secara default nilai dari opsi ini adalah tree,form. Artinya kita bisa berpindah view dari tree/list view ke form view.

Berikut ini adalah beberapa contoh kode pengunaan opsi ini.

<record id="action_model_one_tree_view_only" model="ir.actions.act_window">
    <field name="name">Model One Tree</field>
    <field name="res_model">model.one</field>
    <field name="view_mode">tree</field>
</record>

<record id="action_model_one_tree_kanban" model="ir.actions.act_window">
    <field name="name">Model One Kanban</field>
    <field name="res_model">model.one</field>
    <field name="view_mode">kanban,tree,form</field>
</record>

Perlu diingat, tidak semua opsi dari field view_mode di atas bisa digunakan untuk semua model. Beberapa view kadang membutuhkan field dengan nama tertentu harus ada pada model, misal jika ingin menggunakan view calendar model tersebut harus memiliki field date_start, date_stop dll.

Field selanjutnya dari model ir.actions.act_window yang bisa digunakan untuk mengatur tampilan adalah field view_id. Field ini digunakan untuk memberitahu Odoo, view mana yang harusnya dirender jika suatu model memiliki beberapa view dengan type yang sama. Sebagai contoh kasus, anggaplah kita punya model seperti pada kode di bawah ini.

# -*- coding: utf-8 -*-
from odoo import api, fields, models, exceptions, _

class ModelTwo(models.Model):
    _name = 'model.two'
    _description = 'Model Two'

    name = fields.Char()
    status = fields.Selection([
        ('new', 'New'),
        ('confirmed', 'Confirmed'),
        ('closed', 'Closed')
    ], default='new')
    description = fields.Text()

Kemudian anggaplah model di atas memiliki view seperti pada kode di bawah ini.

<record id="model_two_tree_view_1" model="ir.ui.view">
    <field name="name">model_two_tree_view_1</field>
    <field name="model">model.two</field>
    <field name="priority">1</field>
    <field name="arch" type="xml">
        <tree>
            <field name="name" />
            <field name="status" />
        </tree>
    </field>
</record>

<record id="model_two_tree_view_2" model="ir.ui.view">
    <field name="name">model_two_tree_view_2</field>
    <field name="model">model.two</field>
    <field name="priority">2</field>
    <field name="arch" type="xml">
        <tree>
            <field name="name" />
            <field name="description" />
        </tree>
    </field>
</record>

<record id="model_two_kanban_view_1" model="ir.ui.view">
    <field name="name">model_two_kanban_view_1</field>
    <field name="model">model.two</field>
    <field name="priority">1</field>
    <field name="arch" type="xml">
        <kanban>
            <field name="name"/>
            <field name="status"/>
            <templates>
                <t t-name="kanban-box">
                    <div t-attf-class="oe_kanban_card oe_kanban_global_click">
                        <div class="o_kanban_record_top mb16">
                            <div class="o_kanban_record_headings mt4">
                                <strong class="o_kanban_record_title"><span><t t-esc="record.name.value"/></span></strong>
                            </div>
                        </div>
                        <div class="o_kanban_record_bottom">
                            <div class="oe_kanban_bottom_right">
                                <field name="status" widget="label_selection" />
                            </div>
                        </div>
                    </div>
                </t>
            </templates>
        </kanban>
    </field>
</record>

<record id="model_two_kanban_view_2" model="ir.ui.view">
    <field name="name">model_two_kanban_view_2</field>
    <field name="model">model.two</field>
    <field name="priority">2</field>
    <field name="arch" type="xml">
        <kanban>
            <field name="name"/>
            <field name="description"/>
            <templates>
                <t t-name="kanban-box">
                    <div t-attf-class="oe_kanban_card oe_kanban_global_click">
                        <div class="o_kanban_record_top mb16">
                            <div class="o_kanban_record_headings mt4">
                                <strong class="o_kanban_record_title"><span><t t-esc="record.name.value"/></span></strong>
                            </div>
                        </div>
                        <div class="o_kanban_record_bottom">
                            <div class="oe_kanban_bottom_left">
                                <field name="description" />
                            </div>
                        </div>
                    </div>
                </t>
            </templates>
        </kanban>
    </field>
</record>

<record id="model_two_form_view_1" model="ir.ui.view">
    <field name="name">model_two_form_view_1</field>
    <field name="model">model.two</field>
    <field name="priority">1</field>
    <field name="arch" type="xml">
        <form>
            <sheet>
                <group>
                    <field name="name" />
                    <field name="status" />
                </group>
            </sheet>
        </form>
    </field>
</record>

<record id="model_two_form_view_2" model="ir.ui.view">
    <field name="name">model_two_form_view_2</field>
    <field name="model">model.two</field>
    <field name="priority">2</field>
    <field name="arch" type="xml">
        <form>
            <sheet>
                <group>
                    <field name="name" />
                    <field name="description" />
                </group>
            </sheet>
        </form>
    </field>
</record>

Model model.two di atas memiliki 2 buah tree/list view, 2 buah kanban view dan 2 buah form view. Tree/list view pertama hanya menampilkan field name dan field status, sedangkan tree/list view kedua hanya menampilkan field name dan field description. Begitu juga dengan kanban dan form view-nya.

Secara default Odoo akan menampilkan view yang memiliki nilai priority paling kecil atau view yang paling awal tersimpan di database. Oleh karena itu tree/list view dengan id model_two_tree_view_1 akan dirender, sehingga user hanya bisa melihat field name dan status dari model model.two.

Jika kita ingin Odoo menampilkan data dengan view ber-id model_two_tree_view_2 kita bisa memanfaatkan field view_id dari model ir.actions.act_window. Berikut ini adalah contoh kodenya.

<record id="action_model_two_with_view_id_1" model="ir.actions.act_window">
    <field name="res_model">model.two</field>
    <field name="view_id" ref="model_two_tree_view_2"/>
</record>

Dengan begini kita bisa melihat field description di tree view.

Sayangnya opsi/field view_id dari model ir.actions.act_window ini memiliki beberapa kelemahan. Yang pertama adalah: kita hanya bisa memasukkan satu buah view saja di opsi ini. Dari kode terakhir di atas kita tidak punya kontrol terhadap form view mana yang akan dirender oleh Odoo, karena kita hanya mengisi opsi view_id dengan view dari tree/list view (model_two_tree_view_2). Sehingga form view yang memiliki nilai priority paling kecillah yang akan dirender yaitu form view dengan id model_two_form_view_1, sehingga user tidak bisa melihat field description.

Kelemahan yang kedua adalah: Odoo akan mengabaikan urutan dari opsi view_mode, sebagai contoh kasus anggaplah kita punya kode seperti di bawah ini.

<record id="action_model_two_with_view_id_3" model="ir.actions.act_window">
    <field name="res_model">model.two</field>
    <field name="view_mode">tree,kanban,form</field>
    <field name="view_id" ref="model_two_kanban_view_2"/>
</record>

Dari kode di atas, berdasarkan opsi dari field view_mode seharusnya tree/list view akan dirender terlebih dahulu, selanjutnya user bisa membuka kanban view atau form view secara manual. Tetapi karena kita menambahkan opsi view_id yang merujuk ke sebuah kanban view maka kanban view akan dirender terlebih dahulu, mengabaikan urutan dari opsi view_mode. Sehingga jika kita memiliki kode seperti di bawah ini.

<record id="action_model_two_with_view_id_2" model="ir.actions.act_window">
    <field name="res_model">model.two</field>
    <field name="view_mode">tree,kanban,form</field>
    <field name="view_id" ref="model_two_form_view_2"/>
</record>

Saat ir.actions.act_window di atas dipanggil kita akan langsung dihadapkan dengan sebuah form view, tanpa bisa berpindah ke kanban atau tree view.

Jika kita ingin kontrol yang lebih baik kita bisa menggunakan opsi/field yang lain, yaitu opsi/field view_ids.

Dengan opsi/field view_ids kita bisa mengatur view mana saja yang harusnya dirender oleh Odoo dengan sedikit lebih bebas. Field view_ids sebenarnya berelasi One2many dengan model ir.actions.act_window.view, sehingga kita bisa mengisi field view_ids dengan kode seperti di bawah ini.

<record id="action_model_two_with_view_ids" model="ir.actions.act_window">
    <field name="res_model">model.two</field>
    <field name="view_mode">kanban,tree,form</field>
</record>

<record id="action_model_two_with_view_ids_tree_view" model="ir.actions.act_window.view">
    <field name="act_window_id" ref="action_model_two_with_view_ids" />
    <field name="view_id" ref="model_two_tree_view_2"/>
    <field name="view_mode">tree</field>
    <field name="sequence">2</field>
</record>

<record id="action_model_two_with_view_ids_kanban_view" model="ir.actions.act_window.view">
    <field name="act_window_id" ref="action_model_two_with_view_ids" />
    <field name="view_id" ref="model_two_kanban_view_2"/>
    <field name="view_mode">kanban</field>
    <field name="sequence">1</field>
</record>

<record id="action_model_two_with_view_ids_form_view" model="ir.actions.act_window.view">
    <field name="act_window_id" ref="action_model_two_with_view_ids" />
    <field name="view_id" ref="model_two_form_view_2"/>
    <field name="view_mode">form</field>
    <field name="sequence">3</field>
</record>

Sayangnya opsi view_ids juga akan mengabaikan opsi view_mode dari model ir.actions.act_window. Sehingga kode <field name=”view_mode”>kanban,tree,form</field> di atas jadi tidak berguna. ir.actions.act_window.view dengan sequence paling kecil-lah yang akan dirender terlebih dahulu. Bahkan jika ir.actions.act_window di atas view_mode-nya hanya kita tulis tree,form saja, Odoo akan tetap merender kanban view.

Field selanjutnya dari model ir.actions.act_window yang bisa digunakan untuk mengatur tampilan adalah field search_view_id. Field ini digunakan untuk mengatur search view mana yang akan digunakan untuk memfilter data. Sebagai contoh kasus mari kita tambah 2 buah search view untuk model model.two.

<record id="model_two_search_view_1" model="ir.ui.view">
    <field name="name">model_two_search_view_1</field>
    <field name="model">model.two</field>
    <field name="priority">1</field>
    <field name="arch" type="xml">
        <search>
            <field name="name" />
            <filter string="New" domain="[('status','=','new')]" name="status_new"/>
        </search>
    </field>
</record>

<record id="model_two_search_view_2" model="ir.ui.view">
    <field name="name">model_two_search_view_2</field>
    <field name="model">model.two</field>
    <field name="priority">2</field>
    <field name="arch" type="xml">
        <search>
            <field name="name" />
            <filter string="Confirmed" domain="[('status','=','confirmed')]" name="status_confirmed"/>
            <filter string="Closed" domain="[('status','=','closed')]" name="status_closed"/>
            <group expand="0" string="Group By">
                <filter string="Status" name="group_bystatus" domain="[]" context="{'group_by': 'status'}"/>
            </group>
        </search>
    </field>
</record>

Jika kita ingin menggunakan search view dengan id model_two_search_view_2 kita bisa menggunakan kode seperti di bawah ini.

<record id="action_model_two_with_search_view" model="ir.actions.act_window">
    <field name="res_model">model.two</field>
    <field name="search_view_id" ref="model_two_search_view_2" />
</record>

Membatasi record dengan ir.actions.act_window

Kita bisa membatasi record yang akan ditampilkan dengan ir.actions.act_window dengan beberapa field yang telah disediakan. Yang pertama adalah field domain. Berikut ini adalah contoh kodenya.

<record id="action_model_two_limit_record_with_domain" model="ir.actions.act_window">
    <field name="res_model">model.two</field>
    <field name="domain">[('status','=','confirmed')]</field>
</record>

Dengan field domain kita bisa membatasi record yang akan ditampilkan kepada user. Sayangnya user tidak bisa membatalkan pembatasan dari field domain ini. Dari contoh kode di atas, user hanya bisa membuka model.two yang field status-nya bernilai confirmed, sehingga user tidak bisa melihat record/data lain.

Jika kita ingin data yang ditampilkan pertama kali adalah data yang field status-nya bernilai confirmed, tetapi masih bisa melihat data lain, kita bisa menggunakan opsi/field search_view_id dikombinasikan dengan opsi/field context. Berikut ini adalah contoh kodenya.

<record id="action_model_two_limit_record_with_search_view_and_context" model="ir.actions.act_window">
    <field name="res_model">model.two</field>
    <field name="search_view_id" ref="model_two_search_view_2" />
    <field name="context">{'search_default_status_confirmed': 1}</field>
</record>

Rumus penulisan context untuk memfilter data adalah teks search_default_ diikuti dengan salah satu nama filter di search view, pada contoh kode di atas nama filternya adalah status_confirmed. Silakan cek kode filter ini di search view model_two_search_view_2. Saat user memanggil action window di atas filter status_confirmed akan secara otomatis diaplikasikan, sehingga data yang ditampilkan sudah disortir.

action window dengan tampilan search view pada odoo

Selanjutnya jika user ingin melihat data/record lain user bisa menghapus filter Confirmed yang terlihat pada gambar di atas.

Selain itu kita juga bisa membatasi jumlah data yang akan ditampilkan di tree/list view perhalaman. Yaitu dengan menambah opsi/field limit. Nilai default dari field ini adalah 80, sehingga secara default data yang akan ditampilkan akan sebanyak 80 baris perhalaman. Berikut ini adalah contoh kode penggunaanya.

 <record id="action_model_two_limit_record_number" model="ir.actions.act_window">
    <field name="res_model">model.two</field>
    <field name="limit">2</field>
</record>
action window dengan tampilan search view pada odoo

Dari gambar di atas terlihat bahwa, dari total 8 record sudah dibatasi agar ditampilkan 2 baris perhalaman.

Nilai default

Dengan field context kita juga bisa mengatur nilai default suatu model. Seperti pada kode di bawah ini.

<record id="action_model_two_with_default_value" model="ir.actions.act_window">
    <field name="res_model">model.two</field>
    <field name="context">{'default_name': 'Automatic filled'}</field>
</record>

Jika ir.actions.act_window di atas dipanggil, kemudian user mengklik tombol Create field name secara otomatis akan terisi kata Automatic filled.

Menampilkan record tertentu

Kita juga bisa menampilkan record dengan id/primary key tertentu yaitu dengan menggunakan field res_id dari model ir.actions.act_window, sehingga user bisa langsung melihat data dari record tersebut, tanpa harus mencarinya terlebih dahulu di tree atau kanban view. Sebagai contoh kasus, mari kita buat sebuah record untuk model model.two terlebih dahulu. Perhatikan kode di bawah ini.

<record id="model_two_automatic_created" model="model.two">
    <field name="name">Automatic</field>
    <field name="status">confirmed</field>
    <field name="description">Added when install/upgrade the module</field>
</record>

Kita bisa menampilkan record di atas pada sebuah form view secara langsung dengan kode seperti di bawah ini.

<record id="action_model_two_open_specific_record" model="ir.actions.act_window">
    <field name="res_model">model.two</field>
    <field name="view_mode">form</field>
    <field name="res_id" ref="model_two_automatic_created" />
</record>

Membuat dan memanggil ir.actions.act_window dengan python

Kini saatnya kita membahas bagaimana membuat dan memanggil ir.actions.act_window dengan python. Pertama mari kita buat sebuah model baru lagi.

# -*- coding: utf-8 -*-
from odoo import api, fields, models, exceptions, _

class ModelThree(models.Model):
    _name = 'model.three'
    _description = 'Model Three'

    name = fields.Char()

    def open_model_one(self):
        pass

Nanti kita akan memodifikasi method open_model_one di atas agar return ir.actions.act_window untuk membuka list view dari model model.one. Mari kita buat sebuah form untuk model di atas terlebih dahulu dan tambahkan sebuah button utuk memanggil method open_model_one di atas.

<record id="model_three_form_view" model="ir.ui.view">
    <field name="name">model_three_form_view</field>
    <field name="model">model.three</field>
    <field name="arch" type="xml">
        <form>
            <header>
                <button name="open_model_one" string="Open Model One" type="object" />
            </header>
            <sheet>
                <group>
                    <field name="name" />
                </group>
            </sheet>
        </form>
    </field>
</record>

Pada python, untuk menggunakan fitur ir.actions.act_window kita tidak perlu menambahkan record ke database, cukup return dictionary yang berisi informasi yang mirip dengan table/model ir.actions.act_window. Berikut ini adalah contoh sederhananya.

def open_model_one(self):
    return {
        'type': 'ir.actions.act_window',
        'res_model': 'model.one',
        'view_mode': 'tree,form'
    }

Kode di atas adalah kode minimal untuk menggunakan ir.actions.act_window, jika kita menghapus salah satu key dari dictionary di atas, maka akan error. Tetapi alangkah baiknya jika kita menambah key name, agar di breadcrumb tidak muncul kata undefined atau unnamed.

def open_model_one(self):
    return {
        'type': 'ir.actions.act_window',
        'name': 'Model One',
        'res_model': 'model.one',
        'view_mode': 'tree,form'
    }

Kita bisa menulis opsi/field name, res_model, target, view_mode, domain, context, dan limit seperti saat kita membuat ir.actions.act_window dengan file xml atau csv. Seperti pada kode di bawah ini.

def open_model_two(self):
    return {
        'type': 'ir.actions.act_window',
        'name': 'Model Two',
        'res_model': 'model.two',
        'view_mode': 'tree,form',
        'target': 'fullscreen',
        'domain': [('status','=','new')],
        'context': {'default_name': 'From model three'},
        'limit': 2
    }

Sedangkan untuk opsi/field res_id dan view_id kita bisa menuliskan id dari record yang bersangkutan secara langsung. Yang saya maksud id disini bukan id yang kita tulis di file xml/csv, tetapi id(primary key) di database. Sebagai contoh kasus anggaplah kita sudah tahu id dari record yang akan kita gunakan, maka kita bisa menulisnya seperti ini.

def open_model_two_with_specific_id(self):
    return {
        'type': 'ir.actions.act_window',
        'name': 'Model Two',
        'res_model': 'model.two',
        'view_mode': 'form',
        'res_id': 1
    }

Atau jika kita tahu bahwa record yang akan kita gunakan dibuat dengan file xml/csv dan tahu id-nya. kita bisa menggunakan kode seperti di bawah ini.

def open_model_two_with_specific_id_and_view_id(self):
    return {
        'type': 'ir.actions.act_window',
        'name': 'Model Two',
        'res_model': 'model.two',
        'view_mode': 'form',
        'res_id': self.env.ref('tutorial_action_window.model_two_automatic_created').id,
        'view_id': self.env.ref('tutorial_action_window.model_two_form_view_2').id
    }

Atau jika kita tidak tahu id-nya, kita bisa melakukan search, seperti pada kode di bawah ini.

def open_model_two_with_id_and_view_id_from_search(self):
    res_id = self.env['model.two'].search([('name','=','test')],limit=1)
    form_view_id = self.env['ir.ui.view'].search([('model','=','model.two'),('type','=','form'),('priority','>',1)], limit=1)
    
    return {
        'type': 'ir.actions.act_window',
        'name': 'Model Two',
        'res_model': 'model.two',
        'view_mode': 'form',
        'res_id': res_id.id,
        'view_id': form_view_id.id
    }

Sayangnya kita tidak bisa mengatur opsi/field view_ids jika kita menggunakan ir.actions.act_window dengan python. Opsi/field view_ids dapat diganti dengan opsi/field views. Berikut ini contoh penggunaanya.

def open_model_two_with_views_option(self):
    return {
        'type': 'ir.actions.act_window',
        'name': 'Model Two',
        'res_model': 'model.two',
        'views': [
            (self.env.ref('tutorial_action_window.model_two_kanban_view_2').id, 'kanban'),
            (self.env.ref('tutorial_action_window.model_two_tree_view_2').id, 'tree'),
            (self.env.ref('tutorial_action_window.model_two_form_view_2').id, 'form')
        ]
    }

Hal yang berbeda juga terjadi pada opsi/field search_view_id, dimana kita harus membungkus id dari search view yang akan kita pakai dalam sebuah list, seperti kode di bawah ini.

def open_model_two_with_search_view(self):
    return {
        'type': 'ir.actions.act_window',
        'name': 'Model Two',
        'res_model': 'model.two',
        'view_mode': 'tree,form',
        'search_view_id': [self.env.ref('tutorial_action_window.model_two_search_view_2').id]
    }

Sekarang mari kita coba ir.actions.act_window dengan opsi/field target yang bernilai main. Mari kita siapkan methodnya terlebih dahulu.

def open_other_record(self):
    res_id = self.env['model.three'].search([('id','!=',self.id)],limit=1)
            
    return {
        'type': 'ir.actions.act_window',
        'name': 'Model Three',
        'res_model': 'model.three',
        'view_mode': 'form',
        'res_id': res_id.id
    }

def open_other_record_as_main_target(self):
    res_id = self.env['model.three'].search([('id','!=',self.id)],limit=1)
            
    return {
        'type': 'ir.actions.act_window',
        'name': 'Model Three',
        'res_model': 'model.three',
        'view_mode': 'form',
        'res_id': res_id.id,
        'target': 'main'
    }

Pastikan model model.three memiliki lebih dari satu record. Buka salah satu record kemudian klik tombol Open Other Record berulang kali, sehingga breadcrumb-nya menjadi sangat panjang seperti pada gambar di bawah ini.

form dengan breadcrumb yang panjang pada odoo

Kemudian klik tombol Open Other Record As Main Target, seketika breadcrumb akan dibersihkan, sehingga kita tidak bisa membuka record/view sebelumnya.

Kita juga bisa memanggil ir.actions.act_window yang dibuat dengan file xml/csv dari python, berikut ini adalah contoh kodenya.

def open_action_from_xml(self):
    return self.env['ir.actions.act_window']._for_xml_id('tutorial_action_window.action_model_two_open_specific_record')

Membuat dan memanggil ir.actions.act_window dengan javascript

Sayangnya penggunaan ir.actions.act_window pada javascript sedikit lebih rumit. Untuk sementara Anda dapat mengabaikannya, karena sebagai Odoo developer kita jarang menulis kode javascript, silakan pelajari jika memang Anda membutuhkannya atau lagi senggang. Saya akan menulis tutorialnya jika ada waktu.

Sebagai gambaran, agar kita bisa menggunakan ir.actions.act_window pada javascript, kita harus memanggil method do_action pada object tertentu, silakan cek source code Odoo ini sebagai referensi.

Download Source Code

Tulisan Serupa

Leave a Reply