報(bào)表
報(bào)表打印
Odoo 8.0 開始使用新的基于QWeb残吩,Twitter Bootstrap 和 Wkhtmltopdf的報(bào)表引擎。一個報(bào)表有兩個元素組成:
其一是ir.actions.report.xml
中蝶桶,針對報(bào)表提供的快捷元素<report>
框冀,這個元素用于設(shè)置報(bào)表的各種基本參數(shù)(如默認(rèn)類型,報(bào)表生成后是否保存到數(shù)據(jù)庫)
<report
id="account_invoices"
model="account.invoice"
string="Invoices"
report_type="qweb-pdf"
name="account.report_invoice"
file="account.report_invoice"
attachment_use="True"
attachment="(object.state in ('open','paid')) and
('INV'+(object.number or '').replace('/','')+'.pdf')"
/>
另一個是標(biāo)準(zhǔn)的QWeb視圖肄程,實(shí)例如下:
<t t-call="report.html_container">
<t t-foreach="docs" t-as="o">
<t t-call="report.external_layout">
<div class="page">
<h2>Report title</h2>
</div>
</t>
</t>
</t>
the standard rendering context provides a number of elements, the most
important being:
``docs``
the records for which the report is printed
``user``
the user printing the report
由于報(bào)表是標(biāo)準(zhǔn)的web頁面睦擂,所以都可以通過URL和輸出參數(shù)來訪問得湘,例如HTML版本的發(fā)票報(bào)表可以通過這個地址訪問:http://localhost:8069/report/html/account.report_invoice/1(如果安裝了account
),而PDF版本可以通過這個地址訪問:http://localhost:8069/report/pdf/account.report_invoice/1顿仇。
警告
如果出現(xiàn)了PDF報(bào)表沒有樣式(比如有文本顯示但是與html版本的風(fēng)格/布局不一致)淘正,可能是wkhtmltopdf進(jìn)程不能為下載提供web服務(wù)。
如果你檢查服務(wù)日志夺欲,并且看到生成PDF報(bào)表時CSS樣式未被下載跪帝,那么就可以肯定是這個問題。
wkhtmltopdf進(jìn)程使用web.base.url
這個系統(tǒng)參數(shù)作為根路徑來組合所有文件路徑些阅,但是這個參數(shù)是在管理員帳戶登錄后自動生成的伞剑。如果你的服務(wù)器位于某種代理服務(wù)器之后,則無法訪問該服務(wù)器市埋。你可以添加一個系統(tǒng)參數(shù)來固化它:
-
report.url
黎泣,可以訪問你的服務(wù)器的URL地址,比如http://localhost:8069或者類似的地址缤谎。這個參數(shù)僅用于這個特殊情況抒倚。 -
web.base.url.freeze
,當(dāng)設(shè)置這個參數(shù)值為True
時將停止自動更新web.base.url
坷澡。
練習(xí)創(chuàng)建授課模型的報(bào)表
對于每個授課托呕,報(bào)表都將顯示它的授課名稱,開始和結(jié)束時間,以及課程出席人列表项郊。
openacademy / __ manifest__.py
'views/openacademy.xml',
'views/partner.xml',
'views/session_workflow.xml',
'reports.xml',
],
# only loaded in demonstration mode
'demo': [
openacademy/reports.xml
<odoo>
<data>
<report
id="report_session"
model="openacademy.session"
string="Session Report"
name="openacademy.report_session_view"
file="openacademy.report_session"
report_type="qweb-pdf" />
<template id="report_session_view">
<t t-call="report.html_container">
<t t-foreach="docs" t-as="doc">
<t t-call="report.external_layout">
<div class="page">
<h2 t-field="doc.name"/>
<p>From <span t-field="doc.start_date"/> to <span t-field="doc.end_date"/></p>
<h3>Attendees:</h3>
<ul>
<t t-foreach="doc.attendee_ids" t-as="attendee">
<li><span t-field="attendee.name"/></li>
</t>
</ul>
</div>
</t>
</t>
</t>
</template>
</data>
</odoo>
儀表盤
練習(xí)定義一個儀表盤
定義一個儀表盤馅扣,這個儀表盤包含了已經(jīng)建立的圖形視圖、授課日歷視圖着降、課程列表視圖(可以選擇form視圖)差油。這個儀表盤可以通過菜單中的菜單項(xiàng)使用,并且當(dāng)選擇開放學(xué)院主菜單時自動顯示在web客戶端任洞。
- 建立文件
openacademy/views/session_board.xml
蓄喇。這個文件包含面板視圖,視圖的觸發(fā)action交掏,打開儀表盤的action妆偏,以及重新定義主菜單項(xiàng)以添加儀表盤的action。
注意
可以使用的儀表盤風(fēng)格有:1
耀销,1-1
楼眷,2-1
和1-1-1
- 更新
openacademy/__manifest__.py
文件,以引用新的數(shù)據(jù)文件熊尉。
openacademy/__manifest__.py
'version': '0.1',
# any module necessary for this one to work correctly
'depends': ['base', 'board'],
# always loaded
'data': [
'views/openacademy.xml',
'views/partner.xml',
'views/session_workflow.xml',
'views/session_board.xml',
'reports.xml',
],
# only loaded in demonstration mode
openacademy/views/session_board.xml
<?xml version="1.0"?>
<odoo>
<data>
<record model="ir.actions.act_window" id="act_session_graph">
<field name="name">Attendees by course</field>
<field name="res_model">openacademy.session</field>
<field name="view_type">form</field>
<field name="view_mode">graph</field>
<field name="view_id"
ref="openacademy.openacademy_session_graph_view"/>
</record>
<record model="ir.actions.act_window" id="act_session_calendar">
<field name="name">Sessions</field>
<field name="res_model">openacademy.session</field>
<field name="view_type">form</field>
<field name="view_mode">calendar</field>
<field name="view_id" ref="openacademy.session_calendar_view"/>
</record>
<record model="ir.actions.act_window" id="act_course_list">
<field name="name">Courses</field>
<field name="res_model">openacademy.course</field>
<field name="view_type">form</field>
<field name="view_mode">tree,form</field>
</record>
<record model="ir.ui.view" id="board_session_form">
<field name="name">Session Dashboard Form</field>
<field name="model">board.board</field>
<field name="type">form</field>
<field name="arch" type="xml">
<form string="Session Dashboard">
<board style="2-1">
<column>
<action
string="Attendees by course"
name="%(act_session_graph)d"
height="150"
width="510"/>
<action
string="Sessions"
name="%(act_session_calendar)d"/>
</column>
<column>
<action
string="Courses"
name="%(act_course_list)d"/>
</column>
</board>
</form>
</field>
</record>
<record model="ir.actions.act_window" id="open_board_session">
<field name="name">Session Dashboard</field>
<field name="res_model">board.board</field>
<field name="view_type">form</field>
<field name="view_mode">form</field>
<field name="usage">menu</field>
<field name="view_id" ref="board_session_form"/>
</record>
<menuitem
name="Session Dashboard" parent="base.menu_reporting_dashboard"
action="open_board_session"
sequence="1"
id="menu_board_session" icon="terp-graph"/>
</data>
</odoo>
WebServices
WebService模型為所有web服務(wù)提供通用接口:
- XML-RPC
- JSON-RPC
業(yè)務(wù)對象也可以通過這種分布式機(jī)制進(jìn)行訪問,在客戶端界面通過上下文編輯這些業(yè)務(wù)對象掌腰。
Odoo支持通過XML-RPC/JSON-RPC接口訪問狰住,這兩種協(xié)議在許多開發(fā)語言中都有庫支持。
XML-RPC庫
下面的例子是Python程序通過xmlrpclib
庫訪問Odoo服務(wù)器:
import xmlrpclib
root = 'http://%s:%d/xmlrpc/' % (HOST, PORT)
uid = xmlrpclib.ServerProxy(root + 'common').login(DB, USER, PASS)
print "Logged in as %s (uid: %d)" % (USER, uid)
# Create a new note
sock = xmlrpclib.ServerProxy(root + 'object')
args = {
'color' : 8,
'memo' : 'This is a note',
'create_uid': uid,
}
note_id = sock.execute(DB, uid, PASS, 'note.note', 'create', args)
練習(xí)在客戶端添加新服務(wù)
編寫Python程序齿梁,用來發(fā)送XML-RPC請求到運(yùn)行Odoo的PC催植。這個程序?qū)@示全部授課,以及所對應(yīng)的座位數(shù)勺择。也可以為課程創(chuàng)建新的授課创南。
import functools
import xmlrpclib
HOST = 'localhost'
PORT = 8069
DB = 'openacademy'
USER = 'admin'
PASS = 'admin'
ROOT = 'http://%s:%d/xmlrpc/' % (HOST,PORT)
# 1. Login
uid = xmlrpclib.ServerProxy(ROOT + 'common').login(DB,USER,PASS)
print "Logged in as %s (uid:%d)" % (USER,uid)
call = functools.partial(
xmlrpclib.ServerProxy(ROOT + 'object').execute,
DB, uid, PASS)
# 2. Read the sessions
sessions = call('openacademy.session','search_read', [], ['name','seats'])
for session in sessions:
print "Session %s (%s seats)" % (session['name'], session['seats'])
# 3.create a new session
session_id = call('openacademy.session', 'create', {
'name' : 'My session',
'course_id' : 2,
})
不使用硬編碼,通過課程名稱查找課程ID:
# 3.create a new session for the "Functional" course
course_id = call('openacademy.course', 'search', [('name','ilike','Functional')])[0]
session_id = call('openacademy.session', 'create', {
'name' : 'My session',
'course_id' : course_id,
})
JSON-RPC庫
下面的例子是一個Python程序省核,通過Pythong的標(biāo)準(zhǔn)庫urllib2
和json
與Odoo服務(wù)器交互稿辙。
import json
import random
import urllib2
def json_rpc(url, method, params):
data = {
"jsonrpc": "2.0",
"method": method,
"params": params,
"id": random.randint(0, 1000000000),
}
req = urllib2.Request(url=url, data=json.dumps(data), headers={
"Content-Type":"application/json",
})
reply = json.load(urllib2.urlopen(req))
if reply.get("error"):
raise Exception(reply["error"])
return reply["result"]
def call(url, service, method, *args):
return json_rpc(url, "call", {"service": service, "method": method, "args": args})
# log in the given database
url = "http://%s:%s/jsonrpc" % (HOST, PORT)
uid = call(url, "common", "login", DB, USER, PASS)
# create a new note
args = {
'color' : 8,
'memo' : 'This is another note',
'create_uid': uid,
}
note_id = call(url, "object", "execute", DB, uid, PASS, 'note.note', 'create', args)
下面是使用jsonrpc
完成相同功能的程序
import jsonrpclib
# server proxy object
url = "http://%s:%s/jsonrpc" % (HOST, PORT)
server = jsonrpclib.Server(url)
# log in the given database
uid = server.call(service="common", method="login", args=[DB, USER, PASS])
# helper function for invoking model methods
def invoke(model, method, *args):
args = [DB, uid, PASS, model, method] + list(args)
return server.call(service="object", method="execute", args=args)
# create a new note
args = {
'color' : 8,
'memo' : 'This is another note',
'create_uid': uid,
}
note_id = invoke('note.note', 'create', args)
提醒
有許多語言可以通過XML-RPC或JSON-RPC訪問Odoo系統(tǒng)的高級API,例如: