Web Service dengan XML-RPC

9. Web Service dengan XML-RPC

Penulis: Noprianto

9.1 ERP dan sistem berjalan

Dalam implementasi sebuah ERP, umum ditemukan perusahaan telah memiliki sistem yang berjalan sebelumnya. Sistem tersebut, walaupun mungkin lebih sederhana ataupun kurang terintegrasi, biasanya telah terbiasa digunakan.

Dan, tak jarang, proses transisi ke sebuah ERP membutuhkan dua sistem berjalan berdampingan. Idealnya, sistem lama secara bertahap perlu dikurangi. Tapi, kondisi di lapangan bisa sangat bervariasi. Kadang-kadang, terdapat resistensi yang cukup tinggi dari sisi user. Permasalahannya, semakin lama perusahaan menjalankan dua sistem, semakin jauh pula implementasi sebuah ERP bisa sukses, terutama kalau terdapat perbedaan antar sistem yang fundamental.

Salah satu strategi yang dapat dilakukan adalah dengan konversi data dari sistem lama ke sistem baru, yang dilakukan secara bertahap. Ini dilakukan sambil pelatihan ERP dilakukan kepada user. Strategi ini dapat kita lakukan apabila sistem yang saat ini berjalan sudah tidak dapat dimodifikasi lagi, misal karena source code program tidak tersedia.

Tapi, mari bayangkan situasi dimana sistem berjalan dikembangkan sendiri oleh tim IT internal. Para pengembangnya masih bekerja di perusahaan dan modifikasi bisa dilakukan dengan relatif cepat. Yang ingin kita lakukan adalah ketika data entri dilakukan, langsung disimpan pada server OpenERP. Apabila terdapat laporan sederhana, secara bertahap, juga dapat diambil dari server OpenERP. User interfacenya bisa tetap sama (atau dengan sedikit penyesuaian).

Kita mengetahui bahwa OpenERP menggunakan database system PostgreSQL. Dan, pustaka untuk bekerja dengan database ini tersedia untuk banyak bahasa pemrograman. Jadi, kita mungkin bisa menulis/membaca langsung pada database server-nya. Tentang skema data, karena ini terbuka, maka kita bisa pelajari.

Tapi, coba pikirkan lebih lanjut beberapa pertimbangan berikut: • Akses langsung pada database PostgreSQL mungkin tidak diberikan. Untuk alasan keamanan,

umumnya, database server hanya mengijinkan akses dari OpenERP server. • Kita perlu mempelajari skema yang digunakan. Dengan ratusan tabel dan relasi diantara mereka, ini bukan pekerjaan mudah. • Yang paling penting: dengan arsitektur OpenERP, akses langsung pada database tidak disarankan. Sebagai gantinya, OpenERP menyediakan web service yang akan jauh lebih mudah, nyaman dan

aman untuk digunakan.

9.2 Membangun frontend sendiri

Bagi Anda yang tidak perlu mengalami permasalahan yang dibahas sebelumnya, mari kita anggap Anda cukup beruntung.

Tapi, setelah implementasi tahap awal dilakukan, manajemen mungkin beranggapan bahwa user interface OpenERP tidak selalu cocok digunakan untuk semua user. Sebagai contoh, user di divisi/departemen tertentu akan dapat bekerja lebih cepat apabila sepenuhnya menggunakan keyboard. Tanpa mouse, tanpa GUI, hanya berbasis teks saja.

Lebih lanjut lagi, rupanya terdapat sebagian user yang ingin mengakses ERP lewat perangkat mobile (untuk sebagian kecil fitur). Walaupun akses langsung pada user interface OpenERP (misal lewat VPN) secara teknis dapat dilakukan, manajemen mungkin lebih memilih untuk membangun sistem terpisah, yang tetap terintegrasi dengan OpenERP. Sistem terpisah tersebut yang akan melayani permintaan dari perangkat mobile.

Atau, terdapat contoh kasus lain, dimana input data dilakukan secara otomatis, terus menerus, secara realtime. Data didapatkan dari komputer yang terhubung pada perangkat keras tertentu.

Seberapa jauh Anda perlu atau ingin membangun frontend atau sistem sendiri yang tetap terhubung ke OpenERP, akses langsung pada database seperti disinggung sebelumnya tetap tidak disarankan. Dan, kita akan selalu mengandalkan web service yang telah disediakan.

9.3 XML-RPC dan Python

Terdapat beberapa protokol web service yang disediakan oleh OpenERP, namun bab ini hanya akan membahas XML-RPC. Protokol ini memungkinkan Remote Procedure Call (RPC) yang: • menggunakan XML untuk mengencode pemanggilan • menggunakan HTTP sebagai mekanisme transport

Protokol ini dikembangkan pada tahun 1998. Pustaka untuk berbagai bahasa pemrograman juga mudah ditemukan.

Khusus untuk Python, pustaka untuk bekerja dengan XML-RPC (client ataupun server) telah disertakan dalam standard library sejak Python versi 2.2. Dalam tulisan ini, kita hanya akan menggunakan pustaka client yaitu xmlrpclib pada Python 2.x.

Terdapat sejumlah fungsi yang disediakan oleh OpenERP. Kita akan membahas sebagian dari fungsi- fungsi tersebut dari perspektif Python, baik dengan memanfaatkan pustaka bantu ataupun langsung menggunakan xmlrpclib.

Untuk contoh XML-RPC dan OpenERP dengan beberapa bahasa pemrograman lain, Anda dapat membacanya dari dokumentasi resmi OpenERP.

9.4 Pustaka oerpapi

Pada dasarnya, kita cukup menggunakan xmlrpclib untuk berbicara dengan server OpenERP. Namun, beberapa pustaka bantu membuatnya lebih mudah dan nyaman. Salah satu pustaka yang dapat digunakan adalah oerpapi.

Pustaka ini dikembangkan oleh Noprianto, salah satu anggota tim penulis buku ini, dan dapat didownload dari https://github.com/nopri/oerpapi . Lisensi yang dipergunakan adalah LGPL, sehingga aplikasi yang menggunakan pustaka ini tidak harus disediakan source codenya. Sebagai catatan, pustaka oerpapi pada saat tulisan ini dibuat masih relatif baru dan berada pada versi 0.03.

Semua class ataupun fungsi akan selalu tersedia dalam satu file tunggal oerpapi.py. File ini dapat dikopikan pada (salah satu): • Direktori pustaka Python yang terdaftar (system-wide) • Direktori lain, dimana Anda perlu mengatur environment variabel PYTHONPATH • Direktori program Anda (atau subdirektori di dalamnya)

Untuk menggunakan pustaka ini, kita dapat melakukan import seperti contoh berikut: import oerpapi

Beberapa class telah disediakan untuk bekerja dengan OpenERP. Kita akan membahas beberapa contoh di sini. Pembahasan lain dapat pula ditemukan pada contoh-contoh program. Sementara, untuk informasi selengkapnya tentang module ini, rujuklah pada source code oerpapi.py.

OErpClient

Kita umumnya selalu mulai dari menginstansiasi class ini. Contoh: >>> client = oerpapi.OErpClient('localhost')

>>> client <oerpapi.OErpClient instance at 0xb726ec8c>

Untuk terhubung ke server, kita menggunakan method connect(). Contoh: >>> client.connect() Setelah terhubung, kita bisa mendapatkan beberapa informasi dari server seperti contoh berikut: >>> client.version()

{'server_version_info': [7, 0, 0, 'final', 0], 'server_serie': '7.0', 'server_version': '7.0-20140724-231255', 'protocol_version': 1}

>>> print client.server_environment()

Environment Information : System : Linux-3.13.0-24-generic-i686-with-Ubuntu-14.04-trusty OS Name : posix Distributor ID:

Ubuntu

Description:

Ubuntu 14.04 LTS

Release: 14.04 Codename:

trusty Operating System Release : 3.13.0-24-generic Operating System Version : #46-Ubuntu SMP Thu Apr 10 19:08:14 UTC 2014 Operating System Architecture : 32bit Operating System Locale : en_US.UTF-8 Python Version : 2.7.6 OpenERP-Server Version : 7.0-20140724-231255

Sebelum bekerja dengan database, kita perlu melakukan login terlebih dahulu: >>> client.login('test1', 'demo', 'demo')

>>> client.uid 3

Informasi class

class OErpClient | __init__(self, host, port=8069, data=None) | | check_connectivity(self) | | connect(self, **args) | | create_url(self, resource) | | get_db(self) | | get_model(self, model) | | get_report(self, model, ids, datas=False, context=False) | | login(self, database, user, password) | | server_environment(self) | | version(self)

OErpModel

Melanjutkan dari contoh sebelumnya, ketika telah terhubung dan login, kita bisa bekerja dengan model OpenERP, sebagai contoh adalah res.partner:

>>> partner = client.get_model('res.partner') >>> partner <oerpapi.OErpModel instance at 0xb710e62c>

Terdapat beberapa method yang telah disediakan seperti:

• create: membuat. Catatan: pastikan semua field yang required telah diisikan. • write: update • read: membaca. Catatan: gunakan list kosong sebagai field untuk mendapatkan semua field. • search: mencari. Catatan: untuk kriteria lebih dari satu, pencarian dilakukan dengan Polish

Notation, dimana operator seperti '|' dan '&' ditempatkan di depan. • unlink: menghapus

Contoh: >>> partner_id = partner.create({'name': 'test'})

>>> partner_id 122

>>> partner.write(partner_id, {'name': 'test baru'}) True

>>> partner_search = partner.search([('name', 'ilike', 'test')]) >>> print partner_search [119, 121, 122]

>>> partner.read(partner_search, ['name']) [{'name': 'Test 123', 'id': 119}, {'name': 'test 1234', 'id': 121}, {'name': 'test baru', 'id': 122}]

>>> partner.unlink(partner_id) True

Informasi class class OErpModel

| __init__(self, client, model) | | check_context(self, context) | | check_fields(self, fields) | | check_ids(self, ids) | | check_none(self, val, default=False) | | create(self, values, context=None) | | read(self, ids, fields=None, context=None) | | search(self, domain, offset=0, limit=None, order=None, context=None,

count=False) | | unlink(self, ids, context=None) | | write(self, ids, values, context=None)

OErpDb

Dari instance OErpClient, kita bisa pula bekerja dengan database: >>> db = client.get_db()

>>> db <oerpapi.OErpDb instance at 0xb710e46c>

Terdapat beberapa method yang telah disediakan seperti: • list: mendapatkan daftar database yang tersedia • list_lang: mendapatkan daftar bahasa • exist: memeriksa apakah suatu database telah ditemukan • create: membuat database baru. Bahasa yang dipergunakan bisa diatur, namun tidak semua

terjemahan telah lengkap. Password yang dilewatkan pada fungsi ini akan menjadi password admin untuk database yang dibuat.

• drop: menghapus database • rename: mengganti nama database • dump: melakukan dump/backup database ke file. Perhatikanlah bahwa nilai yang dikembalikan

adalah dalam encoding base64. • restore: melakukan restore dari file ke database baru. Sebagaimana halnya pada dump, kita perlu melewatkan dalam encoding base64. • duplicate: membuat database baru berdasarkan database yang ada • change_admin_password: mengganti password admin. Apa yang kita ganti di sini akan ditulis ulang

pada file konfigurasi server (bukan hanya berlaku sementara). Contoh: >>> db.list()

['test1', 'test1_copy', 'test2', 'test3', 'test3_new', 'test_baru', 'test_baru2'] >>> db.exist('database_tidak_ditemukan')

False >>> db.exist('test1') True

Untuk tugas-tugas administratif, kita perlu menyediakan password admin, seperti yang ditentukan pada konfigurasi server OpenERP:

>>> db.admin_password = 'myadminpassword'

Contoh tugas-tugas administratif:

>>> db.create('test_create', False, 'en_US', 'mypassword') True

>>> db.rename('test_create', 'test_create_rename') True

>>> db.duplicate('test_create_rename', 'test_duplicate') True

>>> db.drop('test_create') False

>>> db.drop('test_create_rename') True

>>> db.drop('test_duplicate') True

Perhatikanlah bahwa apabila password admin tidak diberikan, maka exception akan terjadi: >>> db.admin_password = ''

>>> db.create('test_create', False, 'en_US', 'mypassword') Traceback (most recent call last):

File "<stdin>", line 1, in <module> … … …

raise Fault(**self._stack[0]) xmlrpclib.Fault: <Fault AccessDenied: 'Access denied.'>

Informasi class

class OErpDb | __init__(self, client) | | change_admin_password(self, new_password) | | create(self, name, demo, lang, password) | | drop(self, name) | | dump(self, name) | | duplicate(self, name, target_name) | | exist(self, name) | | list(self, arg=False) | | list_lang(self) | | rename(self, name, new_name) | | restore(self, name, data)

OErpReport

Melanjutkan dari contoh sebelumnya, ketika telah terhubung dan login, kita bisa bekerja dengan report OpenERP. Sebagai contoh, kita bekerja dengan model res.partner:

>>> client.login('test1', 'demo', 'demo') >>> partner = client.get_model('res.partner') >>> partner_search = partner.search([('name', 'ilike', 'test')]) >>> report = client.get_report('res.partner', partner_search) >>> report <oerpapi.OErpReport instance at 0xb705deec>

Report dalam format PDF bisa didapatkan dengan cara memanggil method get. Sebagai contoh: >>> report_output = report.get()

Apa yang dihasilkan adalah isi file report dalam encoding base64. Kita dapat menulisnya ke file: >>> import base64

>>> if report_output: ... f = open('/tmp/report.pdf', 'wb') ... f.write(base64.decodestring(report_output)) ... f.close() ...

Menggunakan program 'file', kita bisa memastikan bahwa file yang dihasilkan adalah dalam format PDF:

$ file report.pdf report.pdf: PDF document, version 1.4

Untuk pengaturan report lebih lanjut, kita bisa melewatkan datas dan context sebagai argumen ketiga dan keempat pada get_report(). Untuk informasi lebih lanjut tentang report, bacalah juga Bab 7 Laporan.

Penundaan dilakukan selama beberapa waktu tertentu sampai report berhasil dibuat. Rujuklah ke source code untuk OErpReport untuk delay_1, delay_2 dan number_of_tries. Kita akan membahas ini juga pada contoh program laporan (11.8).

Informasi class

class OErpReport | __init__(self, client, model, ids, datas=False, context=False) | | check_datas(self) | | get(self)

Exception

Modul ini tidak melakukan try/except untuk exception yang mungkin terjadi. Sebagai contoh, ketika kita tidak melakukan koneksi terlebih dahulu dan ingin login:

>>> client = oerpapi.OErpClient('localhost')>>> client.login('test1', 'demo', 'demo') Traceback (most recent call last):

File "<stdin>", line 1, in <module> … … …

self.uid = self.sock_common.login(self.database, self.user, AttributeError: 'bool' object has no attribute 'login'

Atau, ketika kita sudah terhubung, namun belum melakukan login dan ingin melakukan pencarian: >>> client = oerpapi.OErpClient('localhost')

>>> client.connect() >>> >>> partner = client.get_model('res.partner') >>> partner_search = partner.search([('name', 'ilike', 'test')]) Traceback (most recent call last):

File "<stdin>", line 1, in <module> … … …

raise Fault(**self._stack[0]) xmlrpclib.Fault: <Fault FATAL: database "False" does not exist … …

Oleh karena itu, sangat disarankan dalam program untuk memeriksa adanya exception. Contoh sederhana ketika login dengan password yang salah:

>>> import xmlrpclib >>> client = oerpapi.OErpClient('localhost') >>> client.connect() >>> >>> client.login('test1', 'demo', '') >>> partner = client.get_model('res.partner') >>> >>> try: ... partner_search = partner.search([('name', 'ilike', 'test')]) ... except xmlrpclib.Fault, e: ... partner_search = [] ... print 'Terjadi kesalahan: %s' %(e) ... Terjadi kesalahan: <Fault AccessDenied: 'Access denied.'> >>>

Memeriksa hasil login

Perhatikanlah bahwa method login() tidak mengembalikan nilai sukses atau gagal. Mari kita contohkan login dengan password yang salah:

>>> client = oerpapi.OErpClient('localhost') >>> client.connect() >>> >>> result = client.login('test1', 'demo', '') >>> result >>> type(result) <type 'NoneType'> >>>

Untuk memeriksa apakah login gagal atau sukses, akseslah property uid. Sebagai contoh, pada login yang gagal:

>>> client.uid False

Dan, contoh untuk login yang berhasil (uid akan berisikan nilai User ID OpenERP): >>> client.login('test1', 'demo', 'demo')

>>> client.uid 3

Pemeriksaan berikut bisa pula digunakan: >>> client.login('test1', 'demo', '') >>> if client.uid:

... print 'Login berhasil' ... else: ... print 'Login gagal' ... Login gagal

>>> client.login('test1', 'demo', 'demo') >>> if client.uid: ... print 'Login berhasil' ... else: ... print 'Login gagal' ... Login berhasil

9.5 Program: pilih dan login ke database

Pada program berikut, kita akan mendapatkan daftar database, kemudian memilih dan login ke database. Program mempergunakan pustaka oerpapi.

Source code (11_5.py) # 11_5.py # (c) Noprianto <nop@tedut.com> GPL # # Mendapatkan daftar database # Memilih database # Login ke database

import oerpapi host = raw_input( 'Server: ' )

print 'Mencoba melakukan koneksi ke %s pada port default...' %(host) client = oerpapi.OErpClient(host) client.connect()

version = client.version() print 'Versi: %s' %(version.get( 'server_version' ))

db = client.get_db() db_list = db.list() print 'Database yang tersedia: %s' %(db_list)

db_name = raw_input( 'Database yang ingin digunakan: ' ) if not db.exist(db_name): print 'Database %s tidak ditemukan' %(db_name) else : user = raw_input( '[%s] Masukkan nama user: ' %(db_name)) password = raw_input( '[%s] Masukkan password: ' %(db_name))

print 'Mencoba login...' client.login(db_name, user, password) print 'UserID adalah: %s' %(client.uid)

Jalankanlah program dengan cara berikut: $ python 11_5.py

Server: localhost Mencoba melakukan koneksi ke localhost pada port default... Versi: 7.0-20140724-231255 Database yang tersedia: ['test1', 'test1_copy', 'test2', 'test3', 'test3_new', 'test_baru', 'test_baru2'] Database yang ingin digunakan: test1

[test1] Masukkan nama user: demo [test1] Masukkan password: demo Mencoba login... UserID adalah: 3

Contoh memilih database yang tidak ditemukan: $ python 11_5.py Server: localhost Mencoba melakukan koneksi ke localhost pada port default... Versi: 7.0-20140724-231255 Database yang tersedia: ['test1', 'test1_copy', 'test2', 'test3', 'test3_new', 'test_baru', 'test_baru2'] Database yang ingin digunakan: test Database test tidak ditemukan

Contoh login gagal: $ python 11_5.py Server: localhost Mencoba melakukan koneksi ke localhost pada port default... Versi: 7.0-20140724-231255 Database yang tersedia: ['test1', 'test1_copy', 'test2', 'test3', 'test3_new', 'test_baru', 'test_baru2'] Database yang ingin digunakan: test1 [test1] Masukkan nama user: [test1] Masukkan password: Mencoba login... UserID adalah: False

9.6 Program: buat, update, baca, hapus

Pada program berikut, kita akan bekerja dengan model res.partner untuk: • Membuat partner baru • Mengupdate data partner • Membaca data partner • Menghapus partner

Program mempergunakan pustaka oerpapi. Pembahasan akan dilakukan setelah source code dan contoh output.

Source code (11_6.py) # 11_6.py # (c) Noprianto <nop@tedut.com> GPL # # Membuat partner baru # Mengupdate data partner # Menampilkan data partner # Menghapus partner

import oerpapi host = 'localhost'

db_name = 'test1' user = 'demo' password = 'demo'

fields = [ 'name' , 'website' ] client = oerpapi.OErpClient(host)

client.connect() version = client.version()

print 'Terhubung pada %s, versi %s' %(host, version.get( 'server_version' )) client.login(db_name, user, password)

print 'Login dengan UserID: %s' %(client.uid) print 'Membuat partner (res.partner) baru'

partner_data = {} for f in fields: temp = raw_input( '%s: ' %(f)) partner_data[f] = temp

partner = client.get_model( 'res.partner' ) partner_id = partner.create(partner_data)

print 'Partner ID adalah %s' %(partner_id) print 'Mengupdate data partner ID %s' %(partner_id)

partner_data = {} for f in fields: partner_data = {} for f in fields:

partner.write(partner_id, partner_data) print 'Menampilkan data partner ID %s' %(partner_id)

partner_read = partner.read(partner_id, fields) print partner_read

if raw_input( 'Input Y untuk menghapus partner ID %s: ' %(partner_id)) == 'Y' : partner.unlink(partner_id)

Jalankanlah program dengan cara berikut: $ python 11_6.py

Terhubung pada localhost, versi 7.0-20140724-231255 Login dengan UserID: 3 Membuat partner (res.partner) baru name: Test Partner Baru website: - Partner ID adalah 123 Mengupdate data partner ID 123 name: Test Partner Baru Update website: http://domain.tld Menampilkan data partner ID 123 [{'website': 'http://domain.tld', 'name': 'Test Partner Baru Update', 'id': 123}] Input Y untuk menghapus partner ID 123: Y

Penjelasan • Pada dasarnya, kita bisa bekerja dengan model lain. Model res.partner dalam hal ini hanyalah

contoh saja. • Dalam contoh ini, kita bekerja dengan database test1 dan login sebagai user demo (password: demo). • Untuk pembuatan, update dan baca data, contoh ini hanya menggunakan field name dan website. Sesuaikanlah field ini apabila bekerja dengan model lain.

Contoh dengan model lain Kita akan membuat sebuah product baru. Dalam hal ini, model yang akan kita gunakan adalah product.product.

Untuk membuat product baru, kita akan login sebagai admin. Aktifkanlah developer mode untuk mendapatkan nama field (arahkan pointer mouse pada label field).

>>> import oerpapi >>> client = oerpapi.OErpClient('localhost') >>> client.connect()

>>> >>> client.login('test1', 'admin', 'test1') >>> client.uid 1 >>> >>> product = client.get_model('product.product') >>> product_data = { ... 'name': 'Test Produk', ... 'categ_id': 1, ... 'type': 'service' ... } >>> product_id = product.create(product_data) >>> product_id 51 >>> >>> product.read(product_id, []) [{'warranty': 0.0, 'ean13': False, 'uos_id': False, 'list_price': 1.0, 'weight':

0.0, 'message_follower_ids': [3], 'color': 0, 'incoming_qty': 0.0, 'image': False, 'standard_price': 0.0, 'variants': False, 'price_extra': 0.0, 'mes_type': 'fixed', 'uom_id': [1, 'Unit(s)'], 'code': False, 'description_purchase': False, 'default_code': False, 'name_template': 'Test Produk', 'property_account_income': False, 'qty_available': 0.0, 'id': 51, 'message_summary': ' ', 'uos_coeff': 1.0, 'virtual_available': 0.0, 'sale_ok': True, 'message_is_follower': True, 'categ_id': [1, 'All products'], 'product_manager': False, 'company_id': [1, 'Your Company'], 'message_ids': [254], 'product_tmpl_id': [51, 'Test Produk'], 'state': False, 'uom_po_id': [1, 'Unit(s)'], 'pricelist_id': [], 'type': 'service', 'weight_net':

0.0, 'description': False, 'price': 0.0, 'seller_qty': 0.0, 'supplier_taxes_id': [], 'volume': 0.0, 'outgoing_qty': 0.0, 'seller_info_id': False, 'description_sale': False, 'active': True, 'cost_method': 'standard', 'partner_ref': 'Test Produk', 'rental': False, 'seller_delay': 1, 'packaging': [], 'seller_id': False, 'image_medium': False, 'name': 'Test Produk', 'price_margin':

1.0, 'property_account_expense': False, 'image_small': False, 'lst_price': 1.0, 'taxes_id': [], 'produce_delay': 1.0, 'seller_ids': [], 'message_unread': False}] >>>

9.7 Program: melakukan pencarian

Pada program berikut, kita akan mencari ke res.partner sesuai dengan kriteria pencarian. Program mempergunakan pustaka oerpapi. Pembahasan akan dilakukan setelah source code dan contoh output.

Source code (11_7.py) # 11_7.py # (c) Noprianto <nop@tedut.com> GPL # # Mencari partner

import oerpapi host = 'localhost'

db_name = 'test1' user = 'demo' password = 'demo'

client = oerpapi.OErpClient(host) client.connect() version = client.version()

print 'Terhubung pada %s, versi %s' %(host, version.get( 'server_version' )) client.login(db_name, user, password)

print 'Login dengan UserID: %s' %(client.uid) search_name = raw_input( 'Mencari nama partner yang mengandung teks berikut: ' )

search_data = [( 'name' , 'ilike' , search_name)] print search_data

partner = client.get_model( 'res.partner' ) partner_search = partner.search(search_data)

print 'Ditemukan %s partner' %(len(partner_search)) if partner_search:

fields = [ 'name' ] partner_read = partner.read(partner_search, fields)

for i in partner_read: print i.get( 'name' )

Jalankanlah program dengan cara berikut: $ python 11_7.py Terhubung pada localhost, versi 7.0-20140724-231255 Login dengan UserID: 3 Mencari nama partner yang mengandung teks berikut: tes [('name', 'ilike', 'tes')] Ditemukan 4 partner Test 123 Jalankanlah program dengan cara berikut: $ python 11_7.py Terhubung pada localhost, versi 7.0-20140724-231255 Login dengan UserID: 3 Mencari nama partner yang mengandung teks berikut: tes [('name', 'ilike', 'tes')] Ditemukan 4 partner Test 123

Contoh pencarian dengan hasil tidak ditemukan: $ python 11_7.py Terhubung pada localhost, versi 7.0-20140724-231255 Login dengan UserID: 3 Mencari nama partner yang mengandung teks berikut: tidak_ditemukan [('name', 'ilike', 'tidak_ditemukan')] Ditemukan 0 partner

Penjelasan • Pada dasarnya, kita bisa bekerja dengan model lain. Model res.partner dalam hal ini hanyalah

contoh saja. • Kriteria pencarian mempergunakan Polish Notation. Gunakanlah '|' untuk or dan '&' untuk and.

Contoh dengan model lain Kita akan mencari dari product.product dengan kriteria type=service.

>>> import oerpapi >>> client = oerpapi.OErpClient('localhost') >>> client.connect() >>> >>> client.login('test1', 'demo', 'demo') >>> client.uid 3 >>> >>> product = client.get_model('product.product') >>> search_data = [('type', '=', 'service')] >>> product_search = product.search(search_data) >>> product_search [50, 3, 2, 1, 51] >>> >>> product_read = product.read(product_search, ['name']) >>> product_read [{'id': 50, 'name': 'Advance'}, {'id': 3, 'name': 'On Site Assistance'}, {'id': 2, 'name': 'On Site Monitoring'}, {'id': 1, 'name': 'Service'}, {'id': 51, 'name': 'Test Produk'}] >>>

Contoh beberapa kriteria pencarian 1 Kita akan mencari dari res.partner, untuk nama yang mengandung 'tes' (tidak case-sensitive) atau untuk id < 3.

Perhatikanlah bahwa karena menggunakan Polish Notation, maka operator or '|' ditempatkan di depan.

>>> import oerpapi >>> client = oerpapi.OErpClient('localhost') >>> client.connect() >>> >>> client.login('test1', 'demo', 'demo') >>> client.uid 3 >>> >>> partner = client.get_model('res.partner') >>> search_data = ['|', ('name', 'ilike', 'tes'), ('id', '<', 3)] >>> partner_search = partner.search(search_data) >>> partner_search [119, 121, 124, 125, 1] >>> >>> partner_read = partner.read(partner_search, ['name']) >>> partner_read [{'name': 'Test 123', 'id': 119}, {'name': 'test 1234', 'id': 121}, {'name': 'Test SO', 'id': 124}, {'name': 'Test SO', 'id': 125}, {'name': 'Your Company', 'id': 1}] >>>

Contoh beberapa kriteria pencarian 2 Kita akan mencari dari res.partner, untuk: • nama yang mengandung 'tes' (tidak case-sensitive) atau untuk id < 3 • dan • website = ''

Perhatikanlah bahwa karena menggunakan Polish Notation, maka operator or '|' dan and '&' ditempatkan di depan.

Pertama-tama, kita menyusun untuk kriteria pertama (or): '|', ('name', 'ilike', 'tes'), ('id', '<', 3) Setelah itu, kita gabungkan dengan kriteria kedua (and): '&', '|', ('name', 'ilike', 'tes'), ('id', '<', 3), ('website', '=', '')

>>> import oerpapi >>> client = oerpapi.OErpClient('localhost') >>> client.connect() >>> >>> client.login('test1', 'demo', 'demo') >>> client.uid 3 >>> >>> partner = client.get_model('res.partner') >>> search_data = ['&', '|', ('name', 'ilike', 'tes'), ('id', '<', 3), ('website', '=', '')] >>> partner_search = partner.search(search_data)

>>> partner_search [119] >>> partner_read = partner.read(partner_search, ['name', 'website']) >>> partner_read [{'website': '', 'name': 'Test 123', 'id': 119}] >>> >>> search_data = ['|', ('name', 'ilike', 'tes'), ('id', '<', 3)]>>> partner_search = partner.search(search_data) >>> partner_search [119, 121, 124, 125, 1] >>> >>> partner_read = partner.read(partner_search, ['name', 'website']) >>> partner_read [{'website': '', 'name': 'Test 123', 'id': 119}, {'website': 'b', 'name': 'test 1234', 'id': 121}, {'website': False, 'name': 'Test SO', 'id': 124}, {'website': False, 'name': 'Test SO', 'id': 125}, {'website': 'www.yourcompany.com', 'name': 'Your Company', 'id': 1}]

Dari hasil pencarian, bisa kita lihat bahwa pencarian dengan kriteria pertama saja menghasilkan 5 partner: [119, 121, 124, 125, 1] . Dari hasil pencarian tersebut, hanya satu partner saja (id: 119) yang memenuhi kriteria kedua, yaitu website=''.

9.8 Program: laporan

Pada program berikut, kita akan membuat satu laporan sederhana, dalam format PDF, untuk model res.partner, sesuai hasil pencarian. Program mempergunakan pustaka oerpapi.

Source code (11_8.py) # 11_8.py # (c) Noprianto <nop@tedut.com> GPL # # Membuat laporan sederhana (PDF)

import base64 import oerpapi

host = 'localhost' db_name = 'test1' user = 'demo' password = 'demo'

client = oerpapi.OErpClient(host) client.connect() version = client.version()

print 'Terhubung pada %s, versi %s' %(host, version.get( 'server_version' )) client.login(db_name, user, password)

print 'Login dengan UserID: %s' %(client.uid) search_name = raw_input( 'Mencari nama partner yang mengandung teks berikut: ' )

search_data = [( 'name' , 'ilike' , search_name)] print search_data

partner = client.get_model( 'res.partner' ) partner_search = partner.search(search_data)

print 'Ditemukan %s partner' %(len(partner_search)) if partner_search:

report = client.get_report( 'res.partner' , partner_search) report_result = report.get()

if report_result: fout = '/tmp/report.pdf' f = open(fout, 'wb' ) f.write(base64.decodestring(report_result)) f.close()

print 'Laporan disimpan pada %s' %(fout) else : print 'Laporan gagal dihasilkan' else : print 'Laporan tidak dibuat'

Jalankanlah program dengan cara berikut:

$ python 11_8.py Terhubung pada localhost, versi 7.0-20140724-231255 Login dengan UserID: 3 Mencari nama partner yang mengandung teks berikut: tes [('name', 'ilike', 'tes')] Ditemukan 4 partner Laporan disimpan pada /tmp/report.pdf

File yang dihasilkan adalah file PDF yang valid: $ file /tmp/report.pdf

/tmp/report.pdf: PDF document, version 1.4 Contoh pencarian dengan hasil tidak ditemukan:

$ python 11_8.py Terhubung pada localhost, versi 7.0-20140724-231255 Login dengan UserID: 3 Mencari nama partner yang mengandung teks berikut: tidak_ditemukan [('name', 'ilike', 'tidak_ditemukan')] Ditemukan 0 partner Laporan tidak dibuat

delay_1, delay_2 dan number_of_tries Berikut adalah simulasi pembuatan report dengan semua delay_1, delay_2 dan number_of_tries di set ke 0. Pada bagian pertama dalam contoh, report gagal dibuat.

Pada bagian kedua, kita mengatur ulang ketiga variabel tersebut untuk nilai wajar (untuk localhost dan laporan sangat sederhana), dan report berhasil dibuat.

>>> import oerpapi >>> client = oerpapi.OerpClient('localhost') >>> client.connect() >>> >>> client.login('test1', 'demo', 'demo') >>> client.uid 3 >>> >>> partner = client.get_model('res.partner') >>> search_data = [('name', 'ilike', 'tes')] >>> partner_search = partner.search(search_data) >>> partner_search [119, 121, 124, 125] >>> >>> report = client.get_report('res.partner', partner_search) >>> report.delay_1 = 0 >>> report.delay_2 = 0 >>> report.number_of_tries = 0 >>> report_result = report.get() >>> report_result '' >>> >>> report.delay_1 = 1 >>> report.delay_2 = 0.5

>>> report.number_of_tries = 50 >>> report_result = report.get() >>> len(report_result) 25451

9.9 Program: buat, ganti nama, kopi, hapus database

Pada program berikut, kita akan membuat satu database, dengan opsi untuk menambahkan demo. Database yang baru dibuat tersebut kemudian bisa di-ganti nama, dikopi dan dihapus. Program mempergunakan pustaka oerpapi.

Source code (11_9.py) # 11_9.py # (c) Noprianto <nop@tedut.com> GPL # # Membuat database # Mengganti nama database # Mengopi database # Menghapus database

import oerpapi host = raw_input( 'Server: ' )

print 'Mencoba melakukan koneksi ke %s pada port default...' %(host) client = oerpapi.OErpClient(host) client.connect()

version = client.version() print 'Versi: %s' %(version.get( 'server_version' ))

db = client.get_db() admin_password = raw_input( 'Masukkan password admin: ' ) db_name = raw_input( 'Masukkan nama database yang ingin dibuat: ' ) password = raw_input( 'Masukkan password yang ingin digunakan: ' ) demo = False if raw_input( 'Input Y apabila ingin menggunakan contoh data: ' ) == 'Y' :

demo = True db.admin_password = admin_password

print 'Mohon tunggu...' db.create(db_name, demo, 'id_ID' , password) print db.list()

new_name = raw_input( 'Masukkan nama database yang baru (ENTER=lewatkan): ' ) new_name = new_name.strip() if new_name:

db.rename(db_name, new_name) db_name = new_name

print db.list() copy_name = raw_input( 'Mengopi database ke (ENTER=lewatkan): ' )

copy_name = copy_name.strip() if copy_name:

db.duplicate(db_name, copy_name) print db.list() db.duplicate(db_name, copy_name) print db.list()

Jalankanlah program dengan cara berikut: $ python 11_9.py Server: localhost Mencoba melakukan koneksi ke localhost pada port default... Versi: 7.0-20140724-231255 Masukkan password admin: myadminpassword Masukkan nama database yang ingin dibuat: test9 Masukkan password yang ingin digunakan: password_test9 Input Y apabila ingin menggunakan contoh data: Mohon tunggu... ['test1', 'test1_copy', 'test2', 'test3', 'test30', 'test3_new', 'test9', 'test_baru', 'test_baru2'] Masukkan nama database yang baru (ENTER=lewatkan): test9_rename ['test1', 'test1_copy', 'test2', 'test3', 'test30', 'test3_new', 'test9_rename', 'test_baru', 'test_baru2'] Mengopi database ke (ENTER=lewatkan): test9_copy ['test1', 'test1_copy', 'test2', 'test3', 'test30', 'test3_new', 'test9_copy', 'test9_rename', 'test_baru', 'test_baru2'] Input Y untuk menghapus database test9_rename: Y ['test1', 'test1_copy', 'test2', 'test3', 'test30', 'test3_new', 'test9_copy', 'test_baru', 'test_baru2']

Dalam contoh tersebut: • Kita tidak menambahkan demo ke dalam database pada saat membuat database test9 • Database tersebut kita ganti namanya menjadi test9_rename • Database tersebut kita kopikan ke test9_copy • Pada akhirnya, database test9_rename kita hapus

Perhatikanlah bahwa kita tidak bisa mengopikan ke database yang telah ada sebelumnya: $ python 11_9.py

Server: localhost Mencoba melakukan koneksi ke localhost pada port default... Versi: 7.0-20140724-231255 Masukkan password admin: myadminpassword Masukkan nama database yang ingin dibuat: test10 Masukkan password yang ingin digunakan: password_test10 Input Y apabila ingin menggunakan contoh data: Mohon tunggu... ['test1', 'test10', 'test1_copy', 'test2', 'test3', 'test30', 'test3_new', 'test9_copy', 'test_baru', 'test_baru2'] Masukkan nama database yang baru (ENTER=lewatkan): ['test1', 'test10', 'test1_copy', 'test2', 'test3', 'test30', 'test3_new', 'test9_copy', 'test_baru', 'test_baru2']

Mengopi database ke (ENTER=lewatkan): test9_copy Traceback (most recent call last):

File "11_9.py", line 43, in <module> db.duplicate(db_name, copy_name) … … …

raise Fault(**self._stack[0]) xmlrpclib.Fault: <Fault database "test9_copy" already exists … … …

Bahasa yang dipergunakan Bahasa yang dipergunakan bisa didapatkan dengan memanggil fungsi list_lang. Perhatikanlah bahwa tidak semua terjemahan adalah lengkap.

>>> import oerpapi >>> client = oerpapi.OErpClient('localhost') >>> client.connect() >>> >>> db = client.get_db() >>> langs = db.list_lang() >>> print len(langs) 81 >>> >>> langs_id = [x[0] for x in langs] >>> langs_id ['ab_RU', 'sq_AL', 'am_ET', 'ar_SY', 'bs_BS', 'bg_BG', 'ca_ES', 'zh_CN', 'zh_HK', 'zh_TW', 'hr_HR', 'cs_CZ', 'da_DK', 'nl_NL', 'en_CA', 'en_GB', 'en_US', 'et_EE', 'fi_FI', 'nl_BE', 'fr_BE', 'fr_CH', 'fr_FR', 'gl_ES', 'de_DE', 'el_GR', 'gu_IN', 'he_IL', 'hi_IN', 'hu_HU', 'id_ID', 'iu_CA', 'it_IT', 'ja_JP', 'tlh_TLH', 'ko_KP', 'ko_KR', 'lo_LA', 'lv_LV', 'lt_LT', 'ml_IN', 'mn_MN', 'nb_NO', 'oc_FR', 'fa_IR', 'pl_PL', 'pt_BR', 'pt_PT', 'ro_RO', 'ru_RU', 'sr_RS', 'sr@latin', 'si_LK', 'sk_SK', 'sl_SI', 'es_AR', 'es_BO', 'es_CL', 'es_CO', 'es_CR', 'es_DO', 'es_EC', 'es_GT', 'es_HN', 'es_MX', 'es_NI', 'es_PA', 'es_PE', 'es_PR', 'es_PY', 'es_SV', 'es_UY', 'es_VE', 'es_ES', 'sv_SE', 'te_IN', 'th_TH', 'tr_TR', 'uk_UA', 'ur_PK', 'vi_VN'] >>>

9.10 Program: dump dan restore database

Pada program berikut, kita akan melakukan dump/backup sebuah database dan kemudian melakukan restore dari file backup sebelumnya ke database baru. Program mempergunakan pustaka oerpapi.

Source code (11_10.py) # 11_10.py # (c) Noprianto <nop@tedut.com> GPL # # Dump/backup database # Restore database

import base64 import oerpapi

host = raw_input( 'Server: ' ) print 'Mencoba melakukan koneksi ke %s pada port default...' %(host)

client = oerpapi.OErpClient(host) client.connect()

version = client.version() print 'Versi: %s' %(version.get( 'server_version' ))

db = client.get_db() db_list = db.list() print 'Database yang tersedia: %s' %(db_list)

db_name = raw_input( 'Database yang ingin dibackup: ' ) admin_password = raw_input( 'Masukkan password admin: ' )

db.admin_password = admin_password fout = '/tmp/backup.sql'

print 'Mohon tunggu...' backup = db.dump(db_name) if backup:

f = open( '/tmp/backup.sql' , 'wb' ) f.write(base64.decodestring(backup)) f.close()

print 'Backup disimpan pada %s' %(fout) else : print 'Backup gagal didapatkan'

db_name = raw_input( 'Ingin restore %s ke database: ' %(fout)) db.restore(db_name, backup)

Jalankanlah program dengan cara berikut:

$ python 11_10.py Server: localhost Mencoba melakukan koneksi ke localhost pada port default... Versi: 7.0-20140724-231255 Database yang tersedia: ['test1', 'test10', 'test1_copy', 'test2', 'test3', 'test30', 'test3_new', 'test9_copy', 'test_baru', 'test_baru2'] Database yang ingin dibackup: test10 Masukkan password admin: myadminpassword Mohon tunggu... Backup disimpan pada /tmp/backup.sql Ingin restore /tmp/backup.sql ke database: test10_restore

Format file dump $ file /tmp/backup.sql

/tmp/backup.sql: PostgreSQL custom database dump – v1.12-0

9.11 Menggunakan xmlrpclib

Sebagaimana dibahas sebelumnya, pada dasarnya, kita cukup menggunakan xmlrpclib untuk berbicara dengan server OpenERP. Contoh-contoh sebelumnya yang menggunakan pustaka oerpapi hanyalah bertujuan agar lebih mudah dan nyaman.

Tips: Untuk informasi selengkapnya tentang web service/API, bacalah juga dokumentasi API OpenERP. Apabila diperlukan, Anda juga bisa membaca source code pustaka oerpapi ataupun Bab 5 tentang Model pada OpenERP.

Pertama-tama, kita perlu import module xmlrpclib: >>> import xmlrpclib /xmlrpc/common

Setelah kita mengetahui host dan port, pertama-tama, umumnya kita ingin melakukan koneksi ke service /xmlrpc/common:

>>> host = 'localhost' >>> port = 8069 >>> protocol = 'http://' >>> url = '%s%s:%s/xmlrpc/common' %(protocol, host, port) >>> url 'http://localhost:8069/xmlrpc/common' >>> sock_common = xmlrpclib.ServerProxy(url) >>> sock_common <ServerProxy for localhost:8069/xmlrpc/common> >>>

Service ini menyediakan berbagai utiliti seperti login. Ketika login sukses dilakukan, kita mendapatkan uid.

>>> db_name = 'test1' >>> user = 'demo' >>> password = 'demo' >>> uid = sock_common.login(db_name, user, password) >>> uid 3 >>>

/xmlrpc/object Kita umumnya menggunakan service /xmlrpc/object dan fungsi execute:

>>> url_object = '%s%s:%s/xmlrpc/object' %(protocol, host, port) >>> url_object 'http://localhost:8069/xmlrpc/object' >>> sock_object = xmlrpclib.ServerProxy(url_object)

>>> sock_object <ServerProxy for localhost:8069/xmlrpc/object> >>>

Dengan informasi database, uid dan password, kita bisa bekerja dengan object-object OpenERP. Sebagai contoh, kita akan membuat sebuah partner baru:

>>> partner_data = {'name': 'test xmlrpclib'} >>> partner_id = sock_object.execute(db_name, uid, password, 'res.partner', 'create', partner_data) >>> partner_id 126 >>>

Fungsi execute juga bisa dipergunakan untuk mengupdate, membaca, mencari dan menghapus seperti contoh-contoh berikut:

>>> partner_update = {'name': 'test xmlrpclib updated'} >>> sock_object.execute(db_name, uid, password, 'res.partner', 'write', [partner_id], partner_update) True >>>

>>> fields = ['name'] >>> partner_read = sock_object.execute(db_name, uid, password, 'res.partner', 'read', [partner_id], fields) >>> partner_read [{'name': 'test xmlrpclib updated', 'id': 126}] >>>

>>> search_data = [('name', 'ilike', 'tes')] >>> partner_search = sock_object.execute(db_name, uid, password, 'res.partner', 'search', search_data) >>> partner_search [119, 121, 124, 125, 126] >>>

>>> sock_object.execute(db_name, uid, password, 'res.partner', 'unlink', [partner_id]) True >>>

/xmlrpc/db Menggunakan service /xmlrpc/db, kita bisa bekerja dengan database:

>>> url_db = '%s%s:%s/xmlrpc/db' %(protocol, host, port) >>> url_db 'http://localhost:8069/xmlrpc/db' >>> sock_db = xmlrpclib.ServerProxy(url_db) >>> sock_db <ServerProxy for localhost:8069/xmlrpc/db>

>>> Sebagai contoh, kita memanggil fungsi list untuk mendapatkan daftar database: >>> sock_db.list()

['test1', 'test10', 'test10_restore', 'test1_copy', 'test2', 'test3', 'test30', 'test3_new', 'test9_copy', 'test_baru', 'test_baru2'] >>>

Fungsi create_database dapat digunakan untuk membuat database baru. Perhatikanlah bahwa kita perlu melewatkan password admin sebagai argumen pertama ketika memanggil fungsi yang membutuhkan hak admin.

>>> sock_db.create_database('test40', False, 'id_ID', 'password_test40') Traceback (most recent call last):

File "<stdin>", line 1, in <module> … … …

raise Fault(**self._stack[0]) xmlrpclib.Fault: <Fault AccessDenied: 'Access denied.'> >>>

Pemanggilan fungsi create_database tersebut gagal karena password admin tidak dilewatkan. Kita melakukan koreksi dengan cara berikut:

>>> sock_db.create_database('myadminpassword', 'test40', False, 'id_ID', 'password_test40') True >>> >>> sock_db.list() ['test1', 'test10', 'test10_restore', 'test1_copy', 'test2', 'test20', 'test3', 'test30', 'test3_new', 'test40', 'test9_copy', 'test_baru', 'test_baru2'] >>>

Fungsi drop dapat digunakan untuk menghapus database. Sebagai contoh: >>> sock_db.drop('admin20142', 'test40') True >>>

/xmlrpc/report Menggunakan service /xmlrpc/report, kita bisa bekerja dengan report. Untuk informasi selengkapnya, bacalah dokumentasi API OpenERP.