"Beberapa kelebihan buku ini: ditulis oleh para programer dan praktisi yang bukan saja pernah
mengimplementasi tapi juga memodifikasi OpenERP, ditujukan tidak hanya untuk Windows tapi juga
Linux, dan diterbitkan secara independen dan dengan lisensi terbuka. Disarankan dibaca."
Steven Haryanto
"OpenERP merupakan produk open source yang mudah dikembangkan dan konsisten. Meski begitu
dukungannya cenderung komersil. Ini membuat developer pas-pasan seperti saya kesulitan
mempelajarinya. Kita beruntung Noprianto dkk bersedia membuat buku yang cukup rinci ini
dihadirkan tanpa dipungut biaya."
Owo Sugiana
MEREK DAGANG
KATA PENGANTAR
Pertama-tama, saya mengucapkan terima kasih kepada Whisnu Budhysantika dan Widoyo yang telah
bersedia sama-sama menulis buku ini. Juga terima kasih kepada Owo Sugiana, Steven Haryanto, dan
Zaki Akhmad yang telah bersedia memberikan pujian untuk buku ini.
Menulis buku, sebagai proyek komunitas, tanpa ada kejelasan akan diterbitkan, pastinya bukan
pekerjaan yang menarik :) Perlu komitmen, terutama ketika ditengah proses penulisan, semua penerbit
yang kami hubungi tidak tertarik. Kami memilih untuk terus menulis dan menyediakan bukunya secara
bebas!
Buku ini dipersembahkan untuk komunitas Python Indonesia (http://www.python.or.id)
Noprianto
1/232
Daftar Isi
1. Memulai OpenERP................................................................................................................................6
1.1 Instalasi............................................................................................................................................7
Instalasi di Microsoft Windows........................................................................................................7
Instalasi di distribusi Linux Ubuntu.................................................................................................8
1.2 Bekerja dengan database...............................................................................................................11
Membuat database..........................................................................................................................11
Operasi lain.....................................................................................................................................11
1.3 Settings dan technical features......................................................................................................12
1.4 Modul Sales Management.............................................................................................................15
2. Dasar-Dasar Kustomisasi.....................................................................................................................19
2.1 Developer Mode............................................................................................................................19
2.2 Menambah dan menampilkan field...............................................................................................22
Manage Views................................................................................................................................22
Field baru........................................................................................................................................24
2.3 Menyembunyikan dan mengatur posisi field................................................................................26
2.4 Kelebihan dan kekurangan............................................................................................................27
Kelebihan........................................................................................................................................27
Kekurangan.....................................................................................................................................27
3. Dasar Pengembangan Modul OpenERP..............................................................................................28
3.1 Paket Python..................................................................................................................................28
3.2 Manifest __openerp__.py..............................................................................................................28
3.3 File-file dalam modul....................................................................................................................28
3.4 Lingkungan OpenERP...................................................................................................................29
3.5 Lokasi Modul................................................................................................................................30
3.6 Update daftar modul......................................................................................................................31
3.7 Mencari dari daftar modul.............................................................................................................31
3.8 Langkah berikut.............................................................................................................................31
4. Kasus: Perusahaan Rental Kendaraan..................................................................................................33
4.1 Pendahuluan..................................................................................................................................33
Periode............................................................................................................................................33
Tipe Penggunaan.............................................................................................................................33
4.2 Langkah implementasi..................................................................................................................34
Setup Identitas Perusahaan.............................................................................................................34
Memasang Modul...........................................................................................................................35
Terjemahan Bahasa Indonesia........................................................................................................35
Kode Rekening...............................................................................................................................35
Data Awal........................................................................................................................................37
Operasi............................................................................................................................................41
Laporan...........................................................................................................................................45
5. Model pada OpenERP..........................................................................................................................49
5.1 Hirarki class...................................................................................................................................49
5.2 orm.Model, osv.Model dan osv.osv...............................................................................................51
2/232
3/232
4/232
5/232
1. Memulai OpenERP
Penulis: Whisnu Budhysantika
OpenERP (dulu bernama TinyERP, sekarang bernama Odoo) adalah sebuah perangkat lunak Enterprise
Resource Planning (ERP) atau perangkat lunak perencanaan sumber daya perusahaan yang dilisensikan
free/open source. OpenERP dikembangkan dengan bahasa pemrograman Python. Source code dan
informasi selengkapnya tentang OpenERP bisa didapatkan di website http://www.openerp.com.
Perangkat lunak perencanaan sumber daya perusahaan akan memberikan manfaat yang besar kepada
sebuah perusahaan dalam membantu mengelola sumber daya di sebuah perusahaan sehingga semua
sumber daya yang dimiliki dapat tercatat, terkontrol dan dapat dengan mudah diberdayakan.
Sebagaimana lazimnya sistem aplikasi modern, arsitektur sistem pada OpenERP menerapkan sistem
modular. Setiap adopsi terhadap kebutuhan baru dapat menghasilkan modul baru. Modul-modul
tersebut bisa diinstall bila dibutuhkan. Saat ini tersedia ribuan modul, termasuk yang datang bersama
OpenERP seperti:
CRM
Social Network
eInvoicing & Payments
Point of Sale
Project Management
Issue Tracker
Accounting and Finance
Sales Management
Warehouse Management
MRP
Purchase Management
Employee Directory
Timesheets
Leave Management
Expense Management
Assets Management
Payroll
Kesemua modul yang terinstall dirancang untuk dapat saling terhubung.
6/232
OpenERP mengembangkan jaringan partnership dengan berbagai perusahaan di seluruh dunia untuk
bersama-sama menjadi pelopor dalam pengembangan OpenERP serta menjadi ujung tombak customer
support kepada pengguna OpenERP.
1.1 Instalasi
Server OpenERP dapat dijalankan pada berbagai sistem operasi populer, dan relatif tidak sulit untuk
diinstal. Bahkan, pada sistem operasi Microsoft Windows, tersedia installer yang siap digunakan.
Sementara, untuk client, hanya dibutuhkan web browser.
Berbagai komponen OpenERP, termasuk database, bisa diinstal pada satu server yang sama, ataupun
dipisahkan ke beberapa server.
Installer ataupun source code OpenERP bisa didownload dari websitenya.
Klik ganti pada file installer untuk menginstall OpenERP dan Accept semua parameter default, seperti
pada contoh berikut.
1.
2.
3.
4.
5.
8/232
Apabila menggunakan source code, ekstraklah arsip source code dan masuklah ke dalam direktori hasil
ekstrak.
Cara kedua
Tambahkanlah entri berikut ke /etc/apt/sources.list:
deb http://nightly.openerp.com/7.0/nightly/deb/ ./
Kemudian jalankan:
sudo apt-get update
sudo apt-get install openerp
Persiapan database
Buatlah sebuah user database (kita berikan hak untuk membuat database). Gantilah <user> dengan
nama user yang diinginkan.
sudo -u postgres createuser --pwprompt --createdb <user>
Pastikanlah pengaturan authentication (contoh: /etc/postgresql/9.3/main/pg_hba.conf) telah dilakukan
dengan baik.
9/232
10/232
Membuat database
Untuk membuat database, akses bagian Manage Databases, pada bagian create isi nama database yang
kita inginkan, misal db_latihan, isi password user admin untuk database tersebut. Bagian Master
Password secara default akan terisi dengan admin. Untuk mengubahnya, masuk ke bagian Password.
Untuk menambahkan demo data, aktifkanlah pilihan Load demonstration data. Tunggulah proses yang
berlangsung dan setelah selesai, kita akan login otomatis sebagai user admin dan diarahkan ke halaman
settings, dimana kita bisa melihat modul-modul yang telah terinstall.
Jika kita mengaktifkan pilihan Load demonstration data, maka setelah kita menginstall modul, data
sampel akan disertakan. Ini umumnya kita lakukan ketika mempelajari OpenERP.
Operasi lain
Selain pembuatan database yang telah dibahas sebelumnya, di bagian Manage Databases, kita dapat
pula melakukan berbagai operasi berikut. Semuanya membutuhkan password master OpenERP.
Duplicate
11/232
Modules
Apps
Updates
Installed Modules, daftar modul yang telah kita instal. Apabila kriteria installed pada search
dihapus, kita bisa mencari dari semua modul yang tersedia.
Users
Users, daftar user OpenERP
Translations
Load a Translation, memilih bahasa yang akan dipergunakan
12/232
Apabila kita ingin melakukan pengaturan lebih lanjut, kita dapat mengaktifkan technical features untuk
user tertentu. Sebagai contoh, ketika masih login sebagai admin, di bagian Settings:
pilihlah Users Users
Pilihlah Administrator (admin) dari daftar user
Klik tombol Edit
Aktiflah pada tab Access Rights
Aktifkan pilihan Technical Features
Klik tombol Save
13/232
Ketika kita melakukan reload halaman, maka menu lain akan tersedia pada Settings.
14/232
15/232
Untuk bekerja dengan invoice, kita bisa akses melalui link Invoicing di baris menu bagian atas layar:
Customers
Customer Invoices, berisi data invoice untuk customer yang tercatat dalam database kita.
Customer Refunds, berisi refund dari customer yang tercatat dalam database kita. Refund
adalah dokumen yang berisikan pengurangan sejumlah tagihan dalam invoice yang telah dibuat
untuk customer. Selain melalui bagian ini, refund juga bisa di-generate dari Customer Invoices.
Sales Receipts, berisi data Sales Receipts yang kita terima dari customer. Sales Receipts ini
diperlukan untuk pembuatan Customer Payments.
Customer Payments, berisi data pembayaran yang kita terima dari customer. Kita juga bisa
membuat data pembayaran dari Sales Receipts atau Customer Invoice yang statusnya masih
Open.
Customers, berisi data customer.
Suppliers
Supplier Invoices, berisi data invoice dari supplier yang tercatat dalam database kita.
Supplier Refunds, berisi refund supplier yang tercatat dalam database kita.
Purchase Receipts, berisi data Purchase Receipts yang kita terima dari supplier. Purchase
Receipts ini diperlukan untuk pembuatan data Supplier Payments.
Supplier Payments, berisi data pembayaran dari kita kepada para supplier. Kita juga bisa
membuat data pembayaran dari Purchase Receipts.
Suppliers, berisi data supplier. Dibeberapa sistem bagian ini disebut Master Vendor.
16/232
Untuk bekerja dengan laporan, kita bisa akses melalui link Reporting di baris menu bagian atas layar:
Dashboards
My Dashboard, berisi berbagai laporan yang kita ingin tampilkan sesuai kebutuhan kita.
Berbagai laporan yang terlihat di bagian ini bisa selalu kita ubah-ubah dengan cara masuk ke
modul yang kita inginkan laporannya, klik bagian Graph View dan dari drop down menu di
bagian search, klik Add to Dashboard.
Sales, berisi dashboard mengenai laporan Sales. Secara default bagian ini berisi daftar
Quotation dan grafik Monthly Turnover.
Sales
Sales Analysis, berisi daftar Sales dari setiap personal yang bisa ditampilkan dalam format list
ataupun grafik.
Accounting
Invoices Analysis, berisi laporan analisis invoice.
Sales Receipts Analysis, berisi laporan analisis Sales Receipts.
17/232
18/232
2. Dasar-Dasar Kustomisasi
Penulis: Whisnu Budhysantika
Untuk mengaktifkan fasilitas ini, bisa dengan cara mengakses menu About OpenERP (terdapat di drop
down menu user yang login), lalu klik link Activate the developer mode pada dialog yang ditampilkan.
19/232
Salah satu fitur yang sangat berguna ketika developer mode diaktifkan adalah kita bisa mengetahui
nama dan informasi lain tentang suatu field, ketika kursor mouse diarahkan pada label suatu field.
Selain itu, ketika sedang aktif pada suatu view, kita akan mendapatkan berbagai fasilitas berikut dari
drop down Debug View (item-item berikut tersedia apabila relevan):
View Log (perm_read), menampilkan data:
ID, Identitas unik dari sebuah obyek
XML ID, file xml yang berkaitan dengan obyek.
Creation User, menampilkan data pembuat
Creation Date, menampilkan data tanggal pembuatan
Latest Modification By, menampilkan data pengubah
Latest Modification Date, menampilkan data tanggal pengubahan data
Toggle Form Layout Outline, menampilkan layout dari sebuah form.
Set Defaults, fasilitas untuk membuat value yang ada dalam formulir tersebut menjadi default value
untuk form sejenis. Saat kita memilih fungsi ini, maka akan terdapat form baru yang berisi:
Default, berisi Dropdown mengenai value yang berada dalam form tersebut, misal alamat email,
language, signature dan timezone tergantung pada jenis form-nya.
Opsi Only You dan All Users, bila dipilih Only You, maka default value tersebut hanya berlaku
untuk user yang saat ini sedang login saja. Bila dipilih All Users, maka berlaku untuk semua
user yang terdaftar dalam database tersebut.
JS Test, berfungsi untuk melakukan debugging terhadap seluruh modul yang ada dalam sebuah
database. Kita akan diminta untuk menginput data nama database, password untuk mengakses
database tersebut dan admin password-nya. Selanjutnya adalah proses pengecekan modul oleh
OpenERP dan setelah selesai akan terlihat hasilnya. Bila ditemukan error, maka akan ditandai
20/232
21/232
Manage Views
Saat kita membuka Manage Views, fasilitas ini akan langsung memberikan petunjuk di view mana
sekarang ini kita sedang berada (selected radio button), sebab secara default semua view yang berkaitan
akan ditampilkan. Kita tidak perlu memilih view yang lainnya (kecuali kita tahu). Kita tinggal klik
tombol edit.
22/232
Semua field yang aktif, ditampilkan dalam format XML <field name=nama_field>. Untuk
menambahkan sebuah field baru, kita tinggal mengklik icon plus (+) yang terdapat dibagian kanan
setiap field. Dengan cara ini pula kita bisa memastikan field baru tersebut akan terlihat dibagian mana
dari tampilan.
Saat mengkilk icon plus (+), kita akan dihadapkan ke sebuah dialog yang meminta kita untuk
menginput data Node Type (pilih field) dan Position, selanjutnya klik tombol New Field untuk
membuat field baru ataupun memilih field yang telah dibuat sebelumnya untuk menambahkan field
pada view.
23/232
Field baru
Pada dialog penambahan field baru, kita akan diminta untuk memberikan data:
Wajib diisi
Field name: adalah nama field di database. Untuk penamaan field custom, harus diawali dengan
x_.
Field Label, label yang akan terlihat oleh pengguna.
Field Type, tipe field (untuk selengkapnya, bacalah juga bab 5).
Model, nama model openerp, misal res.partner untuk partner.
Searchable, bila dipilih, maka akan disertakan dalam proses pencarian data.
Tidak wajib diisi:
Domain, python expression, contoh [(color=red)] yang menunjukkan kemungkinan kriteria
dari field.
Serialized Field, jika di set maka field ini tidak akan dibuatkan dalam struktur database tapi
hanya di buat dalam sparse struktur.
Required, bila dipilih, maka field ini akan menjadi field yang wajib diisi.
Read Only, bila dipilih, maka field ini akan menjadi field yang tidak bisa diubah isi defaultnya.
Translatable, bila dipilih, dapat diterjemahkan.
24/232
25/232
26/232
Kekurangan
Apa yang kita lakukan sejauh ini berdampak pada satu database. Bayangkanlah apabila kita harus
melakukan sejumlah kustomisasi yang sama tersebut pada database lain, misal ketika instalasi ulang
dilakukan.
Apabila kita terjemahkan setiap apa yang kita lakukan dalam satu atau lebih modul, modul-modul yang
kita kembangkan tersebut dapat diinstall dan diuninstall setiap kali diperlukan. Sehingga kita bisa
bekerja dengan satu atau lebih database dengan lebih mudah.
Selain itu, terdapat kustomisasi yang lebih kompleks, yang hanya dapat dilakukan lewat pemrograman
dengan Python.
27/232
28/232
Kita bisa melihat satu direktori openerp. Ini merupakan sebuah paket Python:
$ ls -1 --group-directories-first openerp
addons
cli
conf
modules
osv
report
service
tests
tools
workflow
exceptions.py
import_xml.rng
__init__.py
loglevels.py
netsvc.py
PKG-INFO
pooler.py
release.py
sql_db.py
29/232
Apabila kita berada dalam direktori source code OpenERP (root), kita bisa import orm.py dan fields.py
dengan cara berikut:
>>> from openerp.osv import orm, fields
>>> orm
<module 'openerp.osv.orm' from 'openerp/osv/orm.py'>
>>> fields
<module 'openerp.osv.fields' from 'openerp/osv/fields.py'>
>>>
Namun, apabila kita berada di luar source code, maka environment variabel PYTHONPATH perlu diset terlebih dahulu, pada saat kita ingin bekerja dengan nyaman menggunakan IDE (yang mendukung).
Kita tidak perlu lakukan ini pada level modul ketika instalasi dilakukan.
30/232
Kita bisa kopikan modul yang kita kembangkan ke dalam direktori addons yang dikenal, apabila
memiliki hak tulis, atau kita bisa gunakan direktori lain. Direktori lain tersebut kemudian perlu
diinformasikan ke server OpenERP. Bacalah juga bab 8 apabila diperlukan.
Sebuah IDE yang nyaman sangat disarankan. Pilihlah IDE favorit Anda, dan daftarkanlah
PYTHONPATH ataupun hal serupa pada IDE Anda. Apabila didukung, kita bisa memanfaatkan
fasilitas code completion, sebagai contoh.
Mulailah dengan mengembangkan satu modul sederhana, yang menambahkan satu field pada satu
31/232
model. Kita bisa tampilkan field tersebut lewat UI supaya modul kita cukup sederhana.
Pastikan modul dikenal oleh OpenERP. Cobalah untuk install dan pastikan tidak ada pesan
kesalahan.
Apabila modul Anda menambahkan field pada model tertentu, maka Anda bisa juga melihatnya ke
dalam tabel database. Gunakanlah client PostgreSQL yang nyaman, seperti pgAdmin III.
__openerp__.py
{
'name': 'Contoh',
'version': '1.0',
'author': 'noprianto',
'description': 'Contoh modul sederhana',
'category': 'Buku',
'website': 'https://github.com/id-python/buku-openerp',
'depends': ['base'],
'data': [],
}
buku_contoh.py
from openerp.osv import orm, fields
class res_partner(orm.Model):
_name = 'res.partner'
_inherit = 'res.partner'
_columns = {
'buku_contoh': fields.char('Contoh field', size=20)
}
Pada contoh tersebut, kita akan menambahkan satu field, tapi tidak menampilkan dalam view. Ketika
modul sukses diinstall, tidak ada perubahan apapun yang ditampilkan pada model res.partner. Padahal,
sesungguhnya, sebuah field telah ditambahkan. Cobalah untuk menampilkan field buku_contoh dengan
Manage Views.
Untuk informasi tentang model, kita akan membahasnya di bab 5.
32/232
4.1 Pendahuluan
Sebuah perusahaan persewaan kendaraan, melayani sewa kendaraan:
1. Dengan sopir
2. Tanpa sopir
Periode
1. Harian
2. Mingguan
3. Bulanan
Tipe Penggunaan
1. Pribadi / keluarga
2. Dinas
33/232
34/232
Setelah selesai diberikan informasi perusahaan, kita dapat klik pada tombol Preview Header/Footer
untuk melihat header/footer.
Memasang Modul
Lakukanlah instalasi untuk modul-modul berikut:
Fleet Management
Point of Sale
eInvoicing & Payments (akan terinstall dengan sendirinya sebagai dependency)
Kode Rekening
Untuk mencatat semua transaksi agar dapat langsung masuk ke dalam catatan akuntansi (jurnal), perlu
disiapkan kode rekening-kode rekening (Chart of Account COA) yang nanti akan dipergunakan.
Untuk melakukan hal ini, pertama aktifkan Full accounting features, melalui menu Settings
Configuration Akuntansi Full accounting features: journals, legal statements, chart of accounts,
etc.
Lalu untuk mendapatkan daftar kode rekening, klik menu Akuntansi Configuration Akun
Templates Akun Account Templates.
35/232
36/232
Data Awal
Data awal di sini dimaksudkan sebagai data-data dasar yang menjadi acuan data lain pada saat
pengoperasian. Data di sini pada saat berjalan juga masih tetap bisa dilakukan perbaikan, misalnya
ditambah, dihapus, atau diubah.
37/232
Kendaraan
Kendaraan perlu dicatat ke dalam sistem sebagai bagian dari aset. Administrasi kendaraan ini dilakukan
dari menu Fleet. Beberapa data yang perlu diadministrasi antara lain:
1. Kendaraan
2. Service, baik berkala maupun yang berbasis kejadian
3. Bahan bakar, yaitu pencatatan penggunaan bahan bakar
4. Biaya lain
5. Kontrak, misalnya bila kendaaraan disewa dalam jangka waktu yang lama atau berbasis kontrak
Untuk menambah kendaraan, klik menu Fleet Vehicle Vehicle, kemudian klik tombol Create.
38/232
39/232
Pelanggan
Pelanggan ini adalah pilihan, artinya tidak wajib ditambahkan. Namun lebih baik ditambahkan, hal ini
akan memberi nilai tambah sistem agar dapat diketahui loyalitas pelanggan. Selain itu juga berguna
untuk menjaga hubungan agar pelanggan tetap loyal dan perbaikan layanan.
Pelanggan dapat berupa perorangan maupun perusahaan. Data pelanggan perlu dihubungkan dengan
kode rekening yang telah disiapkan sebelumnya.
Data pelanggan dapat dilihat dari menu Sales Sales Customers.
40/232
Operasi
Setelah data-data disiapkan, sistem dapat dioperasikan untuk mencatat transaksi-transaksi yang terjadi.
Beberapa transaksi yang mungkin terjadi pada sistem antara lain:
1. Pelanggan melakukan sewa kendaraan
2. Kendaraan dilakukan perbaikan
3. Laporan keuangan
Pelayanan Sewa Kendaraan
Ada beberapa langkah untuk hingga menerima pembayaran, yaitu:
1. Membuat penawaran
2. Konfirmasi penjualan
3. Membuat tagihan / invoice
4. Terima pembayaran
Pencatatan sewa kendaraan dapat dimulai dari membuat penawaran yang dilakukan melalui menu Sales
Sales Order Penjualan dan klik tombol Create.
41/232
Setelah selesai mengisi data-data, lalu klik tombol Confirm Sale. Setelah ini, maka kita bisa membuat
tagihan / faktur. Setelah Buat Faktur, lalu View Invoice dan klik tombol Validasi, maka faktur sudah
final yang dapat dicetak untuk pelanggan sebagai bahan tagihan.
42/232
Untuk mencatat penerimaan pembayaran, klik tombol Register Payment. Pada dialog yang ditampilkan,
isikan pembayaran dan klik tombol Pay.
43/232
Hal ini akan membuat status dari penjualan ini sudah terbayar.
44/232
Laporan
Ada berbagai laporan keuangan dapat dihasilkan dari openERP. Berikut ini beberapa screenshot yang
mungkin berkaitan dengan Laporan.
Laporan dapat diakses dari menu Reporting.
Dashboard Laporan
45/232
46/232
Laporan Akuntansi
47/232
48/232
Untuk bekerja dengan class ini, kita melakukan import dengan cara:
>>> from openerp.osv import orm
Apa yang kita lakukan pada contoh terakhir adalah mengimport modul orm dan fields dari package
openerp.osv. Sebagai catatan, modul fields mendefinisikan class-class tipe field yang didukung oleh
OpenERP.
Dengan menurunkan dari class Model ini, kita dapat menggunakan dan/atau mengoverride sejumlah
atribut dan method yang telah disediakan.
Dengan komentar tidak disertakan, ini adalah definisi seutuhnya dari class Model.
49/232
class Model(BaseModel):
_auto = True
_register = False
_transient = False
50/232
Dengan cara demikian, kita bisa menggunakan osv.osv dan osv.Model untuk backward compatibility.
Di prompt interaktif Python:
>>> from openerp.osv import osv
>>> osv.osv
<class 'openerp.osv.orm.Model'>
>>> osv.Model
<class 'openerp.osv.orm.Model'>
>>>
>>>
>>> from openerp.osv import orm
>>> orm.Model
<class 'openerp.osv.orm.Model'>
>>>
>>>
Walaupun kita tetap bisa menggunakan osv.osv, untuk kode baru yang ditujukan untuk dijalankan pada
OpenERP versi baru, kita akan menggunakan orm.Model.
51/232
5.3 Atribut
Class BaseModel memiliki sejumlah atribut yang memiliki peranan/arti tertentu dalam OpenERP. Dan,
class Model, sebagai turunan, hanya mendefinisikan ulang beberapa dari atribut tersebut. Class yang
kita bangun, sebagai turunan dari Model, juga melakukan hal yang lebih kurang sama.
Dalam contoh yang akan kita bahas, dimana kita menambah field pada model tertentu, apa yang kita
lakukan adalah:
Membuat sebuah class baru (menurunkan dari Model)
Mendefinisikan ulang beberapa atribut seperti _name, _inherit dan _columns.
Tanpa kita melakukan lebih jauh lagi, field secara otomatis akan ditambahkan.
Berikut adalah sejumlah atribut yang disediakan oleh Model.
Atribut
Default
Catatan
_auto
True
_register
False
_name
None
_columns
{}
_constraints
[]
_custom
False
_defaults
{}
_rec_name
None
_parent_name
'parent_id'
_parent_store
False
_parent_order
False
_date_name
'date'
_order
'id'
_sequence
None
_description
None
_needaction
False
_group_by_full
{}
52/232
Default
Catatan
False
_inherit
_inherits
{}
_inherit_fields
{}
_all_columns
{}
_table
None
_invalids
set()
_log_access
Apabila
tidak Apabila True, maka 4 field akan dibuat
ditentukan,
maka otomatis: create_uid, create_date, write_uid,
nilai
diambil write_date, untuk keperluan log.
berdasarkan _auto,
dengan
default
adalah True
_log_create
False
_sql
_sql_constraints
[]
_protected
['read', 'write',
'create',
'default_get',
'perm_read',
'unlink',
'fields_get',
'fields_view_get'
, 'search',
'name_get',
'distinct_field_g
et',
'name_search',
'copy',
'import_data',
'search_count',
'exists']
CONCURRENCY_CHECK_FIELD
'__last_update'
Modul fields mendefinisikan class-class field yang didukung oleh OpenERP. Contoh output dari dir()
module fields:
>>> dir(fields)
['Binary', 'DT', 'SUPERUSER_ID', '_', '__builtin__', '__builtins__', '__doc__',
'__file__', '__name__', '__package__', '_column', '_logger', '_symbol_set',
'_symbol_set_char', 'base64', 'binary', 'boolean', 'char', 'column_info', 'date',
'datetime', 'dummy', 'field_to_dict', 'float', 'float_repr', 'float_round',
'function', 'get_nice_size', 'html', 'html_sanitize', 'integer',
'invalid_xml_low_bytes', 'logging', 'many2many', 'many2one', 'one2many', 'openerp',
'property', 'pytz', 're', 'reference', 'related', 'sanitize_binary_value',
'selection', 'serialized', 'simplejson', 'sparse', 'text', 'tools', 'xmlrpclib']
>>>
Class _column
Modul fields mendefinisikan sebuah class dengan nama _column, yang merupakan base class untuk
semua tipe field. Berikut adalah atribut yang didefinisikan:
>>> from openerp.osv import orm, fields
>>> c = fields._column()
>>> dir(c)
['__class__', '__delattr__', '__dict__', '__doc__', '__format__',
'__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__',
'__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__',
'__subclasshook__', '__weakref__', '_as_display_name', '_auto_join',
'_classic_read', '_classic_write', '_context', '_deprecated', '_domain', '_multi',
'_obj', '_prefetch', '_properties', '_symbol_c', '_symbol_f', '_symbol_get',
54/232
class reference(_column)
| __init__(self, string, selection, size, **args)
56/232
SELECTION_1 = [
('pilihan1', 'Pilihan 1'),
('pilihan2', 'Pilihan 2'),
('pilihan3', 'Pilihan 3'),
]
SELECTION_2 = [
('pilihan4', 'Pilihan 4'),
('pilihan5', 'Pilihan 5'),
('pilihan6', 'Pilihan 6'),
('pilihan7', 'Pilihan 7'),
('pilihan8', 'Pilihan 8'),
('pilihan9', 'Pilihan 9'),
('pilihan10', 'Pilihan 10'),
]
class res_partner(orm.Model):
_name = 'res.partner'
_inherit = 'res.partner'
def _get_selection_2(self, cr, uid, context=None):
return SELECTION_2
58/232
'Order
Reference',
required=True,
readonly=True,
states={'draft':
'order_line':
readonly=True,
False)]}),
fields.one2many('sale.order.line',
'order_id',
'Order
Lines',
states={'draft': [('readonly', False)], 'sent': [('readonly',
id1='partner_id',
60/232
Untuk contoh tersebut, field buku_field_12 tidak disimpan pada tabel database.
Salah satu contoh tipe field ini yang dapat ditemukan pada OpenERP adalah field country_id dan
country pada res.partner.
Contoh (cuplikan dari openerp/addons/base/res/res_partner.py):
'country_id': fields.many2one('res.country', 'Country'),
'country': fields.related('country_id', type='many2one', relation='res.country',
string='Country',
deprecated="This field will be removed as of
OpenERP 7.1, use country_id instead"),
Dan, kita ingin agar isi field tersebut, yang bertipe char, harus memiliki panjang minimal tiga karakter.
Kita dapat definisikan _constraints dan fungsi untuk memeriksa, sebagai berikut:
def _check_field_11(self, cr, uid, ids, context=None):
for i in self.browse(cr, uid, ids, context=context):
if len(i.buku_field_11) >= 3:
return True
return False
_constraints = (
[_check_field_11, 'Panjang harus minimal 3 karakter',
['buku_field_11']],
)
62/232
Apa yang kita lakukan dengan _name sama dengan _inherit adalah class inheritance, yang kita gunakan
dalam bab ini. Alternatif adalah:
63/232
_name tidak sama dengan _inherit (inheritance by prototype) dimana data disimpan pada tabel lain.
Menggunakan _inherits (inheritance by delegation).
64/232
5.7 Method
Class BaseModel memiliki sejumlah method yang dapat kita gunakan (langsung atau tidak) ataupun
override.
Override umumnya kita perlukan ketika fungsi yang ditawarkan perlu disesuaikan lebih lanjut. Sebagai
contoh, kita menurunkan dari res.partner dan ketika suatu partner dibuat atau diedit, kita ingin
melakukan fungsi tambahan, selain fungsi default yang telah disediakan.
Method-method yang ada dapat pula diakses lewat web service. Bacalah juga bab 9 apabila diperlukan.
Berikut adalah sejumlah method yang disediakan oleh Model. Dokumentasi yang disediakan secara
umum cukup lengkap. Kita akan membahas beberapa diantaranya setelah ini, dalam bagian-bagian
tersendiri.
Method
Argumen
__init__
self, pool, cr
browse
check_access_rights
check_access_rule
check_field_access_rights
check_recursion
clear_caches
self
copy
copy_data
copy_translations
create
default_get
distinct_field_get
exists
export_data
fields_get
fields_get_keys
fields_view_get
get_external_id
Argumen
get_invalid_fields
get_xml_id, get_external_id
import_data
is_transient
self
load
log
name_create
name_get
name_search
perm_read
perm_write
read
read_group
read_string
resolve_2many_commands
search_count
unlink
user_has_groups
view_header_get
view_init
write
write_string
Kalau kita cermati argumen fungsi, kita akan menemukan beberapa yang umum seperti berikut.
66/232
Catatan
cr
user, uid
ids
Id yang akan diproses. Umumnya berupa list dari id. Sebagai contoh, ketika
memanggil unlink, yang akan menghapus record, ids dapat berisikan id-id
record yang akan dihapus.
vals
Merupakan nilai penting yang berhubungan langsung dengan apa yang akan
dilakukan method. Umumnya berupa dictionary. Sebagai contoh, pada
fungsi create yang akan membuat record baru, vals dalam hal ini adalah
dictionary berisi nama field (key) dan nilainya (value).
fields
context
67/232
Setelah itu, untuk langkah ketiga, kita melakukan inisialisasi kursor database:
>>> cr = db.cursor()
>>> cr
<openerp.sql_db.Cursor object at 0xb479a40c>
>>>
Pada langkah keempat berikut, kita akan mengakses salah satu model. Sebagai contoh, kita akan
bekerja dengan model sale_order.
>>> from openerp.addons.sale import sale
Dari manakah kita mendapatkan struktur package seperti itu? Perhatikanlah bahwa modul sale terletak
pada:
$ file openerp/addons/sale/sale.py
openerp/addons/sale/sale.py: Python script, ASCII text executable, with very long
68/232
Apabila langkah keempat sukses dilakukan, kita akan melanjutkan dengan membuat instance dari
model sale.order:
>>> so = sale.sale_order.create_instance(pool, cr)
>>> so
<openerp.osv.orm.sale.order object at 0xb5407bec>
>>>
Perhatikanlah bahwa di dalam modul sale, kita memiliki class sale_order. Sementara, class sale_order
merupakan turunan dari osv.osv (orm.Model), dan kita memiliki class method create_instance.
Selanjutnya, kita tinggal menggunakan method dari Model. Kita akan membahasnya di beberapa
bagian berikut.
69/232
Perhatikanlah bahwa kriteria pencarian dituliskan dalam Polish Notation atau prefix notation (notasi
prefix). Sebagai contoh lain, kita akan mencari dari res.partner, untuk:
nama yang mengandung 'tes' (tidak case-sensitive) atau untuk id < 3
dan
website = ''
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)
70/232
71/232
72/232
73/232
Perhatikanlah bahwa kita memanggil fungsi commit dari kursor koneksi database.
74/232
75/232
__init__.py
from . import buku_partner_nop_1
__openerp__.py
{
'name': 'Partner 1',
'version': '1.0',
'author': 'noprianto',
'description': 'Contoh sederhana tambah field pada partner',
'category': 'Buku',
'website': 'https://github.com/id-python/buku-openerp',
'depends': ['base'],
'data': ['buku_partner_nop_1_view.xml'],
76/232
buku_partner_nop_1.py
from openerp.osv import orm, fields
SELECTION_1 = [
('pilihan1', 'Pilihan 1'),
('pilihan2', 'Pilihan 2'),
('pilihan3', 'Pilihan 3'),
]
SELECTION_2 = [
('pilihan4', 'Pilihan 4'),
('pilihan5', 'Pilihan 5'),
('pilihan6', 'Pilihan 6'),
('pilihan7', 'Pilihan 7'),
('pilihan8', 'Pilihan 8'),
('pilihan9', 'Pilihan 9'),
('pilihan10', 'Pilihan 10'),
]
class res_partner(orm.Model):
_name = 'res.partner'
_inherit = 'res.partner'
def _get_selection_2(self, cr, uid, context=None):
return SELECTION_2
_columns = {
'buku_field_1': fields.char('Buku Field 1', size=20,
required=True,
help='Contoh help'),
'buku_field_2': fields.float('Buku Field 2', digits=(4, 2)),
'buku_field_3': fields.integer('Buku Field 3', size=10),
'buku_field_4': fields.boolean('Buku Field 4'),
'buku_field_5': fields.date('Buku Field 5'),
'buku_field_6': fields.datetime('Buku Field 6'),
'buku_field_7': fields.selection(SELECTION_1, 'Buku Field 7'),
'buku_field_8': fields.selection(_get_selection_2, 'Buku Field
8'),
}
buku_partner_nop_1_view.xml
<?xml version="1.0"?>
<openerp>
<data>
77/232
78/232
__init__.py
from . import buku_partner_nop_2
__openerp__.py
{
'name': 'Partner 2',
'version': '1.0',
'author': 'noprianto',
'description': 'Contoh sederhana readonly dan default pada field',
'category': 'Buku',
'website': 'https://github.com/id-python/buku-openerp',
'depends': ['base'],
'data': ['buku_partner_nop_2_view.xml'],
}
79/232
buku_partner_nop_2.py
from openerp.osv import orm, fields
class res_partner(orm.Model):
_name = 'res.partner'
_inherit = 'res.partner'
_columns = {
'buku_field_9': fields.char('Buku Field 9', size=20,
readonly=True),
'buku_field_10': fields.char('Buku Field 10'),
}
_defaults = {
'buku_field_9': 'Contoh default',
'buku_field_10': lambda self, cr, uid, context: '
'.join(context.keys()),
}
buku_partner_nop_2_view.xml
<?xml version="1.0"?>
<openerp>
<data>
<record model="ir.ui.view" id="view_partner_form">
<field name="name">res.partner.form</field>
<field name="model">res.partner</field>
<field name="inherit_id" ref="base.view_partner_form"/>
<field name="type">form</field>
<field name="arch" type="xml">
<notebook position="inside">
<page string="Buku (4-2)">
<group>
<field name="buku_field_9"/>
<field name="buku_field_10"/>
</group>
</page>
</notebook>
</field>
</record>
</data>
</openerp>
80/232
__init__.py
from . import buku_partner_nop_3
__openerp__.py
{
'name': 'Partner 3',
'version': '1.0',
'author': 'noprianto',
'description': 'Contoh sederhana constraint pada field',
'category': 'Buku',
'website': 'https://github.com/id-python/buku-openerp',
'depends': ['base'],
'data': ['buku_partner_nop_3_view.xml'],
}
81/232
buku_partner_nop_3.py
from openerp.osv import orm, fields
class res_partner(orm.Model):
_name = 'res.partner'
_inherit = 'res.partner'
_columns = {
'buku_field_11': fields.char('Buku Field 11', size=20,
required=True),
}
_defaults = {
'buku_field_11': 'hello',
}
def _check_field_11(self, cr, uid, ids, context=None):
for i in self.browse(cr, uid, ids, context=context):
if len(i.buku_field_11) >= 3:
return True
return False
_constraints = (
[_check_field_11, 'Panjang harus minimal 3 karakter',
['buku_field_11']],
)
buku_partner_nop_3_view.xml
<?xml version="1.0"?>
<openerp>
<data>
<record model="ir.ui.view" id="view_partner_form">
<field name="name">res.partner.form</field>
<field name="model">res.partner</field>
<field name="inherit_id" ref="base.view_partner_form"/>
<field name="type">form</field>
<field name="arch" type="xml">
<notebook position="inside">
<page string="Buku (4-3)">
<group>
<field name="buku_field_11"/>
</group>
</page>
</notebook>
</field>
82/232
83/232
__openerp__.py
{
'name': 'Partner 4',
'version': '1.0',
'author': 'noprianto',
'description': 'Contoh sederhana field functional',
'category': 'Buku',
'website': 'https://github.com/id-python/buku-openerp',
'depends': ['base'],
'data': ['buku_partner_nop_4_view.xml'],
}
buku_partner_nop_4.py
import random
from openerp.osv import orm, fields
class res_partner(orm.Model):
_name = 'res.partner'
_inherit = 'res.partner'
def _function_test(self, cr, uid, ids, field, arg, context=None):
res = {}
for i in ids:
res[i] = random.random()
return res
_columns = {
'buku_field_12': fields.function(_function_test, type='float')
}
buku_partner_nop_4_view.xml
84/232
85/232
__openerp__.py
{
'name': 'Partner 5',
'version': '1.0',
'author': 'noprianto',
'description': 'Contoh sederhana override method create/write',
'category': 'Buku',
'website': 'https://github.com/id-python/buku-openerp',
'depends': ['base'],
}
buku_partner_nop_5.py
from openerp.osv import orm, fields
class res_partner(orm.Model):
_name = 'res.partner'
_inherit = 'res.partner'
def write(self, cr, user, ids, vals, context=None):
comment = vals.get('comment', '')
try:
comment = comment.strip()
vals['comment'] = comment
except AttributeError:
pass
return super(res_partner, self).write(cr, user, ids, vals, context)
def create(self, cr, user, vals, context=None):
comment = vals.get('comment', '')
try:
comment = comment.strip()
vals['comment'] = comment
except AttributeError:
pass
return super(res_partner, self).create(cr, user, vals, context)
86/232
6. Dasar-dasar View
Penulis: Noprianto
Pada bab-bab sebelumnya, kita telah melihat view yang didefinisikan dalam file-file XML. Di bab ini,
kita akan membahas lebih lanjut tentang dasar-dasar view pada OpenERP. Termasuk bagaimana
menambahkan menu/menu item.
OpenERP mendukung beberapa macam tipe view. Namun, kita hanya akan membahas tentang form
dan tree. Form digunakan untuk menampilkan suatu record secara detil. Sementara, tree digunakan
untuk menampilkan beberapa record sekaligus (list). Keduanya dapat pula digunakan untuk
menambahkan/mengedit data, walau pada tree, ini akan lebih terbatas.
Pembahasan akan dilakukan langsung pada contoh modul.
Catatan: definisi view umumnya ditempatkan dalam sub direktori view dalam modul.
6.1 Kerangka
Berikut ini adalah kerangka definisi view dalam sebuah file XML:
<?xml version="1.0"?>
<openerp>
<data>
<definisi view>
.
.
.
<definisi view>
</data>
</openerp>
</record>
87/232
Contoh 2:
<record model="ir.ui.view" id="view_catatan_tree">
</record>
Contoh 3:
<record model="ir.actions.act_window" id="action_buku_catatan_tree">
</record>
Contoh 4:
<menuitem name="Buku" id="menu_buku"/>
Di dalam setiap <record>, kita umumnya bekerja dengan tag <field> dengan berbagai atribut, <form>
dengan berbagai elemen di dalamnya, <tree> ataupun lainnya.
Berikut adalah contoh tag <field>:
<field
<field
<field
<field
name="name">res.partner.form</field>
name="model">res.partner</field>
name="inherit_id" ref="base.view_partner_form"/>
name="arch" type="xml">
</field>
88/232
Lebih lanjut, terdapat sejumlah atribut tambahan yang bisa diberikan pada tag ini, yang mana akan
memiliki arti/efek.
Contoh 1:
<field name="fax" position="replace"/>
Contoh 2:
<field name="mobile" position="before">
<field name="fax"/>
</field>
Contoh 3:
<field name="buku_field_17" password="True" nolabel="1" colspan="2"/>
Contoh 4:
<field name="buku_field_18" attrs="{'required': ['&', ('is_company', '=',
False), ('street', '=', False)]}"/>
89/232
90/232
Catatan: pada saat kita mendefinisikan view, kita juga memberikan nilai id unik per modul.
91/232
92/232
Tag <data> dapat digunakan untuk perubahan pada beberapa lokasi sekaligus.
Menambah field fax sebelum field mobile. Kita akan mulai dari field mobile dengan
position=before, barulah mendefinisikan field fax di dalamnya.
<field name="mobile" position="before">
<field name="fax"/>
</field>
93/232
fields.char('Buku
fields.char('Buku
fields.char('Buku
fields.char('Buku
fields.char('Buku
fields.char('Buku
fields.char('Buku
fields.char('Buku
94/232
Field
Field
Field
Field
Field
Field
Field
Field
13',
14',
15',
16',
17',
18',
19',
20',
size=10),
size=10),
size=10),
size=10),
size=10),
size=10),
size=10),
size=10),
95/232
96/232
97/232
</page>
</notebook>
Menambahkan sebuah field di dalam page tersebut. Per OpenERP versi 7.0, <field
name=nama_field/> tidak menampilkan label, kecuali ditempatkan di dalam <group>. Oleh
karena itu, kita menggunakan <label for=nama_field/> seperti pada contoh.
<label for="buku_field_13"/>
<field name="buku_field_13"/>
Kita membuat sebuah group baru, yang bisa digunakan untuk mengelompokkan sejumlah kolom
dan kemudian membaginya kembali menjadi kolom-kolom. Per OpenERP versi 7.0, jumlah kolom
default dalam group adalah 2, kecuali kita menentukan secara eksplisit dengan atribut col=n.
Group bisa diberikan label/title seperti pada contoh. Kita tambahkan sebuah field ke dalam group
tersebut.
<group string="contoh group">
<field name="buku_field_14"/>
</group>
Kemudian, kita buat satu group lagi dengan jumlah kolom adalah 6. Lalu kita tambahkan dua field,
yang pertama menempati 4 kolom (dengan atribut colspan=n) dan yang kedua menempati
sisanya. Perhatikanlah bahwa label secara otomatis ditambahkan karena dibawah <group>.
98/232
99/232
Kita akan membuat sebuah tab baru, namun tab tersebut hanya tampil apabila partner adalah
perorangan, bukan perusahaan. Apabila Is a Company? di centang, maka tab ini tidak ditampilkan.
Lebih lanjut lagi, di dalam tab tersebut, kita tambahkan dua field, di mana salah satunya, akan menjadi
required (harus diisi) apabila:
Partner bukanlah perusahaan, dan
Alamat (street) tidak diisikan.
Berikut adalah definisi view selengkapnya (buku_partner_nop_9_view.xml):
<?xml version="1.0"?>
<openerp>
<data>
<record model="ir.ui.view" id="view_partner_form">
<field name="name">res.partner.form</field>
<field name="model">res.partner</field>
<field name="inherit_id" ref="buku_partner_nop_7.view_partner_form"/>
100/232
<page
[('is_company', '=', True)]}">
string="Bukan
perusahaan"
attrs="{'invisible':
</page>
Menambahkan satu field lagi, dengan atribut attrs, di mana field akan required apabila kondisi
berikut terpenuhi (& untuk operator &) : ['&', ('is_company', '=', False),
('street', '=', False)]
<field name="buku_field_18" attrs="{'required': ['&', ('is_company', '=',
101/232
Catatan: eval digunakan untuk evaluasi ekspresi Python, digunakan untuk nilai non string.
Sama
seperti
sebelumnya,
dalam
buku_partner_nop_7.view_partner_form
contoh
ini,
kita
turunkan
view
dari
dan modul juga membutuhkan buku_partner_nop_7.
102/232
103/232
Dan, berikut adalah definisi fungsi yang dipanggil, dalam file buku_partner_nop_10.py:
from openerp.osv import orm
class res_partner(orm.Model):
_name = 'res.partner'
_inherit = 'res.partner'
def onchange_buku_field_19(self, cr, uid, ids, buku_field_19, context=None):
ret = {}
ret['warning'] = {
'title': 'Pesan',
'message': 'Isi field buku_field_19 adalah %s' %
(buku_field_19),
}
return ret
Apa yang kita lakukan adalah menambahkan satu field, dengan atribut on_change, dengan nilai
statement pemanggilan fungsi on change, lengkap dengan argumen berupa nama field. Nama field
harus didefinisikan dalam view.
<field name="buku_field_19" on_change="onchange_buku_field_19(buku_field_19)"/>
Fungsi yang dipanggil setidaknya harus menerima argumen cr, uid, ids sebagaimana method lain
(seperti dibahas pada Bab 4), apa yang ingin kita lewatkan, dan sebuah context (sebagaimana
disarankan, disinggung pada Bab 4). Fungsi tersebut dapat merujuk ke record lain yang telah tersimpan
dalam database.
def onchange_buku_field_19(self, cr, uid, ids, buku_field_19, context=None):
Nilai kembalian fungsi, sebuah dictionary, akan menentukan apa yang akan dilakukan sesuai key:
domain: dictionary berupa domain {field: domain}.
value: dictionary berupa nilai field baru: {field: value}. Ini bisa lebih dari satu field, sebagaimana
dibahas pada contoh berikutnya. Dapat memicu pemanggilan fungsi on change pada field lain,
apabila didefinisikan.
warning: dictionary dengan key title (judul) dan message (pesan), yang digunakan untuk
menampilkan pesan. Ini adalah yang kita lakukan dalam contoh ini.
ret = {}
ret['warning'] = {
'title': 'Pesan',
104/232
Catatan: fungsi on change dapat digunakan pada saat record sedang dibuat dan belum disimpan pada
database. Fungsi ini dapat membaca dari database, namun tidak seharusnya menulis ke database.
Sama
seperti
sebelumnya,
dalam
buku_partner_nop_7.view_partner_form
contoh
ini,
kita
turunkan
view
dari
dan modul juga membutuhkan buku_partner_nop_7.
105/232
Dan, berikut adalah definisi fungsi on change yang dipanggil, dalam file buku_partner_nop_11.py:
106/232
Sebagaimana dibahas pada contoh sebelumnya, fungsi mengembalikan dictionary dengan key berupa
value, dengan nilai berupa isi field yang telah ditukar.
Kita lihat bahwa fungsi bekerja dengan isi dua field dilewatkan:
<field
name="buku_field_20"
buku_field_19)"/>
on_change="onchange_buku_field_20(buku_field_20,
Apabila modul pada contoh sebelumnya terinstall, maka ini akan memicu pemanggilan on change.
Sama
seperti
sebelumnya,
dalam
contoh
ini,
kita
turunkan
view
dari
buku_partner_nop_7.view_partner_form dan modul juga membutuhkan buku_partner_nop_7.
File __openerp__.py dalam modul:
{
'name': 'Partner 11',
'version': '1.0',
'author': 'noprianto',
'description': 'form view (partner), on change 2',
'category': 'Buku',
'website': 'https://github.com/id-python/buku-openerp',
'depends': ['buku_partner_nop_7'],
'data': ['buku_partner_nop_11_view.xml'],
}
107/232
108/232
Apa yang berbeda dengan contoh sebelumnya (5.4, modul buku_partner_nop_6), dari sisi inheritance,
selain field yang terlibat, adalah:
<field name="inherit_id" ref="base.view_partner_tree"/>
Di mana nilai base.view_partner_tree kita dapatkan dari popup Manage Views dengan developer mode
diaktifkan.
File __openerp__.py dalam modul:
{
'name': 'Partner 12',
'version': '1.0',
'author': 'noprianto',
'description': 'tree view (partner), tambah/sembunyikan field',
'category': 'Buku',
'website': 'https://github.com/id-python/buku-openerp',
'depends': ['base'],
'data': ['buku_partner_nop_12_view.xml'],
}
109/232
110/232
111/232
112/232
113/232
114/232
7. Dasar-dasar Report
Penulis: Noprianto
Untuk membuat report sendiri di OpenERP, kita memiliki beberapa pilihan cara. Yang akan kita bahas
dalam bab ini adalah penggunaan RML, yang merupakan cara original dalam membuat report di
OpenERP. Cara lain juga tersedia, baik yang datang bersama OpenERP ataupun menggunakan modul
dari pihak lain.
Report dapat ikut pada model, seperti ketika kita memilih beberapa record dari res.partner, kemudian
klik pada tombol Print dan memilih report yang tersedia. Report juga dapat ditempatkan pada
menu/menuitem tersendiri. Apabila parameter dibutuhkan dalam menghasilkan report, kita bisa
menggunakan wizard.
Pembahasan akan dilakukan langsung pada contoh modul.
Catatan: definisi wizard umumnya ditempatkan dalam sub direktori wizard dan definisi report
umumnya ditempatkan dalam sub direktori report.
7.1 Definisi
Sebagaimana halnya view, report juga didefinisikan di dalam file XML.
<?xml version="1.0"?>
<openerp>
<data>
<definisi report>
.
.
.
<definisi report>
</data>
</openerp>
Untuk mendefinisikan report, kita gunakan tag <report> dengan sejumlah atribut. Di dalam bab ini, kita
akan menggunakan:
id: id report (unik).
name: nama report (dibutuhkan).
string: judul report (dibutuhkan).
model: model dimana report didefinisikan (dibutuhkan).
rml: path ke file RML, relatif terhadap addons (apabila digunakan).
auto: apabila False, custom parser digunakan.
header: apabila False, header tidak digunakan.
115/232
Contoh:
<report
id="report_buku_partner_nop_13"
name="buku.partner.nop.13"
string="Report 13"
model="res.partner"
rml="buku_partner_nop_13/report.rml"
auto="True"
header="False"/>
116/232
117/232
118/232
119/232
Dari definisi tersebut, bisa kita lihat bahwa kita akan bekerja dengan model res.partner, tanpa
penggunaan custom parser dan tidak menambahkan header pada laporan.
Laporan sendiri akan dihasilkan dari file report.rml:
<?xml version="1.0"?>
<document filename="report.pdf">
<template pageSize="(612, 792)" title="Report">
<pageTemplate id="page">
<frame id="page" x1="30.0" y1="30.0" width="552" height="732"/>
</pageTemplate>
</template>
<stylesheet>
<blockTableStyle id="Table">
<blockAlignment value="LEFT"/>
<blockValign value="TOP"/>
<lineStyle kind="GRID" colorName="#000000" start="0,0" stop="-1,-1"/>
</blockTableStyle>
<paraStyle name="Standard" fontName="Courier"/>
</stylesheet>
<story>
<para style="Standard">Report 13<br/><br/></para>
<blockTable colWidths="100,200,252" repeatRows="1" style="Table">
<tr>
<td>
<para style="Standard">ID</para>
</td>
<td>
<para style="Standard">Nama</para>
</td>
<td>
<para style="Standard">Website</para>
</td>
</tr>
<tr>
<td>
<para style="Standard">[[ repeatIn(objects, 'o') ]]</para>
<para style="Standard">[[ o.id ]]</para>
</td>
<td>
<para style="Standard">[[ o.name ]]</para>
</td>
<td>
<para style="Standard">[[ o.website ]]</para>
</td>
</tr>
</blockTable>
</story>
120/232
Menambahkan tabel, dengan tiga kolom sesuai ukuran lebar, menggunakan style 'Table' dan baris
pertama akan diulang. Baris dan kolom mirip dengan pada HTML.
<blockTable colWidths="100,200,252" repeatRows="1" style="Table">
</blockTable>
121/232
122/232
Karena kita menggunakan custom parser, auto kita berikan nilai False.
Laporan sendiri akan dihasilkan dari file report.rml:
<?xml version="1.0"?>
<document filename="report.pdf">
<template pageSize="(612, 792)" title="Report">
<pageTemplate id="page">
<frame id="page" x1="30.0" y1="30.0" width="552" height="732"/>
<pageGraphics>
<setFont name="Courier" size="8"/>
<drawString x="30" y="20">Halaman <pageNumber/></drawString>
</pageGraphics>
</pageTemplate>
</template>
<stylesheet>
<blockTableStyle id="Table">
<blockAlignment value="LEFT"/>
<blockValign value="TOP"/>
<lineStyle kind="GRID" colorName="#000000" start="0,0" stop="-1,-1"/>
</blockTableStyle>
<paraStyle name="Standard" fontName="Courier"/>
</stylesheet>
<story>
<para style="Standard">Report 14<br/><br/></para>
<para style="Standard">[[ time.asctime() ]]<br/><br/></para>
<para style="Standard">[[ user.name ]]<br/><br/></para>
<para style="Standard">[[ random.random() ]]<br/><br/></para>
<blockTable colWidths="100,200,252" repeatRows="1" style="Table">
123/232
Untuk menambahkan nomor halaman, kita bisa tempatkan dalam blok <pageGraphics> di dalam
<pageTemplate>. Untuk menggambar string, kita gunakan tag <drawString> pada posisi x dan y
tertentu. Nomor halaman aktif didapatkan dengan tag <pageNumber>.
<pageGraphics>
<setFont name="Courier" size="8"/>
<drawString x="30" y="20">Halaman <pageNumber/></drawString>
</pageGraphics>
Karena kita punya akses ke modul time, maka kita bisa gunakan:
<para style="Standard">[[ time.asctime() ]]<br/><br/></para>
User yang menjalankan report bisa diakses dengan cara berikut (perhatikanlah bahwa ini adalah object
user OpenERP):
<para style="Standard">[[ user.name ]]<br/><br/></para>
124/232
Dalam constructor class yang diturunkan dari rml_parse, kita memanggil constructor parent dan
mengupdate localcontext. Akses untuk modul random kita berikan dengan key 'random'. Kita bisa
gunakan dalam report:
<para style="Standard">[[ random.random() ]]<br/><br/></para>
Tidak lupa, kita instansiasi class report_sxw dari modul report_sxw, dengan informasi laporan kita,
termasuk parser yang digunakan.
Dalam contoh yang lebih umum, kita bisa tambahkan method dalam class parser, yang kemudian
ditambahkan cara akses pada localcontext sehingga bisa dipanggil dari dalam report.
125/232
126/232
7.6 Wizard
Dalam contoh modul buku_nop_report_1, kita bekerja pada model res.partner dan akan menambahkan
satu report.
Report akan diakses lewat menuitem tersendiri. Hasil dari report adalah daftar partner dengan nama
mengandung karakter tertentu. Untuk kebutuhan ini, kita tidak perlu memilih satu atau lebih record,
karena justru yang ingin kita lakukan adalah mencari.
Kriteria pencarian dapat diinput pada wizard.
Ini merupakan contoh sederhana, namun dapat dikembangkan lebih lanjut.
127/232
128/232
</document>
Kriteria pencarian yang diinput oleh user lewat wizard dapat kita akses dengan cara berikut. Variabel
data merupakan sebuah dictionary, mengandung key 'form', yang juga merupakan sebuah dictionary,
mengandung key 'name' berisi apa yang diinput oleh user.
<para
style="Standard">Nama
mengandung
{}).get('name') ]]<br/><br/></para>
teks:
[[
data.get('form',
Karena kita bekerja dengan wizard, kita perlu membuatnya terlebih dahulu, dalam bentuk sebuah class,
yang diturunkan dari orm.TransientModel. Berikut adalah isi file buku_nop_report_1_wizard.py:
from openerp.osv import orm, fields
class buku_nop_report_1(orm.TransientModel):
_name = 'buku.nop.report.1'
_description = 'buku nop report 1 wizard'
_columns = {
129/232
Catatan:
Wizard kita akan berisikan satu field, yaitu name (bertipe char). Kita akan gunakan ini sebagai
kriteria pencarian sebelum menghasilkan report.
Fungsi _get_data digunakan untuk mendapatkan input dari user, menggunakan method read.
Ingatlah bahwa kita berada dalam model buku.nop.report.1 ketika kita melakukan read. Dengan ids
yang kita lewatkan, kita akan mendapatkan anggota pertama dari list yang dikembalikan. Apabila
diperlukan, bacalah juga contoh fungsi read dalam Bab 4.
Yang sangat menarik adalah fungsi download_pdf. Nama ini bukan nama baku, dan diasosiasikan
dengan sebuah tombol di view.
Di dalam fungsi download_pdf, setelah mendapatkan informasi apa yang diinput oleh user, kita
lakukan pencarian:
data = self._get_data(cr, uid, ids, context=context)
domain = [('name', 'ilike', data.get('name'))]
search_result = self.pool.get('res.partner').search(cr, uid, domain)
130/232
Hasil pencarian, kita tempatkan pada sebuah dictionary dengan key adalah ids:
datas = {
'ids': search_result,
Dan, apa yang diinput oleh user bisa diakses dengan key form, sebagaimana kita lihat dalam file
RML:
'form': data,
}
Fungsi akan mengembalikan satu dictionary dengan key memiliki arti khusus. Sebagai contoh, key
datas dapat diakses dari dalam report sebagai variabel data.
'datas': datas,
<para
style="Standard">Nama
mengandung
{}).get('name') ]]<br/><br/></para>
teks:
[[
data.get('form',
Kita memberitahu OpenERP bahwa kita ingin menghasilkan report. Perhatikanlah key type berikut.
'type': 'ir.actions.report.xml',
'report_name': self._name,
Kita bisa menggunakan kursor koneksi database (variabel cr) untuk melakukan SQL Query,
langsung pada database.
131/232
dimana fungsi akan menjalankan fungsi download_pdf (name) ketika diklik (type object). Tombol
cancel merupakan tombol khusus:
<button string="Cancel" special="cancel"/>
132/232
133/232
LICENSE
MANIFEST.in
openerp
openerp.egg-info
openerp-server
PKG-INFO
README
setup.cfg
setup.nsi
setup.py
setup_rpm.sh
win32
import_xml.rng
__init__.py
loglevels.py
modules
netsvc.py
osv
PKG-INFO
pooler.py
release.py
report
service
sql_db.py
tests
tools
workflow
Perhatikanlah bahwa ini adalah package Python dan kita bisa menemukan apa yang kita seringkali
gunakan seperti package osv:
$ ls openerp/osv/
expression.py fields.py
__init__.py
orm.py
osv.py
query.py
Dengan demikian, apabila kita ingin tahu lebih lanjut tentang ORM misalnya, kita dapat membaca file
openerp/osv/orm.py.
Lebih lanjut, dalam mengembangkan modul OpenERP kita sendiri, kita umumnya bergantung pada
addon base. Mari kita perhatikan subdirektori openerp/addons:
$ ls openerp/addons/base
base_data.xml base.sql
i18n
module
134/232
res
static
currency_data.xml
data
__init__.py
ir
__openerp__.py
report
rng
security
test
tests
Apabila kita ingin mengetahui lebih banyak tentang model res.partner misalnya, kita dapat pula
membacanya dari file openerp/addons/base/res/res_partner.py.
Mempelajari source code program sebesar OpenERP tentu saja tidak mudah. Oleh karena itu, kita
umumnya harus fokus pada bagian tertentu dulu. Walaupun ini juga tidak mudah, kita selalu bisa
mencoba/memulai dari yang paling sederhana dulu. Begitu kita sudah lebih terbiasa, proses ini akan
terasa lebih cepat dan nyaman.
Selain dokumentasi yang dituliskan pada source code (termasuk komentar), seringkali kita bisa
terbantu dengan membaca isi fungsi.
135/232
LICENSE
MANIFEST.in
openerp
openerp.egg-info
openerp-server
PKG-INFO
README
setup.cfg
setup.nsi
setup.py
setup_rpm.sh
win32
[CTRL-C]
$ file ~/.openerp_serverrc
/home/c2/.openerp_serverrc: ASCII text
Padukanlah opsi -s dengan -c untuk menyimpan file konfigurasi yang dihasilkan pada file lain. Sebagai
contoh, kita ingin menghasilkan file konfigurasi dan menyimpannya pada file config.ini di direktori
aktif:
$ ./openerp-server -s -c config.ini
2014-08-11 19:54:54,445 4409 INFO ? openerp: OpenERP version 7.0-20140724-231255
[CTRL-C]
$ file config.ini
config.ini: ASCII text
Padukanlah lagi dengan opsi --stop-after-init agar program langsung keluar setelah menghasilkan file
konfigurasi.
$ ./openerp-server -s -c config.ini --stop-after-init
2014-08-11 19:58:22,589 4533 INFO ? openerp: OpenERP version 7.0-20140724-231255
136/232
LICENSE
MANIFEST.in
openerp
openerp.egg-info
openerp-server
PKG-INFO
README
setup.cfg
setup.nsi
setup.py
setup_rpm.sh
win32
dengan
dipisahkan
137/232
oleh
koma.
Sebagai
contoh
Bagi yang tertarik lebih lanjut dengan notati prefix secara umum (tidak spesifik OpenERP), kita bisa
pula mempergunakan pustaka notation, yang dikembangkan oleh Noprianto, salah satu anggota tim
penulis buku ini, dan dapat didownload dari https://github.com/nopri/notation. Pustaka ini hanya
berisikan satu file, yaitu notation.py. Pada saat buku ini ditulis, versi pustaka adalah 0.01.
138/232
Pustaka notation berisikan evaluator sederhana untuk notasi prefix dan postfix. Tersedia fungsi bantu
dan sebuah class yang dapat diturunkan.
Contoh sederhana menggunakan fungsi bantu untuk notasi prefix:
>>> import notation
>>> notation.simple_prefix_notation('+ 1 2')
3.0
>>> notation.simple_prefix_notation('* + 1 2 3')
9.0
>>> notation.simple_prefix_notation('- * + 1 2 3 4')
5.0
>>> notation.simple_prefix_notation('** - * + 1 2 3 4 5')
3125.0
>>> notation.simple_prefix_notation('/ ** - * + 1 2 3 4 5 6')
520.8333333333334
>>>
2 +')
2 + 3 *')
2 + 3 * 4 -')
2 + 3 * 4 - 5 **')
2 + 3 * 4 - 5 ** 6 /')
Apabila kita ingin mengurangi, menambahkan atau mengubah operator, kita bisa menurunkan dari
class SimplePrefixPostfixNotation. Pada contoh pertama, kita hanya mengenal operator +.
>>> import operator
>>> from notation import SimplePrefixPostfixNotation
>>>
>>> class LimitedPrefixPostfixNotation(SimplePrefixPostfixNotation):
...
def __init__(self, reverse=False):
...
self.OPERATORS = {'+': operator.add}
...
self.reverse = reverse
...
>>>
>>> o = LimitedPrefixPostfixNotation()
>>> print o.evaluate('+ 1 2')
3.0
>>> print o.evaluate('* + 1 2 3')
None
>>>
139/232
Dalam pustaka notation ini, evaluator diimplementasikan menggunakan stack, dimana list
dipergunakan sebagai stack. Untuk prefix, ekspresi akan diproses dari belakang.
Berikut adalah cuplikan fungsi evaluate0 class SimplePrefixPostfixNotation. Apabila reverse adalah
True, maka dimaksudkan adalah notasi postfix.
def evaluate0(self, expression):
stack = []
e = str(expression).split()
if not self.reverse:
e = e[-1::-1]
for i in e:
if i not in self.OPERATORS.keys():
n = float(i)
# ValueError
if not self.reverse:
stack.append(n)
else:
stack.insert(0, n)
else:
o1 = stack.pop() #IndexError
o2 = stack.pop() #IndexError
res = self.OPERATORS.get(i)(o1, o2)
if not self.reverse:
stack.append(res)
else:
stack.insert(0, res)
return stack
140/232
Constructor class:
def __init__(self, reverse=False):
self.OPERATORS = {
'+': operator.add,
'-': operator.sub,
'/': operator.truediv,
'*': operator.mul,
'%': operator.mod,
'**': operator.pow,
}
self.reverse = reverse
141/232
Ketika melakukan update module list, terdapat pesan kesalahan ValidateError sebagai berikut:
The value "GPL" for the field "ir_module_module.license" is not in the selection
Apabila kita ubah license menjadi sesuatu yang lain, misal Public Domain:
{
'name': 'Test',
'version': '1.0',
'license': 'Public Domain',
'author': 'noprianto',
'description': 'Test',
'category': 'Buku',
'website': 'https://github.com/id-python/buku-openerp',
'depends': ['base'],
}
dalam
'license': fields.selection([
('GPL-2', 'GPL Version 2'),
('GPL-2 or any later version', 'GPL-2 or later version'),
('GPL-3', 'GPL Version 3'),
('GPL-3 or any later version', 'GPL-3 or later version'),
('AGPL-3', 'Affero GPL-3'),
('Other OSI approved licence', 'Other OSI Approved Licence'),
142/232
file
Sehingga, salah satu pilihan yang bisa kita lakukan adalah mengubah string lisensi ke yang dikenal.
143/232
144/232
Contoh:
>>> from openerp.tools import DEFAULT_SERVER_DATE_FORMAT
>>> from openerp.tools import DEFAULT_SERVER_TIME_FORMAT
>>> from openerp.tools import DEFAULT_SERVER_DATETIME_FORMAT
>>>
>>> DEFAULT_SERVER_DATE_FORMAT
'%Y-%m-%d'
>>> DEFAULT_SERVER_TIME_FORMAT
'%H:%M:%S'
>>> DEFAULT_SERVER_DATETIME_FORMAT
'%Y-%m-%d %H:%M:%S'
>>>
>>> import time
>>> time.strftime(DEFAULT_SERVER_DATETIME_FORMAT)
'2014-08-15 19:03:20'
>>> time.strptime('2014-08-15', DEFAULT_SERVER_DATE_FORMAT)
time.struct_time(tm_year=2014, tm_mon=8, tm_mday=15, tm_hour=0, tm_min=0, tm_sec=0,
tm_wday=4, tm_yday=227, tm_isdst=-1)
>>>
145/232
146/232
147/232
148/232
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>
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}
149/232
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>
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)
151/232
OErpDb
Dari instance OErpClient, kita bisa pula bekerja dengan database:
>>> db = client.get_db()
>>> db
<oerpapi.OErpDb instance at 0xb710e46c>
Untuk tugas-tugas administratif, kita perlu menyediakan password admin, seperti yang ditentukan pada
konfigurasi server OpenERP:
>>> db.admin_password = 'myadminpassword'
152/232
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)
153/232
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)
154/232
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>
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.'>
>>>
155/232
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
156/232
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)
157/232
158/232
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:
159/232
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.
160/232
161/232
162/232
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'}]
>>>
163/232
164/232
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=''.
165/232
167/232
168/232
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()
169/232
170/232
raise Fault(**self._stack[0])
xmlrpclib.Fault: <Fault database "test9_copy" already exists
171/232
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)
172/232
173/232
/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.
>>>
>>>
>>>
>>>
>>>
3
>>>
db_name = 'test1'
user = 'demo'
password = 'demo'
uid = sock_common.login(db_name, user, password)
uid
/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)
174/232
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>
175/232
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']
>>>
/xmlrpc/report
Menggunakan service /xmlrpc/report, kita bisa bekerja dengan report. Untuk informasi selengkapnya,
bacalah dokumentasi API OpenERP.
176/232
Dokumen ini membahas dasar-dasar bahasa pemrograman Python, untuk versi 2.x.
Dokumen ini merupakan revisi ke 6, dimana pada awalnya, ditulis untuk Python versi 2.5, namun
telah sedikit disesuaikan untuk Python 2.7.
177/232
bisa
didapatkan
secara
bebas
dari
178/232
179/232
180/232
181/232
182/232
Detil
None
None Object
Number
Boolean (bool)
Set
pecahan
Complex (complex)
bilangan kompleks
Integer (int)
Catatan
183/232
Unordered
Semua item
dalam set
harus
immutable
Dapat dibuat
dari item
Detil
Catatan
Sequence
String (str)
immutable
immutable
184/232
iterable
Unik
Dapat
dioperasikan
sebagai
himpunan
Memiliki
sifat iterable
Detil
Tuple (tuple)
immutable
List (list)
mutable
Lihat range()
185/232
Catatan
Detil
Catatan
reverse, sort.
Mapping
File
Xrange (xrange)
immutable
Dictionary (dict)
Unordered
(lihatlah juga
pembahasan
Collection)
File (file)
Collection
Sebagai alternatif dari container built-in seperti dict, list, set dan tuple, terdapat pula berbagai
186/232
Operator
Perbandingan boolean
<, lebih kecil
<=, lebih kecil sama dengan
>, lebih besar
>=, lebih besar sama dengan
==, sama dengan
!=, tidak sama dengan
Operator Logical
not, logical negasi
and, logical and
or, logical or
Operator aritmatika
*, perkalian
/, pembagian
//, pembagian integer
%, sisa bagi
+, penjumlahan
187/232
188/232
Lain-lain:
Beberapa fungsi:
type(object): mengembalikan tipe object
id(object): mengembalikan alamat memori object
ininstance(object, class-or-type-or-tuple): mengembalikan apakah object merupakan instance
dari class.
Kategori tipe juga mencakup Callable (dapat dipanggil), Modules (setelah diimport), Classes dan
Type.
189/232
10.6 Kondisi
Sintaks if
if <expression>:
<statement>
<statement>
..
[elif <expression>:
<statement>
<statement>
..
]
[else:
<statement>
<statement>
..
]
Contoh if:
>>> a=10
>>> if a > 5:
...
...
a besar dari 5
Catatan:
190/232
191/232
10.7 Perulangan
Sintaks for
for <target_list> in <expression_list>:
<statement>
<statement>
...
[else:
<statement>
<statement>
..
]
Contoh for:
>>> for i in range(1,10,2):
...
print i
...
1
3
5
7
9
Sintaks while
while <expression>:
<statement>
192/232
Contoh while:
>>> a=1
>>> while a<5:
...
print a
...
a += 1
...
1
2
3
4
Catatan
pass dapat digunakan untuk blok kosong.
Statement break digunakan untuk keluar dari perulangan.
Statement continue digunakan untuk melanjutkan ke iterasi berikutnya.
Statement pada blok else akan dikerjakan apabila perulangan selesai, namun tidak oleh statement
break.
193/232
10.8 Fungsi
Deklarasi fungsi
def <func_name>([parameter_list]):
<statement>
<statement>
...
[return <return_value>]
Catatan:
ketika return tidak didefinisikan, None akan dikembalikan
def test():
...
...
print 'test'
...
Untuk mengetahui docstring fungsi test, akseslah atribut __doc__ dari fungsi test. Contoh:
>>> test.__doc__
194/232
Docstring yang didefinisikan juga berguna dalam penggunaan bersama fungsi help() di sesi interactive:
>>> help(test)
Help on function test in module __main__:
test()
docstring fungsi test
Pemanggilan fungsi
Pemanggilan fungsi harus melihatkan penggunaan (), sesuai argumen fungsi. Tanpa (), python tidak
akan menganggap sintaks tersebut sebagai sintaks yang salah, tetapi tidak akan dikerjakan.
Variabel global
Setiap fungsi akan memiliki variabel lokal sendiri. Namun, ada kalanya, akses ke variabel global
diperlukan.
195/232
Contoh berikut dimaksudkan untuk mengubah variabel global x menjadi 20, namun tidak bekerja:
>>> x=10
>>> def testx():
...
x=20
...
print x
...
>>> x
10
>>> testx()
20
>>> x
10
>>>
global x
...
x=20
...
print x
...
>>> x
10
196/232
Walau demikian, untuk sekedar mereferensi ke variabel global, keyword global tidak diperlukan.
Argumen fungsi
Argumen fungsi bisa diberikan, tanpa harus menyebutkan tipe data. Apabila lebih dari 1 argumen,
maka deretkanlah dengan dipisahkan oleh koma. Pemanggilan fungsi selanjutnya harus disesuaikan
dengan argumen yang didefinisikan, kecuali default argument digunakan (lihat pembahasan
berikutnya).
Contoh 1:
>>> def kuadrat(x):
...
return x*x
...
>>> hasil=kuadrat(12)
>>> print hasil
144
Contoh 2:
>>> def kali(a,b):
...
return a*b
...
>>> hasil=kali(2,4)
197/232
Argumen juga bisa dipanggil dengan menyebutkan nama (keyword) pada parameter formal, sehingga
dapat dipanggil dengan urutan yang tidak sesuai dengan saat deklarasi. Contoh:
...
>>> kali2(b=20, a=10)
(10 x 20) = 200
>>>
Ketika menggunakan keyword argument, pastikan kesalahan-kesalahan seperti berikut tidak dilakukan:
non-keyword argument diberikan keyword argument
duplikasi argumen
salah memberikan keyword
Argumen default
Argumen default memungkinkan pengguna fungsi untuk memanggil fungsi dengan argumen yang lebih
sedikit/sederhana dalam kondisi normal, namun memiliki keleluasaan untuk memanggil fungsi dengan
semua argumen diberikan.
Argumen default digunakan apabila sebuah argumen memiliki nilai tertentu yang umum (digunakan
oleh pemanggil fungsi), namun tetap dimungkinkan untuk diberikan nilai lain.
198/232
Sebagai contoh, kita mendefinisikan sebuah fungsi cetak_nama, dengan dua argumen:
name: nama yang akan dicetak
prefix: prefix pencetakan
Dalam kondisi normal, fungsi akan selalu mencetak tulisan 'Nama Anda adalah ' (prefix) diikuti oleh
name yang diberikan. Apabila prefix ingin diganti, pengguna fungsi tetap dapat melakukannya.
...
>>> cetak_nama('piton')
Nama Anda adalah piton
>>> cetak_nama('piton','Nama=')
Nama=piton
for i in t:
...
print i
...
>>> testt(1,2,3,4,5)
1
199/232
Dengan cara seperti ini, jumlah argumen tidak didefinisikan secara kaku.
keys = arg.keys()
...
for k in keys:
...
...
200/232
Dengan cara seperti ini, argumen tidak didefinisikan secara kaku. Catatan mulai versi 2.6: pada saat
pemanggilan fungsi dengan sintaks **, mapping lain bisa dipergunakan (tidak harus dictionary).
201/232
10.9 Class
Berikut adalah sintaks class:
Catatan:
Dideklarasikan dengan keyword class
Class mendukung docstring seperti halnya fungsi
Setiap definisi method class akan menggunakan keyword self sebagai argumen pertama method,
yang dapat digunakan untuk merujuk ke diri sendiri (object).
Untuk merujuk ke anggota dalam class, gunakanlah kata kunci self.
Constructor class adalah method dengan nama __init__.
Python mendukung multiple inheritance
Python menggunakan name mangling untuk identifier yang diawali oleh paling tidak dua
underscore dan diakhiri paling banyak satu underscore. Name mangling tersebut dapat digunakan
sebagai 'private variable'.
Mengenal dua tipe class: old-style (classic) dan new-style (diperkenalkan sejak Python versi 2.2).
Default adalah old-style pada python 2.x. Untuk membuat class new-style, gunakan base class
berupa class new-style atau object (apabila base class tidak diperlukan).
Instansiasi menggunakan notasi fungsi. Argumen dilewatkan pada method __init__.
Terdapat berbagai nama method spesial, yang diantaranya dapat dilakukan untuk kustomisasi,
emulasi, koersi, context manager with (versi 2.5 ke atas), dan lainnya. Ini merupakan pendekatan
yang dilakukan oleh Python untuk operator overloading.
202/232
pass
...
>>> c1 = MyClass1()
>>> type(c1)
<type 'instance'>
>>> c1
<__main__.MyClass1 instance at 0xb7bf1fcc>
'keterangan MyClass2'
...
...
print 'Inisialisasi...'
...
print x
...
>>> c2 = MyClass2(10)
Inisialisasi...
10
>>> c2.__doc__
'keterangan MyClass2'
>>>
203/232
...
def method2(self):
...
self.method1()
...
>>> c3 = MyClass3(5)
>>> c3.x
5
>>> c3.method1()
---->>> c3.x = 10
>>> c3.method1()
--------->>> c3.method2()
--------->>>
def method1(self):
...
print 'base....'
204/232
def method2(self):
...
print 'derived1...'
...
>>> class Derived2(Base):
...
def method1(self):
...
...
...
print 'derived2...'
...
>>> c4 = Derived1()
>>> c4.method1()
base....
>>> c4.method2()
derived1...
>>>
>>> c5 = Derived2()
>>> c5.method1()
method1 of derived2...
>>> c5.method2()
derived2...
>>>
Catatan: pada class new-style, super() bisa digunakan untuk merefer ke class parent. Lihatlah juga
contoh 8.
205/232
...
def method1(self):
...
print self.__x
...
>>> c6 = Mangling(10)
>>> c6.__x
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: Mangling instance has no attribute '__x'
>>> c6.method1()
10
>>> c6.__x=20
>>> c6.method1()
10
>>>
pass
...
>>> c7 = Struct1()
>>> c7.name = 'test'
206/232
def __init__(self):
print 'Inisialisasi (Base)...'
...
>>>
>>> class Derived1(Base):
...
...
def __init__(self):
print 'Inisialisasi (Derived1)...'
...
>>> class Derived2(Base):
...
def __init__(self):
...
Base.__init__(self)
...
...
>>> d1 = Derived1()
Inisialisasi (Derived1)...
>>> d2 = Derived2()
Inisialisasi (Base)...
207/232
def __init__(self):
print 'Inisialisasi (Base)...'
...
>>> class Derived1(Base):
...
...
def __init__(self):
print 'Inisialisasi (Derived1)...'
...
>>> class Derived2(Base):
...
def __init__(self):
...
super(Derived2, self).__init__()
...
...
>>> d1 = Derived1()
Inisialisasi (Derived1)...
>>> d2 = Derived2()
Inisialisasi (Base)...
Inisialisasi (Derived2)...
208/232
...
...
return self.x + y
...
>>> o1 = Overload1(10)
>>> o1 + 5
15
>>>
...
...
return self.x - y
...
...
return self.x * y
...
>>> o2 = Overload2(10)
>>> o2 - 5
5
>>> o2 * 10
100
>>>
209/232
...
>>>
>>> a = 'halo apa kabar'
>>> a * 2
'halo apa kabarhalo apa kabar'
>>> a - 'a'
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unsupported operand type(s) for -: 'str' and 'str'
>>>
>>>
>>> s = MyStr('halo apa kabar')
>>> s * 2
'halo apa kabarhalo apa kabar'
>>> s - 'a'
'hlo p kbr'
>>>
210/232
211/232
10.10 Modul-modul
Python datang dengan sangat baik modul siap pakai. Pengguna juga dapat menginstall modul tambahan
dari pihak ketiga, ataupun menggunakan modul yang dibuat sendiri. Modul-modul bisa pula
dikelompokkan menjadi package.
Modul dapat digunakan setelah diimport. Contoh penggunaan modul os untuk mendapatkan nama os:
>>> import os
>>> os.name
'posix'
Nama yang lebih pendek bisa digunakan, dengan import <module> as <alias>, sebagai contoh:
>>> import platform as p
>>> p.uname()
('Linux', 'nop1', '2.6.21.5-smp', '#2 SMP Tue Jun 19 14:58:11 CDT 2007', 'i686', 'Intel(R) Celeron(R)
CPU 2.50GHz')
>>>
212/232
Contoh modul
Beberapa contoh modul:
time : bekerja dengan waktu, contoh:
Epoch = waktu dimulai (1 Januari 1970, pukul 00:00)
Dapatkan detik sejak epoch:
time.time()
1228025944.210458
Informasi detil waktu sejak epoch (GMT):
time.gmtime(-100000000)
(1966, 10, 31, 14, 13, 20, 0, 304, 0)
time.gmtime(0)
(1970, 1, 1, 0, 0, 0, 3, 1, 0)
time.gmtime()
(2008, 11, 30, 6, 19, 48, 6, 335, 0)
Informasi detil waktu sejak epoch (lokal):
time.localtime()
(2008, 11, 30, 15, 43, 36, 6, 335, 0)
Parse time dari string (format bisa baca referensi modul time)
time.strptime('2008-11-12', '%Y-%m-%d')
(2008, 11, 12, 0, 0, 0, 2, 317, -1)
Mengembalikan string time dari detik sejak epoch (lokal):
time.ctime(1000)
'Thu Jan 1 07:16:40 1970'
Mengembalikan string time dari sequence time (lokal):
time.asctime((2008,10,11,23,11,22,0,0,0))
213/232
215/232
Search path
Ketika suatu modul diimport, Python akan mencari ke:
direktori aktif
daftar direktori pada variabel PYTHONPATH
default path, lokasi instalasi python
Mulai versi 2.6, per-user site-packages didukung. Untuk informasi selengkapnya, bacalah juga
environment variable PYTHONUSERBASE dan PYTHONNOUSERSITE.
Compiled module
Ketika suatu modul berhasil diimport, versi byte-compiled modul (file bernama sama dengan modul,
namun dengan ekstensi .pyc/.pyo) akan coba dibuat. File byte-compiled tersebut dapat diload lebih
cepat.
Mulai versi 2.6, pembuatan .pyc/.pyo bisa dicegah dengan switch -B, atau environment variabel
PYTHONDONTWRITEBYTECODE.
Nama module
Setiap modul python memiliki nama masing-masing, yang dapat diakses dari properti __name__.
Contoh:
>>> import os
>>> os.__name__
216/232
Sebuah nama spesial __main__ akan didefinisikan apabila modul dijalankan standalone. Dengan
memeriksa apakah __name__ == '__main__', kita bisa memeriksa apakah modul diimport atau
dijalankan standalone.
Contoh:
$ cat module1.py
#!/usr/bin/env python
if __name__ == '__main__':
print 'Dijalankan standalone'
else:
print 'Diimport'
$ python module1.py
Dijalankan standalone
Package
Modul-modul dapat dikelompokkan menjadi package. Berikut adalah beberapa catatan tentang
pembuatan package:
217/232
Sebuah package terdiri dari sebuah direktori di file system. Secara opsional, direktori tersebut dapat
pula berisikan subdirektori-subdirektori.
Sebuah file spesial, __init__.py harus ada di dalam direktori agar direktori tersebut dianggap
sebagai package. File tersebut bisa saja berupa file kosong, atau dapat berisikan inisialisasi.
Sebuah variabel spesial __all__ (opsional; bertipe list) dapat ditentukan di dalam __init__.py, yang
pada akhirnya akan menentukan apa yang tersedia ketika package diimport dengan: from package
import *.
Contoh package1
package1
package1/__init__.py
package1/module2.py
package1/module1.py
218/232
>>> dir()
['__builtins__', '__doc__', '__name__', '__package__']
>>> from package2 import *
>>> dir()
['__builtins__', '__doc__', '__name__', '__package__', 'module1']
>>> module1.function1()
function 1
>>>
219/232
10.11 Exception
Kerjakan apa yang ingin dikerjakan, dan apabila terjadi kesalahan, kita siapkan handlernya.
Try...except...finally
Sintaks try...except...finally:
try:
<statement>
<statement>
...
except [expression [, target]]:
<statement>
<statement>
...
[else:
<statement>
<statement>
]
[finally:
<statement>
<statement>
]
Alur kerja:
Statement diantara try dan except akan dikerjakan
220/232
Catatan:
Klausa else akan dikerjakan, apabila diberikan, dan tidak ada kesalahan yang terjadi. Berguna untuk
perintah yang akan dikerjakan apabila exception tidak terjadi.
try...except...finally berlaku mulai Python v2.5. Sebelumnya, try..except harus ditempatkan
bersarang di try...finally
Untuk menangani lebih dari satu exception pada satu waktu, deretkanlah ke dalam satu tuple (versi
2.6 ke atas).
1/0
...
Kesalahan: pembagian dengan nol
221/232
1/1
... else:
...
...
1
Tidak ada kesalahan yang terjadi
1/1
... else:
...
... finally:
...
...
1
Tidak ada kesalahan yang terjadi
Pembagian selesai
222/232
Try...finally
Sintaks try...finally
try:
<statement>
<statement>
...
finally:
<statement>
<statement>
...
Catatan:
try...finally berguna sebagai cleanup action, apapun kondisi yang terjadi.
Informasi exception
Apabila exception terjadi, informasi tertentu mungkin akan tersedia, sesuai dengan jenis exceptionnya.
Untuk mendapatkan, lewatkan argumen pada exception, seperti contoh berikut.
>>> try:
...
1/0
...
Kesalahan: integer division or modulo by zero
223/232
Catatan:
Kita dapat pula mengakses atribut message apabila dibutuhkan. Contoh:
>>> try:
...
1/0
...
Kesalahan: integer division or modulo by zero
Membangkitkan exception
Untuk membangkitkan kesalahan tertentu, gunakanlah raise. Argumen opsional bisa diberikan.
224/232
10.12 File
Operasi file umumnya melibatkan pembukaan file, melakukan operasi tertentu, dan kemudian menutup
file terbuka tersebut.
Catatan:
path adalah path file yang ingin dibuka
mode dapat bernilai:
r: membuka file untuk dibaca
w: membuka file untuk ditulis. Apabila file yang ingin dibuka telah terdapat di filesystem,
maka isinya akan dihapus. Apabila file tidak ditemukan, maka akan dibuat secara otomatis.
a: membuka file untuk diupdate. Isi file yang sudah ada tidak dihapus.
r+: membuka file untuk dibaca dan ditulis. Isi file yang sudah ada tidak dihapus.
W+: membuka file untuk ditulis dan dibaca. Isi file yang sudah ada akan dihapus.
a+: membuka file untuk dibaca dan ditulis. Isi file yang sudah ada tidak dihapus.
b: apabila ditambahkan ke salah satu dari r, w, atau a, maka akan membuka file dalam modus
binary.
U: apabila ditambahkan ke salah satu dari r, w atau a, maka akan mengaplikasikan universal
newline. Newline pada setiap platform bisa berbeda-beda. Contoh: Linux menggunakan \n,
Windows menggunakan \r\n.
buffersize: ukuran buffer
225/232
Contoh:
>>> f = open('/etc/hosts')
>>> f
<open file '/etc/hosts', mode 'r' at 0xb7bf54e8>
>>> f.close()
>>> f
<closed file '/etc/hosts', mode 'r' at 0xb7bf54e8>
>>>
>>> f = open('/tmp/abc')
>>> isi = f.readlines()
>>> f.close()
>>> isi
['test baris 1\n', 'test baris 2\n', 'test baris 3\n']
>>>
Membaca sekaligus isi file dengan method read(). Hasil pembacaan akan disimpan di string.
>>> f = open('/tmp/abc')
226/232
>>> f = open('/tmp/abc')
>>> while True:
...
baris = f.readline()
...
if not baris:
...
break
...
print baris
...
test baris 1
test baris 2
test baris 3
>>> f.close()
>>>
227/232
>>> linecache.clearcache()
>>> f = open('/tmp/abc')
>>> buf3 = f.read(3)
>>> print buf3
tes
>>> f.close()
>>>
Menulis ke file
Untuk menulis ke file yang telah dibuka, beberapa cara bisa digunakan:
Menulis string dengan method write.
>>> f = open('/tmp/test','w')
>>> f.write('halo apa kabar')
>>> f.close()
>>>
>>> print open('/tmp/test').readlines()
['halo apa kabar']
Statement with
Pada python versi 2.5, statement with diperkenalkan sebagai fitur opsional, dimana untuk
menggunakannya, kita melakukan:
Statement ini dapat digunakan untuk memastikan kode untuk melakukan clean-up akan dikerjakan,
seperti halnya pada try/finally. Dan, ini berlaku untuk object yang mendukung context management
protocol.
Contoh yang mendukung adalah file. Dengan demikian, kita bisa bekerja dengan file dengan cara
berikut:
229/232
for line in f:
...
print line
...
230/232