odoo17核心概念action3——action_service

这是action系列的第三篇文章
action_service 是action的核心。
整个文件接近1500行代码,其中关键的两个函数是:

        doAction,
        doActionButton,

1、doAction


    // ---------------------------------------------------------------------------
    // public API
    // ---------------------------------------------------------------------------

    /**
     * Main entry point of a 'doAction' request. Loads the action and executes it.
     *
     * @param {ActionRequest} actionRequest
     * @param {ActionOptions} options
     * @returns {Promise<number | undefined | void>}
     */
    async function doAction(actionRequest, options = {}) {
        const actionProm = _loadAction(actionRequest, options.additionalContext);
        let action = await keepLast.add(actionProm);
        action = _preprocessAction(action, options.additionalContext);
        options.clearBreadcrumbs = action.target === "main" || options.clearBreadcrumbs;
        switch (action.type) {
            case "ir.actions.act_url":
                return _executeActURLAction(action, options);
            case "ir.actions.act_window":
                if (action.target !== "new") {
                    const canProceed = await clearUncommittedChanges(env);
                    if (!canProceed) {
                        return new Promise(() => {});
                    }
                }
                return _executeActWindowAction(action, options);
            case "ir.actions.act_window_close":
                return _executeCloseAction({ onClose: options.onClose, onCloseInfo: action.infos });
            case "ir.actions.client":
                return _executeClientAction(action, options);
            case "ir.actions.report":
                return _executeReportAction(action, options);
            case "ir.actions.server":
                return _executeServerAction(action, options);
            default: {
                const handler = actionHandlersRegistry.get(action.type, null);
                if (handler !== null) {
                    return handler({ env, action, options });
                }
                throw new Error(
                    `The ActionManager service can't handle actions of type ${action.type}`
                );
            }
        }
    }

注释中写的很清楚:
doAction请求的主要入口点,加载一个Action并执行它。
根据不同的action类型调用不同的函数处理。
注意最后的default:

 const handler = actionHandlersRegistry.get(action.type, null);
                if (handler !== null) {
                    return handler({ env, action, options });
                }
                throw new Error(
                    `The ActionManager service can't handle actions of type ${action.type}`
                );

这里说明,odoo支持用户扩展自己的动作类型,并且将动作类型的处理函数注册到注册表中,这里就可以调用了。

有哪些场景需要扩展action的类型呢?

2、doActionButton

 /**
     * Executes an action on top of the current one (typically, when a button in a
     * view is clicked). The button may be of type 'object' (call a given method
     * of a given model) or 'action' (execute a given action). Alternatively, the
     * button may have the attribute 'special', and in this case an
     * 'ir.actions.act_window_close' is executed.
     *
     * @param {DoActionButtonParams} params
     * @returns {Promise}
     */
    async function doActionButton(params) {
        // determine the action to execute according to the params
        let action;
        const context = makeContext([params.context, params.buttonContext]);
        if (params.special) {
            action = { type: "ir.actions.act_window_close", infos: { special: true } };
        } else if (params.type === "object") {
            // call a Python Object method, which may return an action to execute
            let args = params.resId ? [[params.resId]] : [params.resIds];
            if (params.args) {
                let additionalArgs;
                try {
                    // warning: quotes and double quotes problem due to json and xml clash
                    // maybe we should force escaping in xml or do a better parse of the args array
                    additionalArgs = JSON.parse(params.args.replace(/'/g, '"'));
                } catch {
                    browser.console.error("Could not JSON.parse arguments", params.args);
                }
                args = args.concat(additionalArgs);
            }
            const callProm = env.services.rpc("/web/dataset/call_button", {
                args,
                kwargs: { context },
                method: params.name,
                model: params.resModel,
            });
            action = await keepLast.add(callProm);
            action =
                action && typeof action === "object"
                    ? action
                    : { type: "ir.actions.act_window_close" };
            if (action.help) {
                action.help = markup(action.help);
            }
        } else if (params.type === "action") {
            // execute a given action, so load it first
            context.active_id = params.resId || null;
            context.active_ids = params.resIds;
            context.active_model = params.resModel;
            action = await keepLast.add(_loadAction(params.name, context));
        } else {
            throw new InvalidButtonParamsError("Missing type for doActionButton request");
        }
        // filter out context keys that are specific to the current action, because:
        //  - wrong default_* and search_default_* values won't give the expected result
        //  - wrong group_by values will fail and forbid rendering of the destination view
        const currentCtx = {};
        for (const key in params.context) {
            if (key.match(CTX_KEY_REGEX) === null) {
                currentCtx[key] = params.context[key];
            }
        }
        const activeCtx = { active_model: params.resModel };
        if (params.resId) {
            activeCtx.active_id = params.resId;
            activeCtx.active_ids = [params.resId];
        }
        action.context = makeContext([currentCtx, params.buttonContext, activeCtx, action.context]);
        // in case an effect is returned from python and there is already an effect
        // attribute on the button, the priority is given to the button attribute
        const effect = params.effect ? evaluateExpr(params.effect) : action.effect;
        const options = { onClose: params.onClose };
        await doAction(action, options);
        if (params.close) {
            await _executeCloseAction();
        }
        if (effect) {
            env.services.effect.add(effect);
        }
    }

1、当点击一个按钮的时候会调用这段代码,如果按钮有special属性,那么会执行ir.actions.act_window_close,也就是关闭当前窗口。
2、按钮有两张类型 object 和 action
3、如果是object,会执行调用rpc,调用后端代码
4、最终都是调用doAction函数执行的动作。

更具体的分析留到以后,这里只是简单的分析框架。

吐槽一下,在这个文件里发现一处有瑕疵的代码:

const DIALOG_SIZES = {
    "extra-large": "xl",
    large: "lg",
    medium: "md",
    small: "sm",
};

你可能感兴趣的:(odoo17,odoo,odoo17)