Belajar Odoo Untuk Pemula [Part 6/8]

Meskipun sudah membuat class, object dan field, itu belum cukup untuk menampilkan field-field yang kita buat pada form aplikasi. Maka langkah selanjutnya kita harus membuat view, action dan menu di xml, dan juga membuat report untuk mengekspor data ke dalam pdf.

Ada beberapa view yang bisa kita buat pada file xml, namun ada 3 view yang paling sering digunakan, yaitu :

  • Search view
<record id="view_ms_pendaftaran_search" model="ir.ui.view">
    <field name="name">ms.pendaftaran.search</field>
    <field name="model">ms.pendaftaran</field>
    <field name="arch" type="xml">
        <search string="Search Pendaftaran">
            <field name="name"/>
            <field name="pasien_id"/>
            <field name="poli_id"/>
            <field name="state"/>
            <filter string="Draft" name="draft" domain="[('state','=','draft')]"/>
            <filter string="Confirm" name="confirm" domain="[('state','=','confirm')]"/>
            <group expand="0">
                <filter name="group_pasien" string="Pasien" domain="[]" context="{'group_by':'pasien_id'}"/>
                <filter name="group_poli" string="Poli" domain="[]" context="{'group_by':'poli_id'}"/>
            </group>
        </search>
    </field>
</record>

  • Tree view
<record model="ir.ui.view" id="ms_pendaftaran_tree_view">
    <field name="name">ms.pendaftaran.tree</field>
    <field name="model">ms.pendaftaran</field>
    <field name="arch" type="xml">
        <tree string="Pendaftaran">
            <field name="name"/>
            <field name="tanggal"/>
            <field name="pasien_id"/>
            <field name="poli_id"/>
            <field name="state"/>
        </tree>
    </field>
</record>

  • Form view
<record model="ir.ui.view" id="ms_pendaftaran_form_view">
    <field name="name">ms.pendaftaran.form</field>
    <field name="model">ms.pendaftaran</field>
    <field name="arch" type="xml">
        <form string="Pendaftaran">
            <header>
                <button name="action_confirm" string="Confirm" type="object" class="oe_highlight" attrs="{'invisible': [('state','!=','draft')]}"/>
                <button name="action_cancel" string="Cancel" type="object" attrs="{'invisible': [('state','=','cancel')]}"/>
                <field name="state" widget="statusbar" statusbar_visible="draft,confirm"/>
            </header>
            <sheet>
                <div class="oe_title">
                    <h1>
                        <field name="name" class="oe_inline" readonly="1"/>
                    </h1>
                </div>
                <group col="4">
                    <field name="pasien_id" attrs="{'readonly': [('state','!=','draft')]}" required="1" options="{'no_open': True, 'no_create': True}"/>
                    <field name="poli_id" attrs="{'readonly': [('state','!=','draft')]}" required="1" options="{'no_open': True, 'no_create': True}"/>
                    <field name="tanggal" attrs="{'readonly': [('state','!=','draft')]}" required="1"/>
                </group>
                <notebook>
                    <page string="Note">
                        <group>
                            <field name="note" nolabel="1" class="oe_inline" placeholder="Note"/>
                        </group>
                    </page>
                    <page string="Audit Trail">
                        <group>
                            <group>
                                <field name="create_uid" readonly="1"/>
                                <field name="create_date" readonly="1"/>
                            </group>
                            <group>
                                <field name="write_uid" readonly="1"/>
                                <field name="write_date" readonly="1"/>
                            </group>
                        </group>
                    </page>
                </notebook>
            </sheet>
        </form>
    </field>
</record>

Satu object bisa memiliki beberapa view, meskipun jenis view nya sama. Misalnya object res.partner memiliki view di form dokter dan form pasien. Jadi data pasien dan dokter akan masuk ke table yang sama yaitu res_partner, meskipun tampilan di aplikasinya terpisah.

Sebagian besar attribute field bisa ditulis di py maupun xml. Perbedaannya, ketika diterapkan di py maka akan berlaku untuk semua view. Tapi ketika ditulis di xml maka hanya berlaku untuk view-view tertentu. Misalnya di object res.partner ada field kode, kemudian saya ingin menambahkan attribute required di py nya, maka baik form dokter maupun pasien wajib mengisi field kode tersebut. Berbeda halnya jika attrbute required tersebut ditambahkan di form view dokter, maka required itu hanya berlaku di form dokter sementara di form pasien tidak.

Kemudian membuat action seperti :

<record model="ir.actions.act_window" id="ms_pendaftaran_action">
    <field name="name">Pendaftaran</field>
    <field name="res_model">ms.pendaftaran</field>
    <field name="view_type">form</field>
    <field name="view_mode">tree,form</field>
    <field name="context">{}</field>
    <field name="domain">[]</field>
</record>
 
<record id="ms_pendaftaran_action_tree" model="ir.actions.act_window.view">
    <field eval="1" name="sequence"/>
    <field name="view_mode">tree</field>
    <field name="view_id" ref="ms_pendaftaran_tree_view"/>
    <field name="act_window_id" ref="ms_pendaftaran_action"/>
</record>
 
<record id="ms_pendaftaran_action_form" model="ir.actions.act_window.view">
    <field eval="2" name="sequence"/>
    <field name="view_mode">form</field>
    <field name="view_id" ref="ms_pendaftaran_form_view"/>
    <field name="act_window_id" ref="ms_pendaftaran_action"/>
</record>

Di action kita bisa menambahkan domain/filter, sehingga hanya record-record tertentu sesuai filter yang akan muncul. Misalnya yang diterapkan pada action dokter dan pasien, meskipun data di tablenya bercampur, tapi data yang ditampilkan di menu nya terpisah.

dan menu seperti :

<menuitem action="ms_pendaftaran_action" id="ms_pendaftaran_menu" parent="ms_base.ms_transaksi_submenu" sequence="10"/>

Kemudian berikut ini contoh penulisan qweb report untuk membuat resep obat seperti yang ada pada addons puskesmas :

<odoo>
    <data>
        <template id="report_resepobat_document">
            <t t-call="report.external_layout">
                <t t-set="o" t-value="o.with_context({})"/>
                <div class="page">
                    <div class="oe_structure"/>
                    <h1 class="text-center">Resep Obat</h1>
                    <div class="row mt32 mb32">
                        <div t-if="o.name" class="col-xs-3">
                            <strong>Nomor :</strong>
                            <p t-field="o.name"/>
                        </div>
                        <div t-if="o.pasien_id" class="col-xs-3">
                            <strong>Pasien :</strong>
                            <p t-field="o.pasien_id.name"/>
                        </div>
                        <div t-if="o.tanggal" class="col-xs-3">
                            <strong>Tanggal :</strong>
                            <p t-field="o.tanggal"/>
                        </div>
                    </div>
                    <table class="table table-condensed">
                        <thead>
                            <tr>
                                <th><strong>Obat</strong></th>
                                <th><strong>Aturan Minum</strong></th>
                                <th><strong>Sebelum/Sesudah Makan</strong></th>
                                <th><strong>Quantity</strong></th>
                                <th><strong>Satuan</strong></th>
                            </tr>
                        </thead>
                        <tbody>
                            <tr t-foreach="o.resep_line" t-as="l">
                                <td>
                                    <span t-field="l.product_id.name"/>
                                </td>
                                <td>
                                    <span t-field="l.aturan_minum"/>
                                </td>
                                <td>
                                    <span t-field="l.waktu_minum"/>
                                </td>
                                <td>
                                    <span t-field="l.qty"/>
                                </td>
                                <td>
                                    <span t-field="l.satuan_id.name"/>
                                </td>
                            </tr>
                        </tbody>
                    </table>
                    <div class="oe_structure"/>
                    <div class="row" name="ttd" style="padding-top:20px;">
                        <div class="col-xs-4" style="text-align:center">
                            <div style="padding-bottom:60px;">Tertanda,</div>
                            <div> ( <span t-field="user.name"/> )</div>
                        </div>
                    </div>
                </div>
            </t>
        </template>
        <template id="report_resepobat">
            <t t-call="report.html_container">
                <t t-foreach="docs" t-as="o">
                    <t t-call="ms_puskesmas.report_resepobat_document"/>
                </t>
            </t>
        </template>
        <report 
            string="Resep Obat" 
            id="cpl_action_report_resepobat" 
            model="ms.pemeriksaan" 
            report_type="qweb-pdf" 
            name="ms_puskesmas.report_resepobat" 
            file="ms_puskesmas.report_resepobat" 
        />
    </data>
</odoo>

Praktek

Penulisan top menu dan group menu pada file ms_base/views/ms_menu.xml

Jika kita mendeklarasikan menuitem tanpa mempunyai attribute parent maka menu tersebut akan menjadi top menu. Kemudian jika ada menuitem yang parent nya ke top menu maka akan jadi group menu (yang terletak sebah kiri). Kemudian jika ada menuitem yang parent nya ke group menu (level ke tiga) maka akan menjadi menu yang terletak di bawah group menu. Selanjutnya jika ada menuitem baru yang parentnya ke menu level ke tiga tersebut maka akan menjadi dropdown, dan begitu selanjutnya.

Setiap menuitem bisa ditambakan action untuk menampilkan form ataupun tidak. Pada umumnya action akan ditambahkan pada menuitem level ke tiga, tapi meskipun begitu action tetap bisa ditambahkan pada menuitem pertama atau kedua. Selama rangkaian menu belum mempunyai action maka menu-menu tersebut tidak akan ditampilkan. Misalnya menu-menu di atas yang terletak pada modul ms_base tidak akan ditampilkan selama kita belum menginstal modul ms_puskesmas, karena action baru ditambahkan pada menuitem di modul ms_puskesmas yang parent nya ke menuitem di ms_base.

Penginputan pada umumnya dilakukan pada form view. Namun pada beberapa object yang hanya memiliki sedikit field seperti object ms.poli, penginputan dilakukan pada tree view. Untuk melakukan itu maka harus menambahkan attribute editable (top/bottom) pada blok tree seperti tree view poli di atas.

Ada 3 hal yang bisa kita tambahkan pada search view :

  • Nama field, fungsinya jika didefinisikan maka ketika kita mengetikkan sesuatu pada kolom search maka akan tampil saran beberapa field yang akan dipakai untuk melakukan filter.
  • Filter, fungsinya untuk melakukan filter otomatis sesuai dengan kriteria yang kita inginkan. Daftar filter ada di bawah kolom search, jika diklik maka data akan difilter sesuai kriteria yang sudah ditentukan. Jika filter tidak muncul seperti ini

maka klik advance search (icon kaca pembesar di sebelah kanan kolom search)

  • Group, fungsinya untuk mengelompokkan data secara otomatis berdasarkan field tertentu, cara penggunaannya hampir sama seperti filter. Harap diingat bahwa field yang bisa dipakai untuk grouping hanya field yang disimpan ke database.

Baik filter ataupun group sama-sama bisa ditambahkan manual lewat aplikasi. Namun akan lebih cepat kalau kita membuatnya di coding

Di sebelah kanan Group by ada Favorites, fungsinya untuk menyimpan current filter atau group bahkan kombinasi dari keduanya. Jadi jika suatu saat kita ingin melakukan filter dan/atau group yang sama maka tinggal klik Favorites yang sudah disimpan tersebut.

pada blok action kita bisa melakukan filter data yang akan ditampilkan, misal pada action dokter di atas data difilter hanya yang field dokternya True

pada context ‘default_dokter’:True fungsinya sama dengan attribute default field pada py. Bedanya kalau kita set default di py maka akan berlaku untuk semua object res.partner, sementara jika set di action xml maka hanya berlaku untuk form/action tertentu. Format penulisannya harus diawali dengan default, jadi default_nama_field.

search_view_id bisa ditambahkan bisa juga tidak. Tujuannya ditambahkan adalah jika kita mempunyai lebih dari satu search view untuk model yang sama maka harus menentukan search view mana yang akan dipakai di action tersebut. Dan jika hanya mempunyai satu search view maka tidak perlu menambahkan penulisan search_view_id. Tapi untuk jaga-jaga apabila nanti ada penambahan search view baru maka saran saya ditambahkan saja search_view_id tersebut.

Kemudian jika ada pertanyaan bagaimana jika tidak menambahkan search_view_id padahal kita mempunyai lebih dari satu search view? Maka jawabannya adalah akan menggunakan salah satu search view yang ditambahkan terakhir atau search view dengan sequence paling kecil. Kalau anda lihat view (baik search view, tree view, form view, dll) ada beberapa yang memakai parameter sequence, tujuannya adalah untuk penggunaan tersebut.

ms_dokter_action_tree dan ms_dokter_action_form fungsinya hampir sama dengan search_view_id, yaitu untuk menggunakan form/tree view tertentu secara spesifik. Jadi kita tidak harus selalu menambahkan kedua action tersebut.

Saat klik refund invoice maka akan muncul tampilan seperti di atas, tampilan tersebut dinamakan wizard.

Untuk form Pembayaran seluruhnya menggunakan bawaan odoo termasuk wizard ini, kita hanya menambahkan menunya saja. Kalau dicek nama model nya wizard ini menggunakan model “account.invoice.refund”.

Ada perbedaan antara model wizard dengan model lainnya, perbedaan tersebut adalah pada model wizard biasanya class nya menggunakan models.TransientModel. Dan perbedaan antara models.TransientModel dengan models.Model adalah pada models.TransientModel data yang disimpan di database bersifat sementara. Jadi apapun yang diinput di sana hanya akan disimpan sementara, dan akan dihapus otomatis setelah beberapa lama.

Print-an resep obat menggunakan qweb report yang cara pembuatannya bisa anda lihat pada file ms_puskesmas/report/report_resepobat.xml

Terimakasih, semoga bermanfaat dan CMIIW…

Tutorial odoo/openerp Indonesia