工作流
工作流是与动态业务对象相关联的模型。工作流也用于跟踪动态演进的进程。
练习伪工作流
在授课模型上添加一个字段state
,用于定义一个工作流程。授课存在三个可能的状态:Draft(草稿,默认值)、Confirmed(已确认)、Done(已完成)。在授课的form视图中,添加一个只读字段用于显示课程状态,并可以通过按钮来改变状态。有效的状态值迁移包括:
- Draft->Confirmed
- Confirmed->Draft
- Confirmed->Done
- Done->Draft
- 添加一个新的字段
state
- 添加状态迁移方法,这个方法可以被form表单的按钮所调用,用以更改授课的状态
- 将相关按钮添加到授课的form视图
openacademy/models.py
attendees_count = fields.Integer(
string="Attendees count", compute='_get_attendees_count', store=True)
state = fields.Selection([
('draft', "Draft"),
('confirmed', "Confirmed"),
('done', "Done"),
], default='draft')
@api.multi
def action_draft(self):
self.state = 'draft'
@api.multi
def action_confirm(self):
self.state = 'confirmed'
@api.multi
def action_done(self):
self.state = 'done'
@api.depends('seats', 'attendee_ids')
def _taken_seats(self):
for r in self:
openacademy/views/openacademy.xml
<field name="model">openacademy.session</field>
<field name="arch" type="xml">
<form string="Session Form">
<header>
<button name="action_draft" type="object"
string="Reset to draft"
states="confirmed,done"/>
<button name="action_confirm" type="object"
string="Confirm" states="draft"
class="oe_highlight"/>
<button name="action_done" type="object"
string="Mark as done" states="confirmed"
class="oe_highlight"/>
<field name="state" widget="statusbar"/>
</header>
<sheet>
<group>
<group string="General">
工作流可以与Odoo中的任何对象关联,并且可完全定制化。工作流用于构造和管理业务对象和文档的生命周期,并且通过图形化工具定义转换器、触发器等。工作流、动作(节点或操作)和迁移(条件)通常以XML记录行的形式定义。在工作流进行导航的标签称为工作项。
警告
与模型相关的工作流仅在创建模型记录时被创建。因此,在工作流定义之前创建的授课实例是没有与之对应的工作流实例的。
练习工作流
使用真正的授课工作流替换之前的伪工作流。修改授课的form视图,按钮将调用工作流而不是调用模型的方法。
openacademy/__manifest__.py
'templates.xml',
'views/openacademy.xml',
'views/partner.xml',
'views/session_workflow.xml',
],
# only loaded in demonstration mode
'demo': [
openacademy/models.py
('draft', "Draft"),
('confirmed', "Confirmed"),
('done', "Done"),
])
@api.multi
def action_draft(self):
openacademy/views/openacademy.xml
<field name="arch" type="xml">
<form string="Session Form">
<header>
<button name="draft" type="workflow"
string="Reset to draft"
states="confirmed,done"/>
<button name="confirm" type="workflow"
string="Confirm" states="draft"
class="oe_highlight"/>
<button name="done" type="workflow"
string="Mark as done" states="confirmed"
class="oe_highlight"/>
<field name="state" widget="statusbar"/>
openacademy/views/session_workflow.xml
<odoo>
<data>
<record model="workflow" id="wkf_session">
<field name="name">OpenAcademy sessions workflow</field>
<field name="osv">openacademy.session</field>
<field name="on_create">True</field>
</record>
<record model="workflow.activity" id="draft">
<field name="name">Draft</field>
<field name="wkf_id" ref="wkf_session"/>
<field name="flow_start" eval="True"/>
<field name="kind">function</field>
<field name="action">action_draft()</field>
</record>
<record model="workflow.activity" id="confirmed">
<field name="name">Confirmed</field>
<field name="wkf_id" ref="wkf_session"/>
<field name="kind">function</field>
<field name="action">action_confirm()</field>
</record>
<record model="workflow.activity" id="done">
<field name="name">Done</field>
<field name="wkf_id" ref="wkf_session"/>
<field name="kind">function</field>
<field name="action">action_done()</field>
</record>
<record model="workflow.transition" id="session_draft_to_confirmed">
<field name="act_from" ref="draft"/>
<field name="act_to" ref="confirmed"/>
<field name="signal">confirm</field>
</record>
<record model="workflow.transition" id="session_confirmed_to_draft">
<field name="act_from" ref="confirmed"/>
<field name="act_to" ref="draft"/>
<field name="signal">draft</field>
</record>
<record model="workflow.transition" id="session_done_to_draft">
<field name="act_from" ref="done"/>
<field name="act_to" ref="draft"/>
<field name="signal">draft</field>
</record>
<record model="workflow.transition" id="session_confirmed_to_done">
<field name="act_from" ref="confirmed"/>
<field name="act_to" ref="done"/>
<field name="signal">done</field>
</record>
</data>
</odoo>
提示
要检查授课实例对应的工作流实例是否被正确创建,可以:设置->技术->工作流->实例
练习自动状态迁移
当超过一半座席被保留时,自动将授课的状态从Draft迁移到Confirmed。
openacademy/views/session_workflow.xml
<field name="act_to" ref="done"/>
<field name="signal">done</field>
</record>
<record model="workflow.transition" id="session_auto_confirm_half_filled">
<field name="act_from" ref="draft"/>
<field name="act_to" ref="confirmed"/>
<field name="condition">taken_seats > 50</field>
</record>
</data>
</odoo>
练习服务器动作
用服务器动作替换用于同步授课状态的Python方法。工作流和服务器动作都可以从UI创建。
openacademy/views/session_workflow.xml
<field name="on_create">True</field>
</record>
<record model="ir.actions.server" id="set_session_to_draft">
<field name="name">Set session to Draft</field>
<field name="model_id" ref="model_openacademy_session"/>
<field name="code">
model.search([('id', 'in', context['active_ids'])]).action_draft()
</field>
</record>
<record model="workflow.activity" id="draft">
<field name="name">Draft</field>
<field name="wkf_id" ref="wkf_session"/>
<field name="flow_start" eval="True"/>
<field name="kind">dummy</field>
<field name="action"></field>
<field name="action_id" ref="set_session_to_draft"/>
</record>
<record model="ir.actions.server" id="set_session_to_confirmed">
<field name="name">Set session to Confirmed</field>
<field name="model_id" ref="model_openacademy_session"/>
<field name="code">
model.search([('id', 'in', context['active_ids'])]).action_confirm()
</field>
</record>
<record model="workflow.activity" id="confirmed">
<field name="name">Confirmed</field>
<field name="wkf_id" ref="wkf_session"/>
<field name="kind">dummy</field>
<field name="action"></field>
<field name="action_id" ref="set_session_to_confirmed"/>
</record>
<record model="ir.actions.server" id="set_session_to_done">
<field name="name">Set session to Done</field>
<field name="model_id" ref="model_openacademy_session"/>
<field name="code">
model.search([('id', 'in', context['active_ids'])]).action_done()
</field>
</record>
<record model="workflow.activity" id="done">
<field name="name">Done</field>
<field name="wkf_id" ref="wkf_session"/>
<field name="kind">dummy</field>
<field name="action"></field>
<field name="action_id" ref="set_session_to_done"/>
</record>
<record model="workflow.transition" id="session_draft_to_confirmed">
安全
安全是为了实现统一的安全策略而进行配置的访问控制机制。
基于组的访问控制机制
组是通过在res.groups
模型的记录行来创建的,并通过菜单访问权限来限制权限。但是,即使没有菜单,对象仍然可以间接被访问,因此必须为组定义实际的对象级权限(读取、写入、创建、取消关联)。一般通过模块中的CSV文件插入。也可以通过字段的groups
属性来限制对视图或对象上特定字段的访问。
访问权限
访问权限通过ir.model.access
的记录行来定义。每个访问权限与模型、组(或者非全局访问的组)相关联,并且是一组权限:读取、写入、创建、取消关联。这些访问权限一般通过ir.model.access.csv
这个CSV文件创建。
id,name,model_id/id,group_id/id,perm_read,perm_write,perm_create,perm_unlink
access_idea_idea,idea.idea,model_idea_idea,base.group_user,1,1,1,0
access_idea_vote,idea.vote,model_idea_vote,base.group_user,1,1,1,0
练习
通过Odoo界面添加访问控制权限
建立一个新用户John Smith
,然后建立OpenAcademy/Session Read
组,并赋予这个组对授课模型的读权限。
- 建立一个新用户
John Smit
通过 设置->用户->用户 - 建立一个新组
session_read
通过 设置->用户->组,这个组拥有对授课模型的读权限 - 编辑
John Smith
用户,把他加入到session_read
组 - 以
John Smith
身份登录系统,检查权限是否正确。
练习
通过数据文件添加访问控制权限:
- 建立一个组
OpenAcademy / Manager
,这个组对开放学院的所有模型都有完全权限。 - 让
Session
和Course
对所有用户可读
- 建立新的文件
openacademy/security/security.xml
用来定义OpenAcademy Manager
组 - 编辑文件
openacademy/security/ir.model.access.csv
来添加对模型的访问权限 - 最后更新
openacademy/__manifest__.py
来添加新的数据文件
openacademy/__manifest__.py
# always loaded
'data': [
'security/security.xml',
'security/ir.model.access.csv',
'templates.xml',
'views/openacademy.xml',
'views/partner.xml',
openacademy/security/ir.model.access.csv
id,name,model_id/id,group_id/id,perm_read,perm_write,perm_create,perm_unlink
course_manager,course manager,model_openacademy_course,group_manager,1,1,1,1
session_manager,session manager,model_openacademy_session,group_manager,1,1,1,1
course_read_all,course all,model_openacademy_course,,1,0,0,0
session_read_all,session all,model_openacademy_session,,1,0,0,0
openacademy/security/security.xml
<odoo>
<data>
<record id="group_manager" model="res.groups">
<field name="name">OpenAcademy / Manager</field>
</record>
</data>
</odoo>
记录规则
记录规则限制对给定模型的记录子集的访问权限。一个规则就是ir.rule
模型的一行记录,并且将其关联到模型、数组(many2many字段)、或domain。domain指定了对那些记录有访问权限。
这是一个记录规则的例子,这个规则防止非cancel
状态的负责人被删除。请注意,groups
字段的值必须遵守与ORM的write()
方法一样的规则。
<record id="delete_cancelled_only" model="ir.rule">
<field name="name">Only cancelled leads may be deleted</field>
<field name="model_id" ref="crm.model_crm_lead"/>
<field name="groups" eval="[(4, ref('sales_team.group_sale_manager'))]"/>
<field name="perm_read" eval="0"/>
<field name="perm_write" eval="0"/>
<field name="perm_create" eval="0"/>
<field name="perm_unlink" eval="1" />
<field name="domain_force">[('state','=','cancel')]</field>
</record>
练习记录规则
为授课模型和OpenAcademy / Manager组添加记录规则,这个记录规则限制只有课程负责人可以对课程进行write
和unlink
操作,如果课程还没有负责人,这个组的所有用户都可以编辑它。在openacademy/security/security.xml
文件中创建新的规则:
openacademy/security/security.xml
<record id="group_manager" model="res.groups">
<field name="name">OpenAcademy / Manager</field>
</record>
<record id="only_responsible_can_modify" model="ir.rule">
<field name="name">Only Responsible can modify Course</field>
<field name="model_id" ref="model_openacademy_course"/>
<field name="groups" eval="[(4, ref('openacademy.group_manager'))]"/>
<field name="perm_read" eval="0"/>
<field name="perm_write" eval="1"/>
<field name="perm_create" eval="0"/>
<field name="perm_unlink" eval="1"/>
<field name="domain_force">
['|', ('responsible_id','=',False),
('responsible_id','=',user.id)]
</field>
</record>
</data>
</odoo>