odoo V10开发文档(第三章:工作流、安全机制、向导)

工作流

工作流是与业务流程相关联的模型,工作流同时可用于跟踪工序的演变过程

例:为session模型添加一个state字段用于定义一个工作流
state有三种取值:Draft (默认), Confirmed and Done.
在session表单添加state的显示,并添加一个改变其状态的按钮

#models.py
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'
    
#views.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里以record定义。在工作流中处理的单个流程称为工作项。

与模型关联的工作流是在创建模型记录时生成的,工作流定义之前创建的模型记录是没有相应的工作流的。

例:将之前定义的伪工作流修改为真正的工作流,修改视图让按钮触发真正的工作流

#__manifest__.py
'data':[
    'templates.xml',
    'views/openacademy.xml',
    'views/partner.xml',
    'views/session_workflow.xml',
],

#models.py
state = fields.Selection([
        ('draft', "Draft"),
        ('confirmed', "Confirmed"),
        ('done', "Done"),
    ])

#views.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"/>
    </header>
    
#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>

自动转换:当上座率达到50%时自动将session的状态由draft变为confirmed

#session_workflow.xml
<!-- 工作流自动转换 -->
<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>

<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>

安全机制

1.基于组的权限控制机制

组是以单条记录的形式记录在res.group模型中的,通过菜单定义来控制访问权限。但在不通过菜单访问情况下仍然是可以访问到对象的,所以需要为组定义对象级别的权限(read,write,create,unlink),一般是通过csv文件来定义,也可通过group属性来限制对象或视图中的字段权限

2.访问权限

访问权限通过ir.model.access的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

例:
通过用户界面来添加权限控制

通过设置-用户-用户 添加一个新用户
通过设置-用户-组 建立一个新组
编辑创建的新用户将他加入到新建的组中
用新增的用户帐号登录,看权限是否正确

通过文件来设置权限

#__manifest__.py
'data': [
        'security/security.xml',
    
#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_courses,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_courses,,1,0,0,0
session_read_all,session all,model_openacademy_session,,1,0,0,0

#security/security.xml
<odoo>
    <data>
        <record id="group_manager" model="res.groups">
            <field name="name">OpenAcademy / Manager</field>
        </record>
    </data>
</odoo>

3.基于记录的权限控制

基于记录的权限可以控制指定模型的所有数据集,使用模型的ir.rule属性来声明,可以控制其关联模型、many2many字段、domain表达式所过滤出的字段

例:状态为cancel的负责人才可以删除,group的值必须与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>

例:为课程模型添加记录行权限,限制write和unlink权限,当课程没有负责人时所有组内成员就都可以修改,有负责人时只有负责人有权修改

#security.xml
<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_courses"/>
    <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>

向导

向导以动态的形式描述与用户或对话框的交互,一个向导其实就是一个继承自TransientModel的模型,TransientModel又继承自model,在继承原有属性的基础上新增了新特性

  • 记录是临时的,会在一定时间内自动从数据库删除
  • 向导模型不需要访问权限,所有用户均可访问
  • 向导记录可以通过many2one关联普通记录或其他向导记录,普通记录无法通过many2one关系向导记录

实例:创建一个与session模型有多对一关系、与partner模型有多对多关系的向导

#__init__.py
from . import wizard

#wizard.py
# -*- coding: utf-8 -*-

from odoo import models, fields, api

class Wizard(models.TransientModel):
    _name = 'openacademy.wizard'

    session_id = fields.Many2one('openacademy.session',
        string="Session", required=True)
    attendee_ids = fields.Many2many('res.partner', string="Attendees")

启动向导

向导可以通过ir.actions.act_window记录来启动,将target字段值设置为new即可。target属性会给出一个向导的弹出框。还可以通过一个额外的src_model字段来指定某个模型的向导操作可用,在xml中用act_window标签定义。

<act_window id="launch_the_wizard"
            name="Launch the Wizard"
            src_model="context.model.name"
            res_model="wizard.model.name"
            view_mode="form"
            target="new"
            key2="client_action_multi"/>

向导使用的是常规视图,我们可以给它的按钮添加special="cancel"属性来实现不保存任何数据的情况下关闭向导

例1:为向导定义一个表单,在session模型中添加一个按钮来启动向导,使用self._context拿到当前session,给向导的session字段添加一个默认值
下面的例子可以为session创建一个添加出席者的向导

#wizard.py
def _default_session(self):
        return self.env['openacademy.session'].browse(self._context.get('active_id'))
session_id = fields.Many2one('openacademy.session',
        string="Session", required=True, default=_default_session)
        
#views.xml
<record model="ir.ui.view" id="wizard_form_view">
    <field name="name">wizard.form</field>
    <field name="model">openacademy.wizard</field>
    <field name="arch" type="xml">
        <form string="Add Attendees">
            <group>
                <field name="session_id"/>
                <field name="attendee_ids"/>
            </group>
        </form>
    </field>
</record>

<act_window id="launch_session_wizard"
            name="Add Attendees"
            src_model="openacademy.session"
            res_model="openacademy.wizard"
            view_mode="form"
            target="new"
            key2="client_action_multi"/>
        

例2:注册出席人
给向导添加一个按钮,并将出席人添加到指定session中

#views.xml
</group>
<footer>
      <button name="subscribe" type="object"
              string="Subscribe" class="oe_highlight"/>
      or
      <button special="cancel" string="Cancel"/>
  </footer>
</form>

#wizard.py
 @api.multi
    def subscribe(self):
        self.session_id.attendee_ids |= self.attendee_ids
        return {}

例3:将出席人注册到多个session

#views.xml
<form string="Add Attendees">
    <group>
        <field name="session_ids"/>
        <field name="attendee_ids"/>
    </group>
   
#wizard.py
def _default_sessions(self):
        return self.env['openacademy.session'].browse(self._context.get('active_ids'))

    session_ids = fields.Many2many('openacademy.session',
        string="Sessions", required=True, default=_default_sessions)
    attendee_ids = fields.Many2many('res.partner', string="Attendees")

    @api.multi
    def subscribe(self):
        for session in self.session_ids:
            session.attendee_ids |= self.attendee_ids
        return {}

内容发布自http://www.dingyii.cn,转载请注明出处

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,117评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,328评论 1 293
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,839评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,007评论 0 206
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,384评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,629评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,880评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,593评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,313评论 1 243
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,575评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,066评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,392评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,052评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,082评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,844评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,662评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,575评论 2 270

推荐阅读更多精彩内容

  • 点击查看原文 Web SDK 开发手册 SDK 概述 网易云信 SDK 为 Web 应用提供一个完善的 IM 系统...
    layjoy阅读 13,342评论 0 15
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,100评论 18 139
  • 从三月份找实习到现在,面了一些公司,挂了不少,但最终还是拿到小米、百度、阿里、京东、新浪、CVTE、乐视家的研发岗...
    时芥蓝阅读 42,015评论 11 349
  • 图文/耳风 你的脚步与我的心跳同步在时间星海闪烁后坠落进大地暮色沉寂借此把楼的影子摁入想你的,不眠夜和爱你的,每秒钟
    耳风丶阅读 394评论 14 48
  • 在宽恕中我们得到赦免,在死亡之时即可进入永生。 如果我是受害者,我会不会选择原谅那个伤害我的人呢?尤其是当他夺...
    乂禾央阅读 297评论 0 0