Anda di halaman 1dari 43

Belajar Odoo Untuk Pemula [Part 1/8]

Kalau anda adalah orang yang baru mengenal Odoo dan tertarik utk mempelajari
teknikalnya, tapi bingung harus mulai dari mana? Nah dalam tutorial ini saya ingin
memberikan tips langkah-langkah yang harus dilakukan untuk mulai mempelajari
Odoo dan langsung praktek membuat addons. Adapun pembahasan yang akan saya
sampaikan kurang lebih ada 8 poin, yaitu :

1. Apa saja yang harus disiapkan


2. Membuat dan menginstal addons kosong serta penjelasan isi file
__manifest__.py
3. Download addons yang sudah saya siapkan (tentang puskesmas), penjelasan
komposisi addons dan meng-explore cara penggunaan addons yang
didownload
4. Penjelasan mengenai class, object dan attributenya
5. Penjelasan mengenai fields dan attributenya
6. Penjelasan mengenai view, wizard dan qweb report
7. Penjelasan mengenai method, button dan workflow
8. Penjelasan mengenai inherit
Baiklah, mari kita mulai !

Hal pertama yang harus dilakukan tentu saja adalah menginstal odoo (versi 10).
Boleh menggunakan OS apa saja, tapi saya sarankan pakai linux. Karena dalam
tutorial ini saya menggunakan linux (Ubuntu 16.04). Anda bisa menginstalnya
dengan mengikuti tutorial ini Cara Install Odoo 10 di Ubuntu 14.04
LTS ataupun bisa cari tutorial lain di google.

Kedua, jika odoo nya sudah jalan silahkan coba buat database baru (gunakan data
dummy dengan men-centang checkbox Load demonstration data saat create database)
dan instal beberapa addons default. Saran saya instal 3 addons yang sering dipakai
yaitu Purchase Management, Inventory Management dan Sales. Kemudian coba
explore penggunaan dari masing-masing addons. Mulai dari pembelian barang, cek
ketersediaan barang di gudang dan melakukan penjualan.

Ketiga, siapkan folder baru untuk menyimpan custom addons, karena kita akan
praktek membuat addons sendiri dan ubah konfigurasi odoo agar custom addons
dapat terbaca di apps. Foldernya kita kasih nama custom_addons dan simpan di
dalam folder odoo, kalau anda menginstalnya dari blog saya maka folder odoo ada di
/home/nama_user_ubuntu/odoo-10.0. Kemudian edit konfigurasi dengan
membuka terminal dan ketikkan sudo nano /etc/odoo-server.conf sampai terbuka
tampilan berikut.
Ubah bagian addons_path jadi addons_path = /home/miftah/odoo-
10.0/addons,/home/miftah/odoo-10.0/custom_addons (jangan pakai spasi setelah koma)

Note : Ganti miftah dengan username ubuntu anda

Jika sudah selesai tekan ctrl + x, kemudian ketik y dan enter.

Konfigurasi sudah selesai dan anda sudah siap untuk membuat custom addons.

Keempat, install IDE yang anda suka utk mulai melakukan coding, saya sendiri
menggunakan sublime text.

Kelima, install pgadmin III untuk menampilkan isi database postgresql, dengan
syntax :

$ sudo apt-get install pgadmin3


Setelah selesai instal kemudian buka pgadmin dan buat koneksi baru dengan meng-
klik icon colokan kabel di pojok kiri atas, kemudian isi pop up yang muncul sebagai
berikut :
Password : odoo

Itulah langkah-langkah persiapan untuk mulai melakulan coding, pada tahap


selanjutnya kita akan mulai membuat addons.

Belajar Odoo Untuk Pemula [Part 2/8]


 Posted on22 February 2018
 by Miftahussalam
 1 Commenton Belajar Odoo Untuk Pemula [Part 2/8]
Pada bagian ini kita akan mulai praktek membuat addons. Addons yang akan kita
buat ini tidak akan memuat fungsi atau memberikan efek apapun terhadap
aplikasi, karena pada bagian ini saya hanya ingin menjelaskan syarat minimal
untuk membuat addons. Dan syarat minimal untuk membuat addons agar
terbaca di menu apps adalah dengan membuat satu folder dan satu file.

Sekarang silahkan buat folder baru di dalam folder custom_addons yang sudah
kita buat sebelumnya di part 1 /home/miftah/odoo/custom_addons, beri nama
new_addons. Kemudian buat satu file baru di dalam folder new_addons dan beri
nama __manifest__.py
File manifest berfungsi untuk mendeklarasikan python package sebagai modul
Odoo dan menentukan metadata modul. Penulisan file ini menggunakan single
dictionary yang berisi beberapa key dan value, yang mana setiap key
menunjukkan metadata modul.

Selanjutnya edit file __manifest__.py dan isi dengan {} atau agar lebih lengkap
isi dengan code berikut :

{
"name" : "New Addons",
"version" : "1.0",
"author" : "Miftahussalam",
"website" : "http://miftahussalam.com",
"category" : "New Module",
"summary" : "Ini adalah addons baru",
"description" : """
Latihan membuat addons baru di odoo 10
""",
"depends" : [
"base",
],
"data" : [

],
"demo" : [],
"test" : [],
"images" : [],
"qweb" : [],
"css" : [],
"application" : True,
"installable" : True,
"auto_install" : False,
}
Kemudian save dan sampai sini seharusnya addons sudah bisa terbaca di menu
apps. Silahkan jalankan service odoo (atau restart jika sebelumnya sudah
dijalankan) kemudian masuk ke menu Apps di browser, jangan lupa Aktifkan
Developer Mode agar muncul menu Update Apps List di submenu Apps.

Setelah itu update apps list dengan mengklik menu Update Apps List > Update
dan ketikkan new addons di kolom pencarian (pojok kanan atas), kemudian
enter. Jika berhasil maka akan muncul addons dengan nama New Addons sesuai
dengan nama addons yang kita buat.
Sampai sini maka addons sudah dapat terbaca di menu Apps, akan tetapi belum
bisa diinstal. Untuk menginstalnya maka kita harus menambahkan file baru
dengan nama __init__.py di dalam folder new_addons (sejajar dengan file
__manifest__.py). Biarkan file tersebut kosong, tidak perlu diisi.

Jika sudah, silahkan restart kembali service nya dan update apps list kemudian
instal addons nya

Selamat, anda sudah bisa membuat addons baru dan berhasil menginstalnya
Jika anda bertanya, “Lalu apa maksud dari isi file __manifest__.py”? Berikut
penjelasannya :

 name : tipe string, nama modul/addons


 version : tipe string, versi modul (harus mengikuti aturan semantic
versioning)
 author : tipe string, nama (personal/kelompok) pembuat modul
 website : tipe string, URL website pembuat modul
 category : tipe string (default: Uncategorized), kategori modul untuk
mengelompokkan dan memudahkan pencarian modul. Jika tidak diisi atau
bahkan tidak ditulis baris/key category sama sekali maka secara default
modul tersebut akan dikategorikan sebagai Uncategorized. Kategori juga
bisa hirarki dengan menggunakan separator /. Misal: New Module /
Master Data, maka akan membuat kategori New Module dan kategori
Master Data sebagai child dari New Modul. Dan modul tersebut akan
masuk ke kategori Master Data
 summary : tipe string, deskripsi singkat modul
 description : tipe string, (deskripsi lengkap mengenai modul)
 depends : tipe list(string), daftar modul yang harus ada (terbaca di
apps) agar modul ini bisa diinstal. Artinya harus ada karena modul yang
kita buat menggunakan fitur atau apapun yang terkait dengan modul yang
di depends ini. Ketika instal modul maka odoo akan menginstal modul
yang di depends terlebih dahulu, sebelum menginstal modul yang
sebenarnya kita instal. Dan ketika upgrade modul maka semua modul yang
men-depends ke modul tersebut akan ikut diupgrade, namun tidak berlaku
sebaliknya. Misal modul new_addons depends ke base, saat modul base
diupgrade maka modul new_addons juga akan diupgrade. Namun saat
modul new_addons diupgrade maka modul base tidak akan ikut diupgrade
 data : tipe list(string), daftar file data yang akan selalu diinstal atau
diupdate/upgrade bersamaan dengan modul. Merupakan path dari folder
root modul, biasanya merupakan file xml dan csv. Dan biasanya file yang
di load di sini merupakan file untuk membuat view, action, menu, security,
dll
 demo : tipe list(string), daftar file data yang hanya akan di load
ketika kita mencentang checkbox Load Demonstration Data ketika pertama
kali instal database. Merupakan path dari folder root modul, biasanya
merupakan file xml dan csv. Dan biasanya file yang di load di sini
merupakan file untuk menambahkan record master data atau transaksi
 test : tipe list(string), daftar file data yang hanya akan di load jika
kita menambahkan command --test-enable saat menjalankan service.
Merupakan path dari folder root modul atau bisa juga memanggil file dari
addons lain, biasanya merupakan file yml dan xml. Dan biasanya file yang
di load di sini merupakan file untuk menambahkan record master data
atau transaksi serta berisi proses-proses tertentu untuk melakukan
pengetesan terhadap modul
 images : tipe list(string), path file gambar yang akan digunakan oleh
modul. Note : di screenshot dan video saya menulisnya image (tanpa s),
seharusnya images
 qweb : tipe list(string), path file qweb/xml yang akan digunakan oleh
modul. File qweb harus disimpan di folder static/src/xml
 css : tipe list(string), path file css yang akan digunakan oleh modul.
File css harus disimpan di folder static/src/css
 application : tipe boolean (default: False), jika diisi True maka modul
dianggap sebagai aplikasi lengkap. Sementara jika diisi False dianggap
sebagai modul teknikal yang hanya menambahkan beberapa fungsional
terhadap modul aplikasi yang ada. Sebenarnya tidak terlalu berpengaruh
terhadap modul, hanya akan terfilter sebagai Apps di pencarian default
Apps
 installable : tipe boolean (default: False), jika diisi True maka modul
dapat diinstal dan jika diisi False maka tidak bisa diinstal. Meskipun
tombol instal tetap muncul dan bisa kita klik, tapi odoo tidak akan benar-
benar menginstal modul tersebeut. Note : Kalau saya lihat modul odoo
yang menggunakan ‘installable’: False maka modul tersebut tidak
mempunyai button install, tapi ketika saya buat modul sendiri maka
tombol install tetap muncul meskipun sudah diset False. Dan jujur saja
saya tidak tahu kapan harus set ‘installable’: False, karena logikanya kita

bikin modul untuk diinstal. Kalau anda tahu, please let me know hehe
 auto_install : tipe boolean (default: False), modul akan otomatis diinstal
jika semua modul dependencies nya terinstal. Dan jika modul tersebut
tidak mempunyai dependencies (baris/key depends nya kosong) maka
modul tersebut akan diinstal ketika create database
Diantara informasi metadata tersebut ada yang ditampilkan di interface odoo ada
juga yang tidak.

Sebenarnya masih ada lagi beberapa key metadata yang bisa dipakai dalam file
__manifest__.py tersebut, seperti maintainer, external_dependencies, license,
dll. Akan tetapi kita tidak perlu memasukkan semuanya, bahkan jika kita hanya
mengisi kurung kurawal {} pun modul tetap bisa terbaca di menu Apps. Selain itu
kita juga bisa mengisi key dan value baru yang tidak ada formatnya dari odoo,
asalkan sesuai dengan penulisan dictionary. Misalnya ‘nomor hp’:
‘085123456789’, ‘contributors’: ‘Miftah, Heru dan Ajeng’. Tambahan key value
tersebut tidak akan menyebabkan modul jadi error, tapi juga tidak akan
menambahkan efek apapun terhadap modul.

Perlu diingat bahwa penulisan metadata tersebut menggunakan format


dictionary yaitu ada key dan value, jika penulisannya salah seperti kurang tanda
kutip atau koma di akhir value maka akan menyebabkan addons tidak dapat
terbaca.

Jika anda masih belum berhasil menginstalnya, silahkan download addons yang
sudah saya buat berikut ini https://bitbucket.org/miftahussalam/new-
addons/get/f01b87fb260f.zip

Di bawah ini saya juga membuat tutorial dalam bentuk video yang berhubungan
dengan tutorial part 2 ini, silahkan disimak.

https://youtu.be/5R1Jtt4VZs8
Belajar Odoo Untuk Pemula [Part 3/8]
 Posted on22 February 2018
 by Miftahussalam
 4 Commentson Belajar Odoo Untuk Pemula [Part 3/8]
Seperti yang sudah saya sampaikan sebelumnya, di part 3 ini saya akan memberikan
addons tentang puskesmas yang sudah saya siapkan di sini. Silahkan didownload
dan dicopy ke folder custom_addons, uninstall dan hapus saja addons new_addons
yang sudah ditambahkan sebelumnya. Jangan lupa restart dan update apps list
setiap ada penambahan addons. Jika sudah selesai copy, silahkan instal semua
addons tersebut. Addons puskesmas ini dibuat khusus untuk tutorial ini

berdasarkan perkiraan jadi tidak mewakili proses puskesmas yang


sesungguhnya.

Semua menu yang ditambahkan dari addons tersebut disimpan di menu Puskesmas.
Menu-menu tersebut dikelompokkan jadi dua, yaitu master data dan transaksi.
Master data terdiri dari dokter, pasien, poli dan obat. Sementara transaksi terdiri
dari pendaftaran, pemeriksaan dan pembayaran.

Perbedaan master data dan transaksi secara fungsional saya rasa anda sudah faham,
jadi tidak perlu dijelaskan lagi. Namun secara teknis di odoo ada perbedaan yaitu
transaksi menggunakan workflow sementara master data tidak (workflow akan
dibahas di part 7). Proses di puskesmas ini diawali dari penginputan data dokter,
poli dan obat. Jika ada pasien yang datang maka input data pasien saat mendaftar
(kalau sebelumnya sudah pernah berobat maka tidak perlu diinput lagi). Kemudian
admin puskesmas mengisi data pendaftaran, selanjutnya pasien menunggu antrian
untuk dipanggil dokter. Jika sudah dipanggil maka pasien masuk ke ruang dokter
dan melengkapi data pemeriksaan termasuk memberikan resep obat kepada pasien
untuk ditebus di bagian obat. Setelah itu pasien menuju bagian obat untuk
mengambil dan membayar obat. Di sana admin bagian obat melakukan validasi data
pembayaran dan proses transaksi di puskesmas sudah selesai.

Silahkan anda explore penggunaannya lebih lanjut, dan untuk melihat contoh
penginputannya mari simak video berikut :

Komposisi Module/Addons

Setiap modul odoo yang kita buat dapat berisi penambahan proses, attribute,
tampilan, dll ataupun mengubah proses yang sudah ada, memperluas bahkan
menghapus beberapa tampilan default yang dirasa tidak perlu. Jadi setiap ingin
menambahkan atau mengubah proses default kita harus membuat modul baru dan
sangat tidak dianjurkan mengubah langsung pada modul aslinya.
Dan setiap modul odoo dapat berisi beberapa bagian berikut :

 Business objects : Ditulis menggunakan bahasa pemrograman python, dengan


ekstensi .py
 Data files : Ditulis menggunakan XML atau CSV. Kedua file ini akan
menambahkan data ke dalam table database. Dan data yang ditambahkan
tersebut dapat berfungsi sebagai tampilan/view aplikasi, konfigurasi, data
demo, dll
 Web controllers : Menangani permintaan dari web browsers
 Static web data : Gambar, CSS atau javascript file yang digunakan oleh web
interface atau website
Meskipun demikian, kita tidak harus selalu menambahkan semua bagian tersebut
ketika membuat modul. Tapi bisa hanya menambahkan salah satu atau beberapa
bagian saja. Misalnya dalam addons puskesmas yang anda download itu hanya
memuat file dengan ekstensi py, XML dan CSV.

Selain itu dalam penulisannya odoo juga biasanya membagi ke empat bagian
tersebut menjadi beberapa folder secara lebih spesifik sesuai dengan fungsinya
masing-masing. Ini sama dengan konsep MVC (model, view, controller) pada
aplikasi/sistem lainnya. Sebenarnya pembagian menjadi beberapa folder ini tidak
wajib (kecuali static file), kita tetap bisa menambahkan file-file tersebut tanpa
membagi jadi beberapa folder. Tapi dengan menerapkan konsep MVC ini dapat
memudahkan kita ketika development karena lebih rapi.

Kalau anda ingin melihat struktur folder pada modul default odoo bisa lihat di odoo-
10.0/addons. Odoo juga sudah menyediakan syntax untuk membuat modul odoo
secara otomatis yang akan menghasilkan struktur addons default. Yaitu dengan
masuk ke folder odoo di terminal dan ketikkan python odoo-bin scaffold <nama modul>
<folder penyimpanan>. Contoh :

$ cd /home/miftah/odoo-10.0
$ python odoo-bin scaffold coba custom_addons
Note : seperti biasa, ganti miftah dengan user ubuntu anda

Maka akan terbuat addons baru di folder custom_addons dengan struktur sebagai
berikut
Fungsi dari masing-masing folder tersebut adalah :

 controllers : berisi file untuk menangani permintaan dari web browser (py)
 demo : berisi data demo yang akan terbaca jika kita mencentang Load
Demonstration Data saat instal database (XML, CSV, YML)
 models : berisi file untuk mendeklarasikan object, field, method, dll (py)
 security : berisi file-file yang berhubungan dengan hak akses (XML, CSV)
 views : berisi file-file untuk membuat view atau mengatur tampilan (XML)
Selain beberapa folder tersebut, ada juga folder-folder lain yang sering dipakai,
seperti :

 doc : berisi file document (ODS, PDF)


 i18n : berisi file terjemahan (po, pot)
 report : berisi file-file report (py, XML)
 static : berisi file untuk mendukung tampilan, khususnya pada website (css, js,
png, gif, less, xml)
 test : berisi file untuk melakukan testing otomatis. Ini bisa dijalankan dengan
menambahkan --test-enable saat menjalankan service (YML, XML)
 tests : hampir sama dengan test, cuma beda ekstensi file (py)
 wizard : Membuat object dan tampilan pop-up, data yang diinput disimpan
sementara (py, XML)
 dll
Jujur saja dari beberapa folder tersebut belum semuanya saya coba, sehingga ada

beberapa yang saya tidak tahu fungsinya secara detail

Kemudian ada dua file yang harus ada :

 __manifest__.py : modul odoo dideklarasikan dengan __manifest__.py, jika


tidak ada file ini maka tidak akan terbaca di Apps. Penjelasan mengenai isi file
ini bisa dilihat kembali di part 2.
 __init__.py : modul odoo juga merupakan python package sehingga
menggunakan file __init__.py yang berisi perintah untuk mengimport
beberapa file python dalam modul. Jika file python terbagi menjadi beberapa
folder, maka setiap folder harus menyertakan file __init__.py dan pada file
__init__.py paling atas harus meng import folder-folder tersebut.
Belajar Odoo Untuk Pemula [Part 4/8]
 Posted on22 February 2018
 by Miftahussalam
 3 Commentson Belajar Odoo Untuk Pemula [Part 4/8]
Di part 2 anda sudah berhasil membuat addons kosong yang tidak memberikan efek
apapun terhadap aplikasi, kemudian di part 3 saya memberikan contoh addons yang
sudah berisi penambahan fungsi, view dan report yang terdiri dari file py dan xml.
Dan di part 4 ini kita akan membahas mengenai class, object dan attribute dari
object tersebut. Ketiga komponen tersebut ditulis dalam file py.

Komponen kunci dari odoo adalah ORM (Object Relational Mapping). Seperti yang
kita tahu ORM secara umum berfungsi untuk menghubungkan OOP dengan
database, jadi kita tidak perlu menuliskan syntax SQL secara langsung untuk
mengolah data di database (meskipun itu bisa dilakukan). Selain itu ORM juga
berfungsi untuk keamanan, karena melalui ORM akan dilakukan filter security
sesuai privilege user yang bersangkutan. Berbeda dengan kita menuliskan syntax
SQL secara langsung, maka tidak akan dilakukan pengecekan security. Tapi
meskipun demikian, ada beberapa kondisi dimana kita perlu untuk menuliskan
syntax SQL secara langsung tanpa menggunakan ORM, dengan resiko yang sudah
disebutkan sebelumnya.

Contoh penggunaan ORM :

pemeriksaan_ids = self.env['ms.pemeriksaan'].search([
('pendaftaran_id','=',me_id.id),
('state','!=','cancel')
])
Maka akan select ke database seperti berikut :

select * from ms_pemeriksaan where pendaftaran_id = 0 and state != '


cancel'
Note : angka 0 adalah id transaksi pendaftaran

Business objects dideklarasikan sebagai class python dengan menginherit super


class models.
Models mempunyai beberapa attribute, dan attribute yang paling penting
adalah _name yang harus ada dan menunjukkan nama dari model tersebut.

Berikut ini penjelasan lebih lanjut mengenai attribute yang dimiliki oleh models :


o _name : nama model yang harus ada untuk setiap model. Attribute
name ini akan menjadi table di database. Misalnya ketika kita
menulis _name = "ms.pendaftaran", maka akan membuat
table ms_pendaftarandi database. Nama model sering juga disebut object.
contoh : _name = “ms.pendaftaran”
o _rec_name : filed alternatif yang akan digunakan sebagai nama ketika
relasi ke object lain. Secara default, jika _rec_name tidak ditulis maka
akan menampilkan field name.
contoh : _rec_name = ‘partner_id’
o _inherit : untuk melakukan fungsi inheritance terhadap model yang
sudah dideklarasikan sebelumnya di addons lain. Dapat
menambahkan/mengubah field, method, attribute, dll.
contoh : _inherit = ‘ms.pendaftaran’
o _order : urutan data yang ditampilkan berdasarkan field tertentu, bisa
ascending atau descending. Secara default data diurutkan
berdasarkan id asc.
contoh : _order = ‘name desc’
o _auto : menunjukkan apakah akan dibuat table di database. Secara
default bernilai True, Jika diset False maka harus override init() untuk
membuat table. Jika tidak ingin membuat table maka set False dan
menggunakan models.AbstactModel.
contoh : _auto = False
o _table : nama table yang akan dibuat. Secara default sama dengan
_name.
contoh : _table = ‘tbl_pendaftaran’
o _inherits : ditulis dengan dictionary {‘nama_object_yg_diinherit’ :
‘field_relasi’}, bisa lebih dari satu. Fungsinya yaitu ketika membuat
record di object tersebut, maka akan membuat record juga di object yg
diinherit dengan menyimpan id record object yg di inherit pada field
relasi (many2one) di current object.
contoh : _inherits = {‘ms.pendaftaran’:’pendaftaran_id’}
o _sql_constraints : akan membuat unique constraint di database
contoh : _sql_constraints = [(‘unique_kode’,
‘unique(kode,name)’, ‘Kombinasi kode dan nama sudah ada,
mohon cek kembali !’)]
Artinya akan muncul warning saat menginput kombinasi kode dan
name yang sudah pernah diinput sebelumnya.
o _log_access : akan menambahkan beberapa field secara otomatis
ketika mendefinisikan object baru, secara default bernilai True. Field-
field yang ditambahkan tersebut adalah create_date, create_uid,
write_date dan write_uid.
contoh : _log_access = False

Praktek
Sekarang coba kita praktekkan beberapa attribute di atas ke dalam addons
puskesmas

Kita akan mengubah _rec_name poli sehingga nama poli yang tampil di form
pendaftaran adalah kodenya saja. Ikuti langkah-langkah berikut ini :

https://youtu.be/uhks46QbhEk
Penggunaan _sql_constraint sudah ada pada object “ms.poli” yaitu tidak boleh ada
kode yang sama, silahkan anda test dengan menginput kode yang pernah diinput
untuk record sebelumnya.

Di “ms.poli” pengurutan data pada tree view masih default, yaitu ‘id asc’. Sekarang
coba anda ubah menjadi ‘name asc’ atau ‘name’ saja (jika tidak menuliskan asc/desc
maka secara default adalah asc). Maka data yang diinput akan dirutkan berdasarkan
nama poli.
Belajar Odoo Untuk Pemula [Part 6/8]
 Posted on22 February 2018
 by Miftahussalam
 2 Commentson 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','!=','d
raft')]}"/>
<button name="action_cancel" string="Cancel" type="o
bject" attrs="{'invisible': [('state','=','cancel')]}"/>
<field name="state" widget="statusbar" statusbar_vis
ible="draft,confirm"/>
</header>
<sheet>
<div class="oe_title">
<h1>
<field name="name" class="oe_inline" readonl
y="1"/>
</h1>
</div>
<group col="4">
<field name="pasien_id" attrs="{'readonly': [('s
tate','!=','draft')]}" required="1" options="{'no_open': True, 'no_c
reate': True}"/>
<field name="poli_id" attrs="{'readonly': [('sta
te','!=','draft')]}" required="1" options="{'no_open': True, 'no_cre
ate': True}"/>
<field name="tanggal" attrs="{'readonly': [('sta
te','!=','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" pa


rent="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></t
h>
<th><strong>Sebelum/Sesudah Makan</s
trong></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:2
0px;">
<div class="col-xs-4" style="text-align:cent
er">
<div style="padding-bottom:60px;">Tertan
da,</div>
<div> ( <span t-field="user.name"/> )</d
iv>
</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_documen
t"/>
</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
Belajar Odoo Untuk Pemula [Part 7/8]
 Posted on22 February 2018
 by Miftahussalam
 Leave a commenton Belajar Odoo Untuk Pemula [Part 7/8]
Workflow

Hampir semua form transaksi di odoo mempunyai field state (seperti yang terlihat
pada gambar di bawah), field state tersebut berfungsi untuk melakukan tracking
perkembangan proses seiring dengan berjalannya waktu. Perkembangan proses
itulah yang dinamakan workflow.

Perubahan workflow akan di trigger oleh proses atau action-action tertentu, dan
biasanya action tersebut dijalankan oleh button.

Button

Cara penulisan button bisa lihat di addons puskesmas. Button ada dua type :

 action : ketika diklik akan memanggil record ir.actions.act_window yang


didefinisikan di xml
 object : ketika diklik akan memanggil method di py yang namanya sama
dengan nama button yang didefinisikan
Method

Method atau function di odoo hampir sama dengan function di bahasa


pemrograman lain. Trigger untuk memanggil method tersebut berbeda-beda. Ada
yang dijalankan oleh button, ada yang dipanggil di method lain, ada yang ditrigger
oleh field, dll. Gambar di atas merupakan contoh method yang dijalankan oleh
button, yang salah satu action di dalamnya adalah untuk menjalankan workflow.

Ada beberapa method default yang dimiliki oleh sebuah model. Method-method
tersebut otomatis ditambahkan ketika menambahkan model, meskipun kita tidak
menuliskannya. Method-method tersebut adalah :

 create(vals) → record : Membuat record baru untuk model bersangkutan.


Record yang dibuat valuenya diambil dari parameter vals dengan format
dictionary {‘nama_field1′:’value1’, ‘nama_field2′:’value2’, …}
misal {‘name’:’PO00001′}
return : record, misal purchase.order(1,)
 browse([ids]) → records : Mengambil recordset dari parameter list ids.
Misal browse([1,2,3]). Harus memberikan parameter minimal satu id.
return : recordset, misal purchase.order(1,2,3)
 unlink() : Menghapus data current recordset
return : True
 write(vals) : Mengubah value recordset yang valuenya diambil dari
parameter vals, sama seperti method create
return : True
 read([fields]) : Membaca value dari field yang diinginkan, bisa spesifik field
ataupun membaca seluruh fields yang ada di model yang bersangkutan. Jika
ingin mengambil beberapa field maka harus memberikan parameter nama
field dalam bentuk list, misal read([‘name’,’qty’]). Namun apabila ingin
mengambil semua field maka tidak perlu memberikan parameter, misal
read()
return : dictionary, misal {‘name’:’PO00001′, ‘qty’:5}
 search(args, offset=0, limit=None, order=None, count=False) :
Mencari recordset berdasarkan filter yang diberikan pada args. Penjelasan
dari masing-masing parameter di atas adalah :
– args = kriteria filter/domain yang diinginkan (karena bagian ini cukup
panjang maka akan dijelaskan di bawah). Jika ingin mengambil semua record
yang ada pada model bersangkutan, maka bagian args cukup ditulis list
kosong seperti []
– offset (format int, default None) = jumlah hasil yang akan diabaikan. Misal
jika hasil filter didapatkan 5 recordset dan offset nya samadengan 2 maka
recordset yang didapat adalah 3 recorset (5-2=3)
– limit (format int, default all) = kebalikan dari offset. Akan menampilkan
maksimal record sesuai value dari limit. Misal jika record hasil filter ada 7 dan
limit=5 maka yang ditampilkan hanya 5 record. Tapi jika limit=5 tapi hasil
dari filter didapat 3 record maka yang ditampilkan adalah 3
– order (format str, default None) = untuk mengurutkan hasil pencarian
berdasarkan field tertentu secara ascending atau descending. order ini bisa
dipadukan dengan offset atau limit. Misal jika saya ingin mengambil satu
record terakhir maka bisa tulis search([], limit=1, order=’id desc’)
– count (format bool, default False) = jika True maka hanya akan menghitung
jumlah record yang sesuai dengan kriteria filter dan return nilai jumlah
record yang sesuai. Misal jika record yang dihasilkan adalah 3 record maka
return nya adalah angka 5 (int)
return : recordset, misal purchase.order(1,2,3). Atau return int, misal 3
 search_count(args) → int : Menghitung jumlah record yang sesuai dengan
kriteria pencarian. Fungsi ini hampir sama dengan search([], count=True)
return : int
 name_search(name=”, args=None, operator=’ilike’, limit=100) →
records : Biasanya dipakai ketika ada relasi Many2one dari model lain ke
model yang bersangkutan. Fungsinya untuk mencari record yang sesuai saat
mengetikkan sesuatu pada field Many2one dengan kriteria filter yang sudah
ditentukan pada args. Penjelasan dari masing-masing parameter :
– name (type str) : inputan yang kita ketik pada field many2one
– args (type list) : opsional search domain
– operator (type str) : operator pembanding untuk domain pencarian seperti
‘like’ atau ‘=’
– limit (type int) : maksimal record yang akan direturn (sama dengan limit
pada method search())
return : list pasangan antara id dan name, misal [(6, ‘DFT/18/00005’),(7,
‘DFT/18/00006’)]
 fields_get([fields][, attributes]) : Mengambil daftar fields beserta
attibutenya. Bisa spesifik field-field dan attribute tertentu atau mengambil
semua fields dan attributes. Penjelasan parameter :
– fields (type list) : diisi dengan nama field jika ingin spesifik mengambil field
tertentu atau tidak perlu diisi jika ingin mengambil semuanya
– attributes (type list) : diisi dengan nama attribute field jika ingin spesifik
mengambil attribute tertentu atau tidak perlu diisi jika ingin mengambil
semuanya
return : dictionary {‘nama_field’ : {‘nama_attribute’:’value_attribute’}}
 default_get(fields) → default_values : Memberikan default value fields.
Parameter fields berisi list nama field yang ada pada model bersangkutan,
misal [‘name’,’date’]
return : dictionary, misal {‘name’:’ini default value’}
 copy(default=None) : Menduplikasi record pada model tertentu yang value
field dari record baru nya akan sama persis dengan record yang diduplikasi.
Kecuali field-field yang attribute copy=False. Parameter default berisi
dictionary {‘nama_field’:’value’}. Jika anda ingin mengisi value field record
baru dengan value yang berbeda dari record lama, maka bisa menambahkan
dictionary pada parameter default tersebut denga value yang diinginkan
return : record, misal purchase.order(1,)
 name_get() → [(id, name), …] : Biasanya dipakai untuk mengubah nama
yang akan ditampilkan pada field Many2one. Secara default nama yang
ditampilkan adalah mengambil dari field name atau _rec_name, tapi jika
method ini di override maka nama yang tampil adalah sesuai dengan yang
ditentukan di sini. Dan biasanya override name_get() selalu berbarengan
dengan name_search(), karena pencarian pada field Many2one harus
berdasarkan apa yang ditampilkan agar user tidak bingung
return : list pasangan antara id dan display name, misal [(6,
‘DFT/18/00005’),(7, ‘DFT/18/00006’)]
 dll
Selain method default kita juga bisa menambahkan method-method lain yang
diperlukan sesuai dengan konsep OOP.

Ketika membuat method/function di python kita bisa menambahkan parameter


ataupun tidak. Jika method mempunyai parameter maka saat memanggilnya pun
kita harus memberikan value untuk parameter tersebut. Dan kalau anda perhatikan
pada beberapa method yang mempunyai parameter, cara penulisannya ada yang
hanya menuliskan parameter dan ada juga yang ditulis dengan value nya
menggunakan samadengan. Itu artinya jika hanya menuliskan parameter maka
parameter tersebut wajib disertakan ketika pemanggilan. Tapi jika menggunakan
samadengan maka parameter tidak wajib disertakan dan jika tidak disertakan saat
pemanggilan maka value dari parameter tersebut secara default adalah sesuai
dengan yang ditulis di method itu.

Contoh : def get_product(self, default_code, type=’product’)


maka cara pemanggilannya bisa:
– self.get_product(‘A001′,’consu’), atau
– self.get_product(‘A001’)

Untuk cara pemanggilan pertama maka value dari type adalah ‘consu’. Sementara
pada pemanggilan kedua value type adalah ‘product’
Domains

Domain adalah list kriteria pencarian record yang ditulis dengan format
[(nama_field, operator, value)], dengan penjelasan masing-masing sebagai berikut :

 nama_field (type str) : nama field pada model bersangkutan atau nama field
pada model lain yang mempunyai relasi Many2one dengan model tersebut.
Misal ‘alamat’ atau ‘partner_id.name’ (partner_id adalah field Many2one
yang ada pada current model dan name adalah field yang ada pada model
relasi)
 operator (type str) : digunakan untuk mencocokkan antara nama_field dan
value. Operator yang bisa digunakan adalah :
=sama dengan (case sensitive)
Misal : [(‘name’, ‘=’, ‘dog’)], maka akan mencari name ‘dog’ (case sensitive)

!=tidak sama dengan (case sensitive)


Misal : [(‘name’, ‘!=’, ‘dog’)], maka akan mencari name selain ‘dog’ (case sensitive)

>lebih dari
Misal : [(‘qty’, ‘>’, 2)], maka akan mencari qty 3,4,5,dst

>=lebih dari atau sama dengan


Misal : [(‘qty’, ‘>=’, 2)], maka akan mencari qty 2,3,4,5,dst

<kurang dari
Misal : [(‘qty’, ‘<‘, 2)], maka akan mencari qty 1,0,-1,-2,dst

<=kurang dari atau sama dengan


Misal : [(‘qty’, ‘<=’, 2)], maka akan mencari qty 2,1,0,-1,-2,dst

=?tidak diisi (None atau False) atau sama dengan (case sensitive)
Misal : [(‘name’, ‘=?’, ‘dog’)], maka akan mencari name ‘dog’ atau name ‘ ‘ / False /
None

=like hampir sama dengan fungsi samadengan, tapi bisa menambahkan % pada
inputan sehingga fungsinya jadi sama dengan like (case sensitive)
Misal : [(‘name’, ‘=like’, ‘dog’)], maka akan mencari name ‘dog’. Jika pada inputan
ditulis %dog% maka akan mencari name ‘dog’, ‘doggy’, ‘bulldog’

likemengandung karakter (case sensitive)


Misal : [(‘name’, ‘like’, ‘dog’)], maka akan mencari name ‘dog’, ‘doggy’, ‘bulldog’

not like kebalikan dari like, tidak mengandung karakter (case sensitive)
ilike mengandung karakter (tidak case sensitive)
Misal : [(‘name’, ‘ilike’, ‘dog’)], maka akan mencari name ‘dog’, ‘doggy’, ‘bulldog’,
‘Dog’, ‘dOg’

not ilike kebalikan dari ilike, tidak mengandung karakter (tidak case sensitive)

=ilike hampir sama dengan fungsi samadengan, tapi bisa menambahkan % pada
inputan sehingga fungsinya jadi sama dengan ilike (tidak case sensitive)
Misal : [(‘name’, ‘=ilike’, ‘dog’)], maka akan mencari name ‘dog’, ‘Dog’, ‘DoG’, dll.
Jika pada inputan ditulis %dog% maka akan mencari name ‘dog’, ‘doggy’, ‘doGgy’,
‘bulldog’, ‘BulldoG’

in sama dengan salah satu dari list value (value harus list dan case sensitive)

not in tidak sama dengan semua list value (value harus list dan case sensitive)

child_of merupakan turunan dari value.Biasanya pada model yang mempunyai


attribute _parent_name (bentuk hirarki). Salah santu contoh model hirarki adalah
product.category dan stock.location

 value (type variable, yang bisa berisi str, int, dll) : yang akan dicocokkan
dengan nama field
Method Decorators

Penulisan method bisa menggunakan decorator ataupun tidak. Decorator ditulis


dengan awalan @ dan terdiri dari beberapa jenis API, sebagai berikut :

 @api.multi : method berisi recordset. Artinya self bisa berisi lebih dari satu
record
 @api.one : method hanya berisi satu record
 @api.model : self tidak mempunyai ids karena record belum disimpan ke
database
 @api.depends(‘nama_field1′,’nama_field2’) : merupakan daftar field yang
dapat men trigger method. Artinya jika field-field yang ditulis di depends ini
valuenya berubah maka method akan dijalankan/compute. Biasanya dipakai
pada field compute
 @api.constrains(‘nama_field1′,’nama_field2’) : hampir sama dengan
api.depends, fungsinya untuk melakukan pengecekan validasi data
 @api.onchange(‘nama_field1′,’nama_field2’) : triggernya hampir sama
seperti api.depends, fungsinya untuk memberikan value field, domain atau
memberikan warning
 dll
Praktek
Method def get_sequence pada addons ms_base diperlukan untuk penomoran
otomatis sesuai format tertentu. Method ini akan dipanggil di model lain, khususnya
di method create (karena penomoran akan muncul otomatis saat record transaksi di
save)

def _get_usia pada file ms_pemeriksaan merupakan method yang dipakai pada field
compute/function usia, menghitung usia dari tanggal kelahiran pasien. Method ini
menggunakan api.one karena untuk menghitung usia pasti hanya dari satu record.
Sebenarnya bisa juga menggunakan api.multi asal self nya di looping dulu

override def create untuk mengisi value field name dengan penomoran otomatis.
Saat override existing method kita harus menjalankan super(nama_class,
self).nama_method(parameter_jika_ada) agar action yang ada pada method asalnya
juga dijalankan. Jika kita override atau menulis ulang method tanpa menjalankan
super maka method aslinya atau method di parent modelnya tidak akan dijalankan

pada method def action_confirm dilakukan looping pada self karena seperti yang
dijelaskan di atas action_confirm menggunakan api.multi sehingga self bisa berisi
multi record. Method ini ditrigger oleh button Confirm yang nama button nya sama
dengan nama method. Saat button Confirm di klik maka dalam method
menjalankan action untuk mengubah state dari Draft menjadi Confirmed dan
membuat satu record pemeriksaan
Belajar Odoo Untuk Pemula [Part 8/8]
 Posted on22 February 2018
 by Miftahussalam
 2 Commentson Belajar Odoo Untuk Pemula [Part 8/8]

Inheritance
Model Inheritance

Odoo menyediakan dua mekanisme inheritance untuk memperluas model yang ada
dengan cara yang modular.

Pertama, memungkinkan modul untuk memodifikasi behavior model yang


didefinisikan pada modul lain, seperti :

 Menambahkan field
 Menambahkan constraint
 Menambahkan method
 Override field yang ada di model lain (mengubah attribute)
 Override method di model lain
 dll
Kedua, pendelegasian yang memungkinkan untuk menghubungkan semua record
model terhadap parent model. Jenis kedua ini ditulis dengan syntax _inherits seperti
yang sudah dibahas di part sebelumnya.

View Inheritance

View inheritance memungkinkan kita untuk menambah, memodifikasi ataupun


menghapus tampilan view yang didefinisikan di parent nya.

View inheritance me refer ke parent menggunakan inherit_id. Setelah itu kita bisa
memodifikasi isi dari view parent dengan menggunakan position.

<record id="ms_ir_module_module_search_view" model="ir.ui.view">


<field name="name">ms.ir.module.module.search</field>
<field name="model">ir.module.module</field>
<field name="inherit_id" ref="base.view_module_filter"/>
<field name="arch" type="xml">

<field name="name" position="after">


<field name="author"/>
<field name="website"/>
<filter name="filter_miftah" string="New Addons" domain=
"[('author','=','Miftahussalam')]"/>
</field>

</field>
</record>
position bisa berisi beberapa value :

 inside : akan menempatkan field/button baru di akhir elemen yang cocok


 replace : akan mereplace/meremove field/button dari model parent
 before : akan menempatkan field/button baru sebelum elemen
 after : akan menempatkan field/button baru setelah elemen
 attributes : mengubah atribut dari elemen yang cocok dengan elemen atribut
khusus yang ditambahkan

Praktek
Contoh inherit untuk menambahkan method salah satunya ada pada file
ms_base/models/ir_sequence.py

Method tersebut ditambahkan untuk memudahkan pembuatan nomor sequence


yang dipanggil di semua form transaksi (contoh: DFT/18/00005).
Pada file ms_puskesmas/models/res_partner.py inherit ke model res.partner
dengan tujuan untuk menambahkan fields, constraint dan override method.

Selain menambahkan field kita juga bisa mengubah attribute fields dengan cara
menulis ulang field beserta type nya yang sudah ada di model parent, dan kita hanya
perlu menuliskan attribute yang mau diubah atau ditambahkan. Misal kita akan
menggunakan field city di res.partner akan tetapi string nya mau diubah menjadi
‘Kota’, seperti ini :

Pertama-tama kita tambahkan field city di xml pada


file ms_puskesmas/views/res_partner.xml di bagian record id
“ms_pasien_form_view”
Terlihat pada tampilan aplikasi stringnya adalah ‘City’, kemudian kita akan ubah
menjadi ‘Kota’. Untuk melakukan itu sebenarnya ada dua cara. Pertama ubah di xml
dengan menggunakan attributes seperti yang diterapkan untuk field street di atas.
Kedua ubah di py seperti yang akan kita praktekkan sekarang.

Masih di file res_partner.py tambahkan field :

city = fields.Char(string='Kota')

Silahkan restart service dan upgrade, maka string filed city akan berubah menjadi
‘Kota’
Pada ms_base/views/ir_module_module.xml merupakan contoh inherit
view view_module_filter (tempat install addons pada menu Apps) untuk
menambahkan field author, website dan filter, serta membuat default filter agar
ketika klik menu Apps maka sudah otomatis ter filter hanya addons custom yang
muncul.

Selanjutnya kita akan coba praktekkan mekanisme inheritance yang kedua, yaitu
pendelegasian dengan menggunakan syntax _inherits.

Kita akan buat model master baru, yaitu model ms.room

Silahkan buat file baru di ms_puskesmas/models dengan nama ms_room.py dan isi
dengan syntax berikut

from odoo import fields, api, models

class ms_room(models.Model):
_name = "ms.room"
_description = "Poli"

name = fields.Char('Nama', required=True)


kode = fields.Char('Kode', required=True, copy=False)
posisi = fields.Char('Posisi Ruangan')

_sql_constraints = [
('unique_kode', 'unique(kode)', 'Kode Poli duplicate, mohon
cek kembali !'),
]

@api.multi
def name_get(self):
result = []
for me in self :
if me.posisi :
result.append((me.id, "%s - %s" % (me.posisi, me.nam
e)))
else :
result.append((me.id, me.name))
return result

@api.model
def name_search(self, name, args=None, operator='ilike', limit=1
00):
args = args or []
if name :
recs = self.search([
'|',
('posisi', operator, name),
('name', operator, name),
] + args, limit=limit)
else :
recs = self.search([] + args, limit=limit)
return recs.name_get()
dan di ms_puskesmas/views dengan nama ms_room.xml

<odoo>
<data>

<record model="ir.ui.view" id="ms_room_tree_view">


<field name="name">ms.room.tree</field>
<field name="model">ms.room</field>
<field name="arch" type="xml">
<tree string="Ruangan" editable="top">
<field name="kode"/>
<field name="name"/>
<field name="posisi"/>
</tree>
</field>
</record>

<record id="view_ms_room_search" model="ir.ui.view">


<field name="name">ms.room.search</field>
<field name="model">ms.room</field>
<field name="arch" type="xml">
<search string="Search Ruangan">
<field name="name"/>
<field name="kode"/>
<field name="posisi"/>
</search>
</field>
</record>

<record model="ir.actions.act_window" id="ms_room_action">


<field name="name">Ruangan</field>
<field name="res_model">ms.room</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_room_action_tree" model="ir.actions.act_windo


w.view">
<field eval="1" name="sequence"/>
<field name="view_mode">tree</field>
<field name="view_id" ref="ms_room_tree_view"/>
<field name="act_window_id" ref="ms_room_action"/>
</record>

<menuitem action="ms_room_action" id="ms_room_menu" parent="


ms_base.ms_data_master_submenu" sequence="25"/>

</data>
</odoo>
Jangan lupa tambah import ms_room di ms_puskesmas/models/__init__.py dan
update __manifest__.py untuk membaca file ms_puskesmas.xml

Kemudian update isi file ms_poli.py dan ms_poli.xml seperti berikut :

ms_poli.py

from odoo import fields, api, models

class ms_poli(models.Model):
_name = "ms.poli"
_description = "Poli"
_inherits = {'ms.room': 'room_id'}

room_id = fields.Many2one('ms.room', string='Ruangan', ondelete=


'restrict', required=True, auto_join=True)
name = fields.Char(related='room_id.name', inherited=True)
kode = fields.Char(related='room_id.kode', inherited=True)

@api.multi
def name_get(self):
result = []
for me in self :
result.append((me.id, "%s - %s" % (me.kode, me.name)))
return result

@api.model
def name_search(self, name, args=None, operator='ilike', limit=1
00):
args = args or []
if name :
recs = self.search([
'|',
('kode', operator, name),
('name', operator, name),
] + args, limit=limit)
else :
recs = self.search([] + args, limit=limit)
return recs.name_get()
ms_poli.xml

<odoo>
<data>

<record model="ir.ui.view" id="ms_poli_tree_view">


<field name="name">ms.poli.tree</field>
<field name="model">ms.poli</field>
<field name="arch" type="xml">
<tree string="Poli">
<field name="kode"/>
<field name="name"/>
<field name="room_id" readonly="1" attrs="{'invi
sible': [('id','=',False)]}"/>
<field name="id" invisible="1"/>
</tree>
</field>
</record>

<record model="ir.ui.view" id="ms_poli_form_view">


<field name="name">ms.poli.form</field>
<field name="model">ms.poli</field>
<field name="arch" type="xml">

<form string="Poli">
<sheet>
<group col="4">
<field name="kode"/>
<field name="name"/>
<field name="room_id" readonly="1" attrs
="{'invisible': [('id','=',False)]}" required="0"/>
<field name="id" invisible="1"/>
</group>
</sheet>
</form>

</field>
</record>

<record id="view_ms_poli_search" model="ir.ui.view">


<field name="name">ms.poli.search</field>
<field name="model">ms.poli</field>
<field name="arch" type="xml">
<search string="Search Poli">
<field name="name"/>
<field name="kode"/>
<field name="room_id"/>
</search>
</field>
</record>

<record model="ir.actions.act_window" id="ms_poli_action">


<field name="name">Poli</field>
<field name="res_model">ms.poli</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_poli_action_tree" model="ir.actions.act_windo


w.view">
<field eval="1" name="sequence"/>
<field name="view_mode">tree</field>
<field name="view_id" ref="ms_poli_tree_view"/>
<field name="act_window_id" ref="ms_poli_action"/>
</record>

<record id="ms_poli_action_form" model="ir.actions.act_windo


w.view">
<field eval="1" name="sequence"/>
<field name="view_mode">form</field>
<field name="view_id" ref="ms_poli_form_view"/>
<field name="act_window_id" ref="ms_poli_action"/>
</record>
<menuitem action="ms_poli_action" id="ms_poli_menu" parent="
ms_base.ms_data_master_submenu" sequence="30"/>

</data>
</odoo>
Silahkan upgrade modul sehingga muncul menu baru di Data Master yaitu menu
Ruangan

Jika belum berhasil/error silahkan ambil source code berikut puskesmas branch
lanjut

ms.poli menginherits ms.room sehingga setiap create Poli baru maka akan otomatis
membuat Ruangan baru dengan nama dan kode yang sama. Tapi tidak berlaku
sebaliknya, ketika membuat ruangan baru tidak akan otomatis membuat poli.
Karena setiap poli pasti membutuhkan ruangan, tapi tidak setiap ruangan ditujukan
untuk poli.

Silahkan lakukan testing dengan membuat poli baru

Note : Jika sebelumnya master poli sudah terdapat record maka akan ada error
akses. Cara mengatasinya silahkan hapus semua record poli lewat pgAdmin.

Berikut contoh penginputannya

https://youtu.be/q2kZksnU2po
Alhamdulillah, kita sudah menyelesaikan materi dasar odoo teknikal. Saya rasa jika
anda sudah memahami materi-materi yang disampaikan dari part 1-8 ini maka

sudah cukup untuk menumbuhkan benih-benih cinta terhadap odoo

Saran saya setelah ini anda harus mempelajari satu materi lagi yang belum dibahas
di serial ini dan cukup penting ketika implementasi, yaitu mengenai hak akses. Dan
insya Allah di lain waktu saya juga akan membahasnya di blog ini.

Saya menyadari tutorial ini masih banyak kekurangan, dan insya Allah saya akan
terus mengupdate dan melengkapinya agar lebih mudah difahami. Kemudian jika
yang saya sampaikan terdapat kekeliruan mohon beri tahu saya karena saya juga
masih belajar.

Anda mungkin juga menyukai