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’

like mengandung 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

Terimakasih, semoga bermanfaat dan CMIIW…

Tutorial odoo/openerp Indonesia