API 接口?
使用Web服務(Working with Web Services)?
鑑於OpenERP的架構,它不適合直接通過PostgreSQL客戶端或者 ODBC 這樣的連接方法訪問數據庫, 幸運的是,OpenERP提供了一個非常全面的web服務集,允許你通過標準協議做任何事情。
Note
雖然直接訪問數據庫,在技術上是可行的,你必須意識到這可能對您的數據造成災難性的後果,除非你知道你是在做 什麼。當你直接訪問數據庫的時候,建議您關閉OpenERP服務器,以避免緩存和併發問題。
支持的網絡服務協議(Supported Web Services Protocols)?
目前支持的協議是XML-RPC和Net-RPC。XML-RPC是用於Web服務的第一批標準之一, 幾乎可以再任何語言中使用。這是一個非常詳細的協議,而且在需要的時候可以引入潛在位。 另一方面,Net-RPC是一個優化的協議,特別用在Python編寫的應用程序之間。.
對於REST風格的web服務的支持在將來的OpenErp發佈包中支持。
對於SOAP協議,目前的OPenErp已經不再支持,但是如果在社區有足夠的愛好者的話將來可能恢復。
可用的Web服務(Available Web Services)?
OpenERP 爲你提供了以下的Web服務.
Note
你能在服務的源碼(/bin/service/web_services.py)的對應類裏面找到每種服務的細節 .
db:
提供函數創建、刪除、備份、恢復數據庫. 請謹慎使用!
common:
讓你登錄和退出 OpenERP, 並且提供各種實用功能。你只有登錄後才能使用其他的網絡服務.
object:
這是最有用的網絡服務,因爲通過它可以訪問 OpenERP 對象. 值得注意的是, 函數 “execute” 讓你調用對象的方法, 比如可以搜索的大部分的ORM方法,讀寫記錄。它也可以用來調用價格計算等對象的其他方法.
Note
主要的 ORM 方法一覽:
- create({‘field’:’value’})
創建一個具有指定值的新紀錄
Returns: 新紀錄的ID
- search([(‘arg1’,’=’,’value1’)...], offset=0, limit=1000)
arg1, arg2, .. ,argN: 指定列表的搜索條件
offset: 跳過的可選的記錄
limit: 返回的最大數量的記錄
Returns: 匹配給定條件的記錄
- read([IDS], [‘field1’,’field2’,...])
fields: 返回的字段名字(默認全部返回) (default: all fields)
Returns: 每條記錄的ID和請求字段的值
- write([IDS], {‘field1’:’value1’,’field2’:3})
values: 更新的字段的值
Updates 對給定的記錄按照給定的值進行更新
Returns: True
- unlink([IDS])
按照給定的IDS刪除記錄
Returns: True
通過 Web 服務不能使用 Browse() 函數.
另一個有用的功能是 “exec_workflow”, 它可以讓你通過工作流制定記錄的進展.
嚮導:
提供對舊式的嚮導。新風格的嚮導是基於ORM的,因此他們可以通過 “object” web 服務來進行訪問.
報告:
讓你生成和檢索報告.
例子:通過Web服務寫入數據(Example:writing data through the Web Service)?
下面是一個寫數據的例子程序。在下一章你會發現關於多種編程語言 XML-RPC的更詳盡的例子.
login: 在Web服務 “common” 中調用 “login” 函數,使用下面的參數:
database
user name
password
創建一個新的合作者: 在Web服務 “object” 中調用 “execute” 函數,使用下面的參數:
database
user id provided by “login” in step 1.
the object name : ‘res.partner’
the name of the ORM method : “create”
some data to be recorded
上面提到的數據都是鍵值對, 比如:
name: Fabien Pinckaers
lang: fr_FR
但是更復雜的數據結構也可以發送。比如你可以在一個單一的Web服務調用中創建一個合作者 和他的地址。在那種情況下,所有的數據在服務的相同的數據庫事務中來處理。這意味. 着你一定要保存好你的數據一致性的狀態。這是對所有ERP應用的關鍵要求.
XML-RPC Web服務(XML-RPC Web Services)?
XML-RPC 是一個著名的Web服務. Web 服務是一個工具,它可以再現有的網絡基礎設施上面設置分佈式的應用程序。這些應用程序使用一種傳輸層的網絡但是並不提供直接通過瀏覽器的人機界面。可擴展標記語言(XML)提供了描述遠程過程調用(RPC)的詞彙表,RPC是使用超文本傳輸協議(HTTP) 在計算機之間傳輸。實際上,RPC讓各開發者自行定義網絡調用中的接口。這些接口可以是很簡單的一個函數調用也可以像大型API那樣複雜.
XML-RPC 允許在兩臺或者更多運行不同操作系統和不同語言程序的計算機之間協同處理。比如,一個JAVA應用可以和一個Perl應用會談,一個Perl應用可以同一個同ASP會談的PYTHON應用會談,等等。系統集成商往往在不同系統之間建立自己的連接,創建它們自己定義的格式的協議來進行通信,但是這造成了大量的不常使用的協議。RPC方法的程序員無需瞭解底層的協議、網絡以及各種實施細則.
XML-RPC 可以同 Python, Java, Perl, PHP, C, C++, Ruby, Microsoft’s .NET 以及許多其他的編程語言來一起使用。它的實現被廣泛用於 Unix, Linux, Windows 和 Macintosh 的平臺.
一個 XML-RPC 調用實在雙方之間進行的,客戶端(調用程序)和服務器(被調用過程)。服務時提供在一個特定的URL上的,比如 (such as http://example.org:8080/rpcserv/).
上面我們只是接觸了 XML-RPC 的表面. 我推薦 O’Reilly’s “Programming Web Service with XML-RPC” 進行進一步的學習。還可以閱讀以下幾個環節:
接口(InterFaces)?
XML-RPC?
XML-RPC 架構?
OpenERP 基於C/S體系結構。服務器和客戶端之間的通信使用XML-RPC協議。XML-RPC是一個非常簡單的協議,它允許客戶端進行遠程過程調用。被調用的函數,它的參數,調用結果通過XML編碼並且使用HTTP進行傳輸。欲瞭解更多的關於XML-RPC的詳盡信息,請參閱: http://www.xml-rpc.com.
架構(Architecture)?
下面的圖標綜合了OpenERP的客戶端和服務器結構。OpenERP的服務器和客戶端通信使用 XML-RPC.
客戶端
OpenERP 的邏輯是在服務器端配置的。客戶端是很簡單的,它是僅用於POST的數據(forms, lists, trees)並且把結果發回服務器。新功能的更新和加入並不需要客戶端的升級,這使得OpenERP更容易維護.
客戶端並不明白POST的內容。即使像點擊打印圖標的行動時發送到服務器並且詢問如何作出反應.
客戶端的操作時很簡單的,當客戶發出一個動作(保存一個表格、打開一個目錄、打印…)它發送動作到服務器。然後服務器執行客戶端的請求並將結果發送回來.
下面是三種行爲;
Open a window (form or tree)
Print a document
Execute a wizard
Python?
通過 xml-rpc 獲取數據?
代碼示例?
創建一個合作伙伴和他的地址
import xmlrpclib username = 'admin' # OpenERP 登陸用戶 pwd = 'admin' # 登陸密碼 dbname = 'terp' # OpenERP 帳套 # Get the uid sock_common = xmlrpclib.ServerProxy ('http://localhost:8069/xmlrpc/common') uid = sock_common.login(dbname, username, pwd) #replace localhost with the address of the server sock = xmlrpclib.ServerProxy('http://localhost:8069/xmlrpc/object') partner = { 'name': 'Fabien Pinckaers', 'lang': 'fr_FR', } partner_id = sock.execute(dbname, uid, pwd, 'res.partner', 'create', partner) address = { 'partner_id': partner_id, 'type' : 'default', 'street': 'Chaussée de Namur 40', 'zip': '1367', 'city': 'Grand-Rosière', 'phone': '+3281813700', 'fax': '+3281733501', } address_id = sock.execute(dbname, uid, pwd, 'res.partner.address', 'create', address)
查詢業務夥伴
args = [('vat', '=', 'ZZZZZZ')] # 查詢過濾條件 ids = sock.execute(dbname, uid, pwd, 'res.partner', 'search', args)
讀取業務夥伴數據
fields = ['name', 'active', 'vat', 'ref'] # 需要讀取的數據字段 data = sock.execute(dbname, uid, pwd, 'res.partner', 'read', ids, fields) #ids is a list of id
更新業務夥伴數據
values = {'vat': 'ZZ1ZZZ'} # 待更新數據Dictionary result = sock.execute(dbname, uid, pwd, 'res.partner', 'write', ids, values)
刪除業務夥伴
# ids : 待刪除業務夥伴id列表 result = sock.execute(dbname, uid, pwd, 'res.partner', 'unlink', ids)
PHP?
通過 xml-rpc 獲取數據?
下載 XML-RPC PHP Library
windows / linux: 從 http://phpxmlrpc.sourceforge.net/ 上下載xmlrpc框架,目前最新的正式版本是2007年2月25日發行的2.2版本
配置 PHP XML-RPC Library
從xmlrpc-2.2.tar.gz 解壓出xmlrpc.inc 文件,把這個文件放到php函數庫文件夾中,重啓apache/iis 服務器
代碼示例
登陸OpenERP
function connect() { var $user = 'admin'; var $password = 'admin'; var $dbname = 'db_name'; var $server_url = 'http://localhost:8069/xmlrpc/'; if(isset($_COOKIE["user_id"]) == true) { if($_COOKIE["user_id"]>0) { return $_COOKIE["user_id"]; } } $sock = new xmlrpc_client($server_url.'common'); $msg = new xmlrpcmsg('login'); $msg->addParam(new xmlrpcval($dbname, "string")); $msg->addParam(new xmlrpcval($user, "string")); $msg->addParam(new xmlrpcval($password, "string")); $resp = $sock->send($msg); $val = $resp->value(); $id = $val->scalarval(); setcookie("user_id",$id,time()+3600); if($id > 0) { return $id; }else{ return -1; } }
查詢業務夥伴
/** * $client = xml-rpc handler * $relation = name of the relation ex: res.partner * $attribute = name of the attribute ex:code * $operator = search term operator ex: ilike, =, != * $key=search for */ function search($client,$relation,$attribute,$operator,$keys) { var $user = 'admin'; var $password = 'admin'; var $userId = -1; var $dbname = 'db_name'; var $server_url = 'http://localhost:8069/xmlrpc/'; $key = array(new xmlrpcval(array(new xmlrpcval($attribute , "string"), new xmlrpcval($operator,"string"), new xmlrpcval($keys,"string")),"array"), ); if($userId<=0) { connect(); } $msg = new xmlrpcmsg('execute'); $msg->addParam(new xmlrpcval($dbname, "string")); $msg->addParam(new xmlrpcval($userId, "int")); $msg->addParam(new xmlrpcval($password, "string")); $msg->addParam(new xmlrpcval($relation, "string")); $msg->addParam(new xmlrpcval("search", "string")); $msg->addParam(new xmlrpcval($key, "array")); $resp = $client->send($msg); $val = $resp->value(); $ids = $val->scalarval(); return $ids; }
創建業務夥伴
<? include('xmlrpc.inc'); $arrayVal = array( 'name'=>new xmlrpcval('Fabien Pinckaers', "string") , 'vat'=>new xmlrpcval('BE477472701' , "string") ); $client = new xmlrpc_client("http://localhost:8069/xmlrpc/object"); $msg = new xmlrpcmsg('execute'); $msg->addParam(new xmlrpcval("dbname", "string")); $msg->addParam(new xmlrpcval("3", "int")); $msg->addParam(new xmlrpcval("demo", "string")); $msg->addParam(new xmlrpcval("res.partner", "string")); $msg->addParam(new xmlrpcval("create", "string")); $msg->addParam(new xmlrpcval($arrayVal, "struct")); $resp = $client->send($msg); if ($resp->faultCode()) echo 'Error: '.$resp->faultString(); else echo 'Partner '.$resp->value()->scalarval().' created !'; ?>
更新業務夥伴數據
/** * $client = xml-rpc handler * $relation = name of the relation ex: res.partner * $attribute = name of the attribute ex:code * $operator = search term operator ex: ilike, =, != * $id = id of the record to be updated * $data = data to be updated */ function write($client,$relation,$attribute,$operator,$data,$id) { var $user = 'admin'; var $password = 'admin'; var $userId = -1; var $dbname = 'db_name'; var $server_url = 'http://localhost:8069/xmlrpc/'; $id_val = array(); $id_val[0] = new xmlrpcval($id, "int"); if($userId<=0) { connect(); } $msg = new xmlrpcmsg('execute'); $msg->addParam(new xmlrpcval($dbname, "string")); $msg->addParam(new xmlrpcval($userId, "int")); $msg->addParam(new xmlrpcval($password, "string")); $msg->addParam(new xmlrpcval($relation, "string")); $msg->addParam(new xmlrpcval("write", "string")); $msg->addParam(new xmlrpcval($id, "array")); $msg->addParam(new xmlrpcval($data, "struct")); $resp = $client->send($msg); $val = $resp->value(); $record = $val->scalarval(); return $record; }
JAVA?
通過 xml-rpc 獲取數據?
下載 JAVA XML-RPC Library
從 http://ws.apache.org/xmlrpc/ 上下載java xmlrpc框架,目前最新版本是2007年8月發佈的3.1版本. All OpenERP errors throw exceptions because the framework allows only an int as the error code where OpenERP returns a string.
代碼示例
獲取OpenERP帳套列表
import java.net.URL; import java.util.Vector; import org.apache.commons.lang.StringUtils; import org.apache.xmlrpc.XmlRpcException; import org.apache.xmlrpc.client.XmlRpcClient; import org.apache.xmlrpc.client.XmlRpcClientConfigImpl; public Vector<String> getDatabaseList(String host, int port) { XmlRpcClient xmlrpcDb = new XmlRpcClient(); XmlRpcClientConfigImpl xmlrpcConfigDb = new XmlRpcClientConfigImpl(); xmlrpcConfigDb.setEnabledForExtensions(true); xmlrpcConfigDb.setServerURL(new URL("http",host,port,"/xmlrpc/db")); xmlrpcDb.setConfig(xmlrpcConfigDb); try { //Retrieve databases Vector<Object> params = new Vector<Object>(); Object result = xmlrpcDb.execute("list", params); Object[] a = (Object[]) result; Vector<String> res = new Vector<String>(); for (int i = 0; i < a.length; i++) { if (a[i] instanceof String) { res.addElement((String)a[i]); } } catch (XmlRpcException e) { logger.warn("XmlException Error while retrieving OpenERP Databases: ",e); return -2; } catch (Exception e) { logger.warn("Error while retrieving OpenERP Databases: ",e); return -3; } }
登陸
import java.net.URL; import org.apache.commons.lang.StringUtils; import org.apache.xmlrpc.XmlRpcException; import org.apache.xmlrpc.client.XmlRpcClient; import org.apache.xmlrpc.client.XmlRpcClientConfigImpl; public int Connect(String host, int port, String tinydb, String login, String password) { XmlRpcClient xmlrpcLogin = new XmlRpcClient(); XmlRpcClientConfigImpl xmlrpcConfigLogin = new XmlRpcClientConfigImpl(); xmlrpcConfigLogin.setEnabledForExtensions(true); xmlrpcConfigLogin.setServerURL(new URL("http",host,port,"/xmlrpc/common")); xmlrpcLogin.setConfig(xmlrpcConfigLogin); try { //Connect params = new Object[] {tinydb,login,password}; Object id = xmlrpcLogin.execute("login", params); if (id instanceof Integer) return (Integer)id; return -1; } catch (XmlRpcException e) { logger.warn("XmlException Error while logging to OpenERP: ",e); return -2; } catch (Exception e) { logger.warn("Error while logging to OpenERP: ",e); return -3; } }
查詢業務夥伴
TODO
創建業務夥伴
TODO
更新業務夥伴
TODO
Python 代碼示例?
創建合作伙伴和他們的地址的例子.
import xmlrpclib sock = xmlrpclib.ServerProxy('http://localhost:8069/xmlrpc/object') uid = 1 pwd = 'demo' partner = { 'title': 'Monsieur', 'name': 'Fabien Pinckaers', 'lang': 'fr', 'active': True, } partner_id = sock.execute(dbname, uid, pwd, 'res.partner', 'create', partner) address = { 'partner_id': partner_id, 'type': 'default', 'street': 'Rue du vieux chateau, 21', 'zip': '1457', 'city': 'Walhain', 'phone': '(+32)10.68.94.39', 'fax': '(+32)10.68.94.39', } sock.execute(dbname, uid, pwd, 'res.partner.address', 'create', address)
用下面的腳本來獲得用戶的 UID :
sock = xmlrpclib.ServerProxy('http://localhost:8069/xmlrpc/common') UID = sock.login('terp3', 'admin', 'admin')
CRUD(創建/讀取/更新/刪除)代碼示例:
""" :The login function is under :: http://localhost:8069/xmlrpc/common :For object retrieval use: :: http://localhost:8069/xmlrpc/object """ import xmlrpclib user = 'admin' pwd = 'admin' dbname = 'terp3' model = 'res.partner' sock = xmlrpclib.ServerProxy('http://localhost:8069/xmlrpc/common') uid = sock.login(dbname ,user ,pwd) sock = xmlrpclib.ServerProxy('http://localhost:8069/xmlrpc/object') # CREATE A PARTNER partner_data = {'name'.. code-block:: php:'Tiny', 'active':True, 'vat':'ZZZZZ'} partner_id = sock.execute(dbname, uid, pwd, model, 'create', partner_data) # The relation between res.partner and res.partner.category is of type many2many # To add categories to a partner use the following format: partner_data = {'name':'Provider2', 'category_id': [(6,0,[3, 2, 1])]} # Where [3, 2, 1] are id fields of lines in res.partner.category # SEARCH PARTNERS args = [('vat', '=', 'ZZZZZ'),] ids = sock.execute(dbname, uid, pwd, model, 'search', args) # READ PARTNER DATA fields = ['name', 'active', 'vat', 'ref'] results = sock.execute(dbname, uid, pwd, model, 'read', ids, fields) print results # EDIT PARTNER DATA values = {'vat':'ZZ1ZZ'} results = sock.execute(dbname, uid, pwd, model, 'write', ids, values) # DELETE PARTNER DATA results = sock.execute(dbname, uid, pwd, model, 'unlink', ids)
PRINT(打印) 示例代碼:
打印發票
IDS is the invoice ID, as returned by:
ids = sock.execute(dbname, uid, pwd, ‘account.invoice’, ‘search’, [(‘number’, ‘ilike’, invoicenumber), (‘type’, ‘=’, ‘out_invoice’)])
import time import base64 printsock = xmlrpclib.ServerProxy('http://server:8069/xmlrpc/report') model = 'account.invoice' id_report = printsock.report(dbname, uid, pwd, model, ids, {'model': model, 'id': ids[0], 'report_type':'pdf'}) time.sleep(5) state = False attempt = 0 while not state: report = printsock.report_get(dbname, uid, pwd, id_report) state = report['state'] if not state: time.sleep(1) attempt += 1 if attempt>200: print 'Printing aborted, too long delay !' string_pdf = base64.decodestring(report['result']) file_pdf = open('/tmp/file.pdf','w') file_pdf.write(string_pdf) file_pdf.close()
PHP 代碼示例?
下面的例子是如何使用 PHP 創建一個合作伙伴. 這裏使用 phpxmlrpc 庫, 在 sourceforge 上有效.
<? include('xmlrpc.inc'); $arrayVal = array( 'name'=>new xmlrpcval('Fabien Pinckaers', "string") , 'vat'=>new xmlrpcval('BE477472701' , "string") ); $client = new xmlrpc_client("http://localhost:8069/xmlrpc/object"); $msg = new xmlrpcmsg('execute'); $msg->addParam(new xmlrpcval("dbname", "string")); $msg->addParam(new xmlrpcval("3", "int")); $msg->addParam(new xmlrpcval("demo", "string")); $msg->addParam(new xmlrpcval("res.partner", "string")); $msg->addParam(new xmlrpcval("create", "string")); $msg->addParam(new xmlrpcval($arrayVal, "struct")); $resp = $client->send($msg); if ($resp->faultCode()) echo 'Error: '.$resp->faultString(); else echo 'Partner '.$resp->value()->scalarval().' created !'; ?>
Perl 代碼示例?
下面的例子是使用 Perl 創建、查找、刪除一個合作伙伴.
#!c:/perl/bin/perl # 17-02-2010 # OpenERP XML RPC communication example # Todor Todorov <[email protected]> <[email protected]> use strict; use Frontier::Client; use Data::Dumper; my($user) = 'admin'; my($pw) = 'admin'; my($db) = 'put_your_dbname_here'; my($model) = 'res.partner'; #登錄 my $server_url = 'http://localhost:8069/xmlrpc/common'; my $server = Frontier::Client->new('url' => $server_url); my $uid = $server->call('login',$db,$user,$pw); print Dumper($uid); my $server_url = 'http://localhost:8069/xmlrpc/object'; my $server = Frontier::Client->new('url' => $server_url); print Dumper($server); # # 創建合作伙伴 # my $partner_data = {'name'=>'MyNewPartnerName', 'active'=> 'True', 'vat'=>'ZZZZZ'}; my $partner_id = $server->call('execute',$db, $uid, $pw, $model, 'create', $partner_data); print Dumper($partner_id); # # 搜索合作伙伴 # my $query = [['vat', '=', 'ZZZZZ']]; print Dumper($query); my $ids = $server->call('execute',$db, $uid, $pw, $model, 'search', $query); print Dumper($ids); #這裏等待用戶輸入 #OpenERP interface my be checked if partner is shown there print $/."Check OpenERP if partner is inserted. Press ENTER".$/; <STDIN>; # # 刪除合作伙伴 # my $results = $server->call('execute',$db, $uid, $pw, $model, 'unlink', $ids); print Dumper($results);
在 OpenERP 的 GTK 或 web 客戶端的一切活動都是通過 XML/RPC webservices. 啓動 openERP GTK 客戶端 使用 ./openerp-client.py -l debug_rpc (or debug_rpc_answer) 然後你可以在 GTK 客戶端操作,查看客戶端操作日誌, 你將看到webservice的標籤。通過在日誌中創建縮進將幫助您 找出它的web服務.