行动

操作定义系统响应用户操作的行为:登录、操作按钮、选择发票……

Actions can be stored in the database or returned directly as dictionaries in e.g.按钮方法。所有操作都共享两个强制属性:

type

当前操作的类别,确定可以使用哪些字段以及如何解释操作

name

用户可读的操作简短描述,可以显示在客户端界面中

客户端可以通过 4 种形式获取操作:

  • False

    如果当前打开任何操作对话框,请将其关闭

  • 一个字符串

    如果 client action 匹配,则解释为客户端操作的标记,否则视为数字

  • 一个数字

    从数据库中读取相应的操作记录,可以是数据库标识符或 external id

  • 一本字典

    视为客户端操作描述符并执行

绑定

除了两个强制属性之外,所有操作还共享用于在任意模型的上下文菜单中呈现操作的“可选”属性:

binding_model_id

指定动作绑定到哪个模型

注解

对于服务器操作,请使用“model_id”。

binding_type

指定绑定的类型,主要是操作将出现在哪个上下文菜单下

``action``(默认)

指定该操作将出现在绑定模型的 Action 上下文菜单中。

report

指定该操作将出现在绑定模型的 Print 上下文菜单中。

binding_view_types

以逗号分隔的视图类型列表,其操作出现在上下文菜单中,主要是“列表”和/或“表单”。默认为 list,form (列表和表单)

窗口操作 (ir.actions.act_window)

最常见的操作类型,用于通过 views 呈现模型的可视化:窗口操作为模型(以及可能的模型的特定记录)定义一组视图类型(以及可能的特定视图)。

其字段有:

res_model

模型来呈现视图

views

(view_id, view_type) pairs. The second element of each pair is the category of the view (list, form, graph, …) and the first is an optional database id (or False 的列表)。如果未提供 id,客户端应获取请求模型的指定类型的默认视图(这由 fields_view_get() 自动完成)。列表的第一种类型是默认视图类型,并且在执行操作时默认打开。每种视图类型在列表中最多应出现一次

``res_id``(可选)

如果默认视图是“form”,则指定要加载的记录(否则应创建新记录)

``search_view_id``(可选)

(id, name) pair, id 是要为操作加载的特定搜索视图的数据库标识符。默认获取模型的默认搜索视图

``target``(可选)

是否应在主要内容区域中打开视图(current), in full screen mode (fullscreen) or in a dialog/popup (new). Use main instead of current to clear the breadcrumbs. Defaults to current

``context``(可选)

要传递到视图的附加上下文数据

``domain``(可选)

过滤域以隐式添加到所有视图搜索查询

``limit``(可选)

默认情况下在列表中显示的记录数。在 Web 客户端中默认为 80

例如,要使用列表和表单视图打开客户(与设置了“customer”标志的合作伙伴):

{
    "type": "ir.actions.act_window",
    "res_model": "res.partner",
    "views": [[False, "list"], [False, "form"]],
    "domain": [["customer", "=", true]],
}

或者在新对话框中打开特定产品(单独获取)的表单视图::

{
    "type": "ir.actions.act_window",
    "res_model": "product.product",
    "views": [[False, "form"]],
    "res_id": a_product_id,
    "target": "new",
}

数据库内窗口操作有几个不同的字段,客户端应忽略这些字段,主要用于组成“views”列表:

view_mode (default= list,form)

以逗号分隔的视图类型列表作为字符串(/!\ 无空格/!\)。所有这些类型都将出现在生成的 views list (with at least a False view_id 中)

view_ids

M2M[#notquitem2m]_查看对象,定义``views``的初始内容

注解

Act_window 视图也可以通过 ir.actions.act_window.view 干净地定义。

如果您计划允许模型使用多个视图,请更喜欢使用 ir.actions.act_window.view 而不是操作 view_ids

<record model="ir.actions.act_window.view" id="test_action_tree">
   <field name="sequence" eval="1"/>
   <field name="view_mode">list</field>
   <field name="view_id" ref="view_test_tree"/>
   <field name="act_window_id" ref="test_action"/>
</record>
view_id

添加到``views`` list in case its type is part of the view_mode list and not already filled by one of the views in ``view_ids``的特定视图

这些主要在从 数据文件 定义操作时使用:

<record model="ir.actions.act_window" id="test_action">
    <field name="name">A Test Action</field>
    <field name="res_model">some.model</field>
    <field name="view_mode">graph</field>
    <field name="view_id" ref="my_specific_view"/>
</record>

将使用“my_specific_view”视图,即使这不是模型的默认视图。

views 序列的服务器端组成如下:

  • 获取每个``(id, type)`` from view_ids (ordered by sequence

  • 如果``view_id`` is defined and its type isn’t already filled, append its (id, type)

  • 对于“view_mode`, append ``(False, type)`”中的每个未填充类型

1

从技术上讲,它不是 M2M:添加了一个序列字段,并且可能仅由视图类型组成,没有视图 id。

URL 操作 (ir.actions.act_url)

允许通过 Odoo 操作打开 URL(网站/网页)。可以通过两个字段进行定制:

url

激活操作时要打开的地址

target (default= new)

可用的值为:

  • new:在新窗口/页面中打开 URL

  • self:在当前窗口/页面中打开 URL(替换实际内容)

  • download:重定向到下载 URL

例子:

{
    "type": "ir.actions.act_url",
    "url": "https://www.chinaodoo.com",
    "target": "self",
}

这将用 Odoo 主页替换当前内容部分。

服务器操作 (ir.actions.server)

允许从任何有效的操作位置触发复杂的服务器代码。只有两个字段与客户相关:

id

要运行的服务器操作的数据库内标识符

``context``(可选)

运行服务器操作时使用的上下文数据

数据库内记录更加丰富,可以根据其“state”执行许多特定或通用操作。一些字段(和相应的行为)在状态之间共享:

model_id

Odoo 模型与动作相关联。

state

  • code: Executes python code given through the code 参数。

  • object_create: Creates a new record of model crud_model_id following fields_lines 规格。

  • object_write: Updates the current record(s) following fields_lines 规格

  • multi: Executes several actions given through the child_ids 参数。

状态字段

根据其状态,行为是通过不同的字段定义的。相关状态在每个字段后给出。

``code``(代码)

指定调用操作时要执行的一段Python代码

<record model="ir.actions.server" id="print_instance">
    <field name="name">Res Partner Server Action</field>
    <field name="model_id" ref="model_res_partner"/>
    <field name="state">code</field>
    <field name="code">
        raise Warning(record.name)
    </field>
</record>

注解

该代码段可以定义一个名为“action”的变量,该变量将作为下一个要执行的操作返回给客户端:

<record model="ir.actions.server" id="print_instance">
    <field name="name">Res Partner Server Action</field>
    <field name="model_id" ref="model_res_partner"/>
    <field name="state">code</field>
    <field name="code">
        if record.some_condition():
            action = {
                "type": "ir.actions.act_window",
                "view_mode": "form",
                "res_model": record._name,
                "res_id": record.id,
            }
    </field>
</record>

如果满足某些条件,将要求客户打开表格进行记录

``crud_model_id``(创建)(必需)

创建新记录的模型

``link_field_id``(创建)

Many2one 到 ir.model.fields,指定应设置新创建记录的当前记录的 m2o 字段(模型应匹配)

``fields_lines``(创建/写入)

创建或复制记录时要覆盖的字段。 One2many 包含以下字段:

col1

ir.model.fields to set in the concerned model (crud_model_id for creates, model_id 用于更新)

value

该字段的值,通过“type”解释

``type``(值|reference|方程)

如果 value, the value field is interpreted as a literal value (possibly converted), if equation the value 字段被解释为 Python 表达式并计算

``child_ids``(多)

指定要在状态 multi 中执行的多个子操作 (ir.actions.server)。如果子操作本身返回操作,则最后一个操作将作为多重操作自己的下一个操作返回给客户端

评估背景

在服务器操作或周围服务器操作的评估上下文中可以使用许多键:

  • model model object linked to the action via model_id

  • 触发操作的“record`/``records`”记录/记录集可以为空。

  • env Odoo 环境

  • datetime, dateutil, time, ``timezone``对应的Python模块

  • log: log(message, level='info') 日志函数用于在 ir.logging 表中记录调试信息

  • Warning constructor for the Warning 异常

报告操作 (ir.actions.report)

触发报告的打印。

如果您通过 <record> 而不是 <report> 标签定义报告,并希望该操作显示在模型视图的“打印”菜单中,则还需要指定 binding_model_id from 绑定. It’s not necessary to set binding_type to report, since ir.actions.report 将隐式默认为该值。

``name``(强制)

如果未指定“print_report_name”,则用作文件名。否则,仅在在某种列表中查找报告时用作报告的助记符/描述

``model``(强制)

您的报告将涉及的模型

``report_type``(默认=qweb-pdf)

HTML 的“qweb-pdf` for PDF reports or ``qweb-html`”

``report_name``(强制)

用于呈现报告的 qweb 模板的名称 (external id)

print_report_name

定义报告名称的 python 表达式。

groups_id

允许查看/使用当前报告的组的 Many2many 字段

multi

如果设置为“True”,该操作将不会显示在表单视图上。

paperformat_id

Many2one 字段填写您希望用于此报告的纸张格式(如果未指定,将使用公司格式)

attachment_use

如果设置为“True”,则仅在第一次请求时生成一次报告,然后从存储的报告中重新打印,而不是每次都重新生成。

可用于只能生成一次的报告(例如出于法律原因)

attachment

定义报告名称的 python 表达式;该记录可通过变量“object”进行访问

客户端操作 (ir.actions.client)

触发完全在客户端执行的操作。

tag

操作的客户端标识符,客户端应该知道如何做出反应的任意字符串

``params``(可选)

与客户端操作标记一起发送到客户端的附加数据的 Python 字典

``target``(可选)

是否应在主要内容区域中打开客户端操作(current), in full screen mode (fullscreen) or in a dialog/popup (new). Use main instead of current to clear the breadcrumbs. Defaults to current

{
    "type": "ir.actions.client",
    "tag": "pos.ui"
}

告诉客户端启动销售点接口,服务器不知道 POS 接口如何工作。

计划的操作 (ir.cron)

操作按预定义的频率自动触发。

name

计划动作名称(主要用于日志显示)

interval_number

两次执行操作之间的 interval_type uom 数

interval_type

频率间隔的测量单位 (minutes, hours, days, weeks, months)

model_id

将调用此操作的模型

code

操作的代码内容。可以是对模型方法的简单调用:

model.<method_name>()
nextcall

此操作的下一个计划执行日期(日期/时间格式)

priority

同时执行多个动作时动作的优先级

编写 cron 函数

运行计划操作时,建议您尝试对进度进行批处理,以避免长时间阻塞工作人员并可能遇到超时异常。因此,您应该拆分处理,以便每个调用都能在一些需要完成的工作上取得进展。

编写此类函数时,您应该专注于处理单个批次。一个批次应该处理一条或多条记录,并且通常应该不超过*几秒钟*。

框架在每批之后提交工作。框架将根据需要多次调用该函数来处理剩余的工作。不要重新安排自己的工作。

def _cron_do_something(self, *, limit=300):  # limit: allows for tweaking
    domain = [('state', '=', 'ready')]
    records = self.search(domain, limit=limit)
    records.do_something()
    # notify progression
    remaining = 0 if len(records) == limit else self.search_count(domain)
    self.env['ir.cron']._commit_progress(len(records), remaining=remaining)

在某些情况下,您可能希望在多个批次之间共享资源或自己管理循环以处理异常。在这种情况下,您应该通过调用 IrCron._commit_progress() 并检查结果来通知调度程序您的工作进度。进度函数返回调用剩余的秒数;如果为0,则必须尽快返回。

以下示例说明了如何在处理每条记录后提交,同时保持连接打开。

def _cron_do_something(self):
    assert self.env.context.get('cron_id'), "Run only inside cron jobs"
    domain = [('state', '=', 'ready')]
    records = self.search(domain)
    self.env['ir.cron']._commit_progress(remaining=len(records))

    with open_some_connection() as conn:
        for record in records:
            # You may have other needs; we do some common stuff here:
            # - lock record (also checks existence)
            # - prefetch: break prefetch in this case, we process one record
            # - filtered_domain: record may have changed
            record = record.try_lock_for_update().filtered_domain(domain)
            if not record:
                continue
            # Processing the batch here...
            try
                record.do_something(conn)
                if not self.env['ir.cron']._commit_progress(1):
                    break
            except Exception:
                # if you handle exceptions, the default stategy is to
                # rollback first the error
                self.env.cr.rollback()
                _logger.warning(...)
                # you may commit some status using _commit_progress

运行 cron 函数

您不应该直接调用 cron 函数。运行函数有两种方法:

cron 函数的测试应通过在注册表测试模式下调用 IrCron.method_direct_trigger() 来完成。

安全

为了在计划操作之间保持资源的公平使用,一些安全措施可确保计划操作的正确运行。

  • 如果计划的操作连续三次遇到错误或超时,它将跳过当前执行并被视为失败。

  • 如果计划操作在至少 7 天内连续五次执行失败,则该操作将被停用并通知数据库管理员。

  • 数据库级别的 cron 执行存在硬限制,执行 cron 作业的进程将被终止。