Odoo10開發(fā)教程九(報(bào)表和WebService)

報(bào)表

報(bào)表打印

Odoo 8.0 開始使用新的基于QWeb残吩,Twitter BootstrapWkhtmltopdf的報(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客戶端任洞。

  1. 建立文件openacademy/views/session_board.xml蓄喇。這個文件包含面板視圖,視圖的觸發(fā)action交掏,打開儀表盤的action妆偏,以及重新定義主菜單項(xiàng)以添加儀表盤的action。

注意
可以使用的儀表盤風(fēng)格有:1耀销,1-1楼眷,2-11-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)庫urllib2json與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,例如:

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末气忠,一起剝皮案震驚了整個濱河市邻储,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌旧噪,老刑警劉巖吨娜,帶你破解...
    沈念sama閱讀 216,402評論 6 499
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異淘钟,居然都是意外死亡宦赠,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,377評論 3 392
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來勾扭,“玉大人缤骨,你說我怎么就攤上這事〕呓瑁” “怎么了绊起?”我有些...
    開封第一講書人閱讀 162,483評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長燎斩。 經(jīng)常有香客問我虱歪,道長,這世上最難降的妖魔是什么栅表? 我笑而不...
    開封第一講書人閱讀 58,165評論 1 292
  • 正文 為了忘掉前任笋鄙,我火速辦了婚禮,結(jié)果婚禮上怪瓶,老公的妹妹穿的比我還像新娘萧落。我一直安慰自己,他們只是感情好洗贰,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,176評論 6 388
  • 文/花漫 我一把揭開白布找岖。 她就那樣靜靜地躺著,像睡著了一般敛滋。 火紅的嫁衣襯著肌膚如雪许布。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,146評論 1 297
  • 那天绎晃,我揣著相機(jī)與錄音蜜唾,去河邊找鬼。 笑死庶艾,一個胖子當(dāng)著我的面吹牛袁余,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播咱揍,決...
    沈念sama閱讀 40,032評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼颖榜,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了述召?” 一聲冷哼從身側(cè)響起朱转,我...
    開封第一講書人閱讀 38,896評論 0 274
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎积暖,沒想到半個月后藤为,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,311評論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡夺刑,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,536評論 2 332
  • 正文 我和宋清朗相戀三年缅疟,在試婚紗的時候發(fā)現(xiàn)自己被綠了分别。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,696評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡存淫,死狀恐怖耘斩,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情桅咆,我是刑警寧澤括授,帶...
    沈念sama閱讀 35,413評論 5 343
  • 正文 年R本政府宣布,位于F島的核電站岩饼,受9級特大地震影響荚虚,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜籍茧,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,008評論 3 325
  • 文/蒙蒙 一版述、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧寞冯,春花似錦渴析、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至螟蝙,卻和暖如春恢恼,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背胰默。 一陣腳步聲響...
    開封第一講書人閱讀 32,815評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留漓踢,地道東北人牵署。 一個月前我還...
    沈念sama閱讀 47,698評論 2 368
  • 正文 我出身青樓,卻偏偏與公主長得像喧半,于是被迫代替她去往敵國和親奴迅。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,592評論 2 353

推薦閱讀更多精彩內(nèi)容