Odoo10开发教程九(报表和WebService)

报表

报表打印

Odoo 8.0 开始使用新的基于QWebTwitter BootstrapWkhtmltopdf的报表引擎。一个报表有两个元素组成:
其一是ir.actions.report.xml中,针对报表提供的快捷元素<report>,这个元素用于设置报表的各种基本参数(如默认类型,报表生成后是否保存到数据库)

<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')"
/>

另一个是标准的QWeb视图,实例如下:

<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

由于报表是标准的web页面,所以都可以通过URL和输出参数来访问,例如HTML版本的发票报表可以通过这个地址访问:http://localhost:8069/report/html/account.report_invoice/1(如果安装了account),而PDF版本可以通过这个地址访问:http://localhost:8069/report/pdf/account.report_invoice/1

警告
如果出现了PDF报表没有样式(比如有文本显示但是与html版本的风格/布局不一致),可能是wkhtmltopdf进程不能为下载提供web服务。
如果你检查服务日志,并且看到生成PDF报表时CSS样式未被下载,那么就可以肯定是这个问题。
wkhtmltopdf进程使用web.base.url这个系统参数作为根路径来组合所有文件路径,但是这个参数是在管理员帐户登录后自动生成的。如果你的服务器位于某种代理服务器之后,则无法访问该服务器。你可以添加一个系统参数来固化它:

  • report.url,可以访问你的服务器的URL地址,比如http://localhost:8069或者类似的地址。这个参数仅用于这个特殊情况。
  • web.base.url.freeze,当设置这个参数值为True时将停止自动更新web.base.url

练习创建授课模型的报表
对于每个授课,报表都将显示它的授课名称,开始和结束时间,以及课程出席人列表。

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>

仪表盘

练习定义一个仪表盘
定义一个仪表盘,这个仪表盘包含了已经建立的图形视图、授课日历视图、课程列表视图(可以选择form视图)。这个仪表盘可以通过菜单中的菜单项使用,并且当选择开放学院主菜单时自动显示在web客户端。

  1. 建立文件openacademy/views/session_board.xml。这个文件包含面板视图,视图的触发action,打开仪表盘的action,以及重新定义主菜单项以添加仪表盘的action。

注意
可以使用的仪表盘风格有:11-12-11-1-1

  1. 更新openacademy/__manifest__.py文件,以引用新的数据文件。

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服务提供通用接口:

  • XML-RPC
  • JSON-RPC
    业务对象也可以通过这种分布式机制进行访问,在客户端界面通过上下文编辑这些业务对象。
    Odoo支持通过XML-RPC/JSON-RPC接口访问,这两种协议在许多开发语言中都有库支持。

XML-RPC库
下面的例子是Python程序通过xmlrpclib库访问Odoo服务器:

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)

练习在客户端添加新服务
编写Python程序,用来发送XML-RPC请求到运行Odoo的PC。这个程序将显示全部授课,以及所对应的座位数。也可以为课程创建新的授课。

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的标准库urllib2json与Odoo服务器交互。

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系统的高级API,例如:

    原文作者:luohuayong
    原文地址: https://www.jianshu.com/p/7383f3406f24
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞