Pemrograman Javascript pada Odoo (Bagian Empat) – Field Attribute dan Ajax

Artikel ini adalah bagian keempat dari seri pemrograman javascript pada odoo. Jika anda belum membaca artikel bagian pertama sampai ketiga, saya sarankan untuk membaca ketiga artikel tersebut terlebih dahulu. Linknya seharusnya bisa anda temukan di bagian bawah halaman ini.

Pada bagian keempat ini saya akan membahas bagaimana menambah dan menggunakan attribute dan melakukan ajax call.

Pada umumnya ada 3 cara penulisan attribute, yang pertama yaitu dengan cara langsung menulisnya pada field, seperti attribute invisible pada kode dibawah ini.

<field name="partner_id" invisible="1" />

Cara yang kedua adalah dengan memasukkan attribute tersebut didalam attribute attrs, seperti pada kode di bawah ini.

<field name="partner_id" attrs="{'invisible': [('user_id','=',False)]}" />

Sedangkang cara yang ketiga adalah dengan memasukkan attribute tersebut didalam attribute options, seperti yang telah kita lakukan pada seri kedua.

<field name="field_one" widget="widget_one" options="{'step': 1000}"/>

Sebagai contoh kasus, mari kita tambah sebuah tombol baru di widget yang sudah kita buat sejak seri pertama dengan kode di bawah ini.

<?xml version="1.0" encoding="UTF-8"?>
<template>

    <t t-name="WidgetOneTemplate">
        <div>
            <t t-if="widget.mode == 'edit' ">
                <div class="input-group">
                    <div class="input-group-prepend">
                        <button class="btn btn-danger btn-minus"> - </button>
                    </div>
                    <input type="text" class="form-control" t-att-value="formated_value" disabled="disabled" />
                    <div class="input-group-append">
                        <button class="btn btn-success btn-plus"> + </button>
                        <button class="btn btn-primary btn-copy"><i class="fa fa-copy"></i></button>
                        <!-- Tombol tambahan di tutorial bagian keempat -->
                        <button class="btn btn-warning btn-dollar"><i class="fa fa-dollar"></i></button>
                    </div>
                </div>
            </t>
            <t t-if="widget.mode == 'readonly' ">
                <span t-esc="formated_value" />
            </t>
        </div>
    </t>

</template>

Tampilan form akan menjadi seperti pada gambar di bawah ini.

Tambah tombol pada widget odoo

Selanjutnya mari kita tambah sebuah attribute pada field yang menggunakan widget yang telah kita buat, seperti pada kode di bawah ini.

<field name="field_one" widget="widget_one" options="{'step': 1000}" relatedModel="sale.order" />

Pada kode diatas saya telah menambah attribute relatedModel dengan value sale.order, sedangkan attribute options sudah ada sejak seri kedua. Lalu bagaimana cara mendapatkan value dari attribute relatedModel tersebut jika user melakukan klik pada tombol dengan class btn-dollar ?

Pertama kita perlu menambah event click pada tombol dengan class btn-dollar yang telah kita buat sebelumnya, kali ini saya memilih menggunakan cara yang telah kita bahas pada seri kedua, alih-alih menggunakan cara yang kita bahas di seri ketiga, yaitu dengan kode berikut ini.

events: { // daftar event, mirip event di jquery
    'click .btn-minus': 'btn_minus_action',
    'click .btn-plus': 'btn_plus_action',
    'click .btn-dollar': 'btn_dollar_action', // tambahan di seri bagian 4
},

Sedangkan untuk mendapat value dari suatu attribute kita bisa menggunakan kode di bawah ini.

btn_dollar_action: function(){
    console.log(this.attrs.relatedModel)
},

Selanjutnya bagaimana jika kita mengubah kode field di atas menjadi seperti ini ?

<field name="field_one" widget="widget_one" options="{'step': 1000}" relatedModel="sale.order" attrs="{'relatedAction': 'get_last_order_amount'}" />

Untuk mendapatkan value dari attribute relatedAction di atas kita bisa menggunakan kode di bawah ini.

btn_dollar_action: function(){
    console.log(this.attrs.modifiers.relatedAction)
},

Sebenarnya jika kita melakukan console.log() pada variabel this seperti pada kode di bawah ini.

btn_dollar_action: function(){
    console.log(this)
},

Kita akan bisa melihat semua property dan value yang dimiliki oleh widget tersebut, termasuk value dari property attrs, yang terlihat seperti pada gambar di bawah ini.

nilai attribute atts odoo

Oleh karena itu, untuk mendapatkan nilai dari attribute step kita juga bisa menggunakan kode this.attrs.options.step alih-alih menggunakan kode this.nodeOptions.step seperti yang telah kita lakukan di seri bagian kedua.

Selanjutnya kita akan membahas bagaimana melakukan ajax call ke server dari widget yang telah kita buat.

Tetapi sebelum menulis kode ajax kita perlu menentukan kita akan memanggil aksi pada controller atau aksi pada model. Karena caranya berbeda. Kali ini kita akan membahas bagaimana memanggil aksi/method pada suatu model terlebih dahulu. Sebagai contoh kasus anggaplah pada model sale.order kita memiliki method seperti pada kode di bawah ini.

class SaleOrder(models.Model):
    _inherit = 'sale.order'

    def get_last_order_amount(self):
        print('get_last_order_amount=====called=======')
        print(self)
        return 1000

Ingat pada awal-awal tulisan ini kita telah mengatur field agar memiliki attribute seperti pada kode di bawah ini.

<field name="field_one" widget="widget_one" options="{'step': 1000}" relatedModel="sale.order" attrs="{'relatedAction': 'get_last_order_amount'}" />

Kita akan memanfaatkan attribute relatedModel dan attribute relatedAction di atas agar widget yang kita buat bisa digunakan untuk mendapatkan data dari semua model secara dinamis. Misal di form lain jika widget yang kita buat bisa mendapatkan data dari model purchase.order kita bisa menggunakan kode seperti ini.

<field name="field_one" widget="widget_one" options="{'step': 1000}" relatedModel="purchase.order" attrs="{'relatedAction': 'get_last_order_amount'}" />

Tentu saja kita harus menambah method get_last_order_amount di model purchase.order terlebih dahulu agar kode bisa berjalan.

Ok. Sekarang mari kita tulis kode ajax yang memanggil aksi suatu model saat user melakukan klik pada tombol dengan icon dollar.

btn_dollar_action: function(){
    var self = this;
    this._rpc({
        model: this.attrs.relatedModel,
        method: this.attrs.modifiers.relatedAction,
        args: [[]]
    }).then(function(result){
        self._setValue(result.toString());
    });            
},

Jika anda perhatikan dan anda sudah membaca tulisan saya tentang Memanggil API Odoo dengan PHP maka parameter yang dilewatkan pada method _rpc sangatlah mirip. Value dari property model adalah nama model yang akan kita panggil, sedangkan value dari property method adalah nama method dari model tersebut. Semua public method dari suatu model baik bawaan odoo seperti read, search, search_name, create dll atau public method yang kita tambahkan, dalam kasus ini adalah method get_last_order_amount dapat dipanggil lewat ajax, sama dengan saat kita memanggil external API odoo.

Berikut ini adalah screenshot setelah user klik tombol dengan icon dolar.

memanggil method odoo lewat widget

Dari gambar di atas terlihat bahwa ajax telah dieksekusi dengan baik dilihat dari log di google chrome developer tool, log di terminal komputer saya, dan nilai dari widget yang telah kita buat pun sudah diganti dengan nilai dari server.

Selanjutnya kita akan membahas bagaimana mengisi dan menggunakan property args. Pada contoh diatas value dari index pertama dari properti args adalah sebuah array kosong, oleh karena itu, di python jika kita memanggil kode print(self) odoo akan menampilkan model kosong juga, perhatikan gambar terminal saya di atas. Kemudian anggaplah di database saya, saya memiliki sales order dengan id 1 dan 2 kemudian saya mengganti kode widget menjadi seperti ini.

btn_dollar_action: function(){
    var self = this;
    this._rpc({
        model: this.attrs.relatedModel,
        method: this.attrs.modifiers.relatedAction,
        args: [[1,2]]
    }).then(function(result){
        self._setValue(result.toString());
    });            
},

Dan mengubah kode python menjadi seperti ini.

def get_last_order_amount(self):
    print('get_last_order_amount=====called=======')
    print(self)
    value = 0
    for order in self:
        print('oder_id====', order.id)
        print('customer====', order.partner_id.name)
        print('amount====', order.amount_total)
        value += order.amount_total
    return value

Secara otomatis object self akan berisi informasi dari sales order dengan dengan id 1 dan 2. Kita tidak perlu melakukan pencarian secara manual dengan method search atau browse untuk mengetahui sales order dengan id 1 dan 2 itu milik siapa.

memanggil method odoo lewat widget

Selanjutnya bagaimana jika kita menambah positioned argument pada method sales order di atas ? Seperti pada kode di bawah ini ?

def get_last_order_amount(self, value_1, value_2):
    print('get_last_order_amount=====called=======')
    print(self)
    print(value_1)
    print(value_2)
    value = 0
    for order in self:
        print('oder_id====', order.id)
        print('customer====', order.partner_id.name)
        print('amount====', order.amount_total)
        value += order.amount_total
    return value

Untuk mengisi positioned argument, dalam contoh di atas adalah argument value_1 dan value_2 kita bisa menulisnya secara berurutan setelah parameter array yang berisi id dari model. Seperti pada kode di bawah ini.

btn_dollar_action: function(){
    var self = this;
    this._rpc({
        model: this.attrs.relatedModel,
        method: this.attrs.modifiers.relatedAction,
        args: [[1,2],100,200]
    }).then(function(result){
        self._setValue(result.toString());
    });            
},

Seperti yang sudah kita ketahui, positioned argument harus selalu diisi nilainya, karena tidak memiliki nilai default, kalau tidak akan muncul error. Lalu bagaimana jika method yang kita panggil memiliki positioned argument dan default value argument(saya biasa memanggil argument ini sebagai keyword argument), seperti pada kode di bawah ini ?

def get_last_order_amount(self, value_1, value_2, value_3=3, value_4=4):
    print('get_last_order_amount=====called=======')
    print(self)
    print(value_1)
    print(value_2)
    print(value_3)
    print(value_4)
    value = 0
    for order in self:
        print('oder_id====', order.id)
        print('customer====', order.partner_id.name)
        print('amount====', order.amount_total)
        value += order.amount_total
    return value

Jika anda ingin mengirim semua nilai untuk semua argument, anda hanya perlu menulis nilainya secara berurutan seperti pada kode di bawah ini.

btn_dollar_action: function(){
    var self = this;
    this._rpc({
        model: this.attrs.relatedModel,
        method: this.attrs.modifiers.relatedAction,
        args: [[1,2],100,200,300,400]
    }).then(function(result){
        self._setValue(result.toString());
    });            
},

Tetapi jika anda hanya ingin mengisi nilai dari keyword argument tertentu saja anda harus menulisnya di property kwargs, seperti pada kode di bawah ini.

btn_dollar_action: function(){
    var self = this;
    this._rpc({
        model: this.attrs.relatedModel,
        method: this.attrs.modifiers.relatedAction,
        args: [[1,2],100,200],
        kwargs: {value_4: 4000}                
    }).then(function(result){
        self._setValue(result.toString());
    });            
},

Selanjutnya kita akan membahas bagaimana melakukan ajax call ke odoo controller.

Berbeda dengan ajax ke model, untuk melakukan ajax ke controller kita tidak bisa menggunakan method this._rpc, tetapi harus menggunakan method rpc dari object session. Oleh karena itu kita perlu mengimportnya terlebih dahulu dengan kode di bawah ini.

var session = require('web.session');

Perlu anda ingat, saat mengimport object web.session kita harus menggunakan huruf s kecil, bukan S besar, karena odoo juga memiliki object web.Session dengan huruf S besar. Kemudian anggaplah kita memiliki controller seperti di bawah ini.

# -*- coding: utf-8 -*-

from odoo import http
from odoo.http import request


class TutorialController(http.Controller):

    @http.route(['/tutorial/amount'], type='json', auth='user')
    def get_amount(self, **kwargs):
        print('Controller=====/tutorial/amount=====called')
        print(kwargs)
        return 20000

Selanjutnya untuk melakukan panggilan ajax ke controller tersebut dari widget, kita bisa menggunakan kode seperti ini.

btn_dollar_action: function(){
    var self = this;
    session.rpc(
        '/tutorial/amount',
        {
            'oder': [1,2]
        }
    ).then(function(result){
        self._setValue(result.toString());
    });            
},

Hasilnya akan terlihat seperti pada gambar di bawah ini.

memanggil method odoo lewat widget

Saat kita melakukan ajax call ke controller kita harus melakukan semuanya secara manual. Misal jika kita ingin tahu sales order dengan id 1 dan 2 itu milik siapa, maka kita harus memanggil method search atau browse pada model sale.order. Jika melakukan ajax call ke model hal ini akan berjalan secara otomatis. Tetapi ajax call ke controller juga memiliki kelebihan sendiri, misal kita bisa menggunakan method sudo untuk mem-bypass hak akses. Oleh karena itu jika user tidak memiliki hak akses Read ke model sale.order maka kita bisa menggunakan method sudo sehingga prosess tetap bisa berjalan. Sedangkan jika kita melakukan ajax call ke model dan user tidak memiliki hak akses Read pada model tersebut sebuah error akan muncul. Jadi pilih dan gunakan sesuai kebutuhan.

Download Source Code
Tulisan Serupa

6 Replies to “Pemrograman Javascript pada Odoo (Bagian Empat) – Field Attribute dan Ajax”

  1. hallo mas, saya mau bertanya. saya sudah buat widget dalam bentuk button yang digunakan user untuk menyimpan data dari pop up ke dalam elemen , tapi pas di klik data nya tidak tampil di dalam elemen .

    kira-kira ada solusi?

    Thankyou

  2. hallo mas, saya mau bertanya.
    saya sudah membuat widget dalam bentuk button yang rencananya akan digunakan untuk simpan data dari pop up ke dalam elemen notebook page , tetapi kendalanya adalah ketika button di klik data yang sudah di input tidak tampil di dalam elemen notebook page tersebut. dan pas di cek di console, semua data yang sudah di input muncul undefined.

    kira-kira ada solusi ?

    Thankyou

    1. tidak bisa kasih saran tanpa lihat kodenya, kemungkinan salah nama class/id kalau pakai jquery, misal waktu pakai kode

      $('.my_input').val();
      1. ini kodenya mas, saya pake input nya checkbox.

        _onClickButton: function () {
        var self = this;
        var deret_value = $(‘input[name=”deret_value”]:checked’).val();
        var mesin_produksi_id = $(‘input[name=”mesin_produksi_id”]:checked’).val();
        var putus_lusi = this.$(‘input[data-field=”putus_lusi”]’).is(“checked”);
        var putus_pakan = this.$(‘input[data-field=”putus_pakan”]’).is(“checked”);
        var bendera_merah = this.$(‘input[data-field=”bendera_merah”]’).is(“checked”);
        var ambrol = this.$(‘input[data-field=”ambrol”]’).is(“checked”);
        var dedel = this.$(‘input[data-field=”dedel”]’).is(“checked”);
        var hb = this.$(‘input[data-field=”hb”]’).is(“checked”);
        var naik_beam = this.$(‘input[data-field=”naik_beam”]’).is(“checked”);
        var oh = this.$(‘input[data-field=”oh”]’).is(“checked”);
        var preventif = this.$(‘input[data-field=”preventif”]’).is(“checked”);
        var lain_lain = this.$(‘textarea[data-field=”lain_lain”]’).val();

        1. maaf aku tidak bisa lihat apa yang salah dari potongan kode ini, sepertinya sih ok. kalau masih tidak bisa mungkin bisa kirim demo module

Leave a Reply

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