Odoo 17 POS前端载入初始数据的流程 - xiaohao0576/odoo-doc GitHub Wiki

先从前端的一个JS方法开始

https://github.com/odoo/odoo/blob/b0d51f52e6820455343bc7fbce70866bddea8a5b/addons/point_of_sale/static/src/app/store/pos_store.js#L258

    async load_server_data() {
        const loadedData = await this.orm.silent.call("pos.session", "load_pos_data", [
            [odoo.pos_session_id],
        ]);
        await this._processData(loadedData);
        return this.after_load_server_data();
    }

上面的方法,用orm方法调用了后端pos.session中的load_pos_data方法 https://github.com/odoo/odoo/blob/b0d51f52e6820455343bc7fbce70866bddea8a5b/addons/point_of_sale/models/pos_session.py#L1620

    def load_pos_data(self):
        loaded_data = {}
        self = self.with_context(loaded_data=loaded_data)
        for model in self._pos_ui_models_to_load():
            loaded_data[model] = self._load_model(model)
        self._pos_data_process(loaded_data)
        return loaded_data

_pos_ui_models_to_load()方法里面列出了需要导出数据的model名称列表

    @api.model
    def _pos_ui_models_to_load(self):
        models_to_load = [
            'res.company',
            'decimal.precision',
            'uom.uom',
            'res.country.state',
            'res.country',
            'res.lang',
            'account.tax',
            'pos.session',
            'pos.config',
            'pos.printer',
            'pos.bill',
            'res.partner',
            'stock.picking.type',
            'res.users',
            'product.product',
            'product.pricelist',
            'res.currency',
            'pos.category',
            'pos.combo',
            'pos.combo.line',
            'product.packaging',
            'account.cash.rounding',
            'pos.payment.method',
            'account.fiscal.position',
        ]

        return models_to_load

_load_model方法使用了Python的getattr内置方法,用反射的方式通过拼接字符串去调用对象的方法

    def _load_model(self, model):
        model_name = model.replace('.', '_')
        loader = getattr(self, '_get_pos_ui_%s' % model_name, None)
        params = getattr(self, '_loader_params_%s' % model_name, None)
        if loader and params:
            return loader(params())
        else:
            raise NotImplementedError(_("The function to load %s has not been implemented.", model))

pos.printer模型举例

loader = getattr(self, '_get_pos_ui_pos_printer',None)
params = getattr(self, '_loader_params_pos_printer, None)

return loader(params())
相当于先调用`_loader_params_pos_printer`这个方法,获取doman和字段列表
然后再把得到了params传到`_get_pos_ui_pos_printer`方法中,去数据库调取数据

最后,不能用 loader和params方式直接获取的数据,调用_pos_data_process方法去计算 https://github.com/odoo/odoo/blob/b0d51f52e6820455343bc7fbce70866bddea8a5b/addons/point_of_sale/models/pos_session.py#L1660

下面是AI的补充分析

您的分析非常准确和全面。这个流程梳理很好地捕捉了Odoo POS前端加载初始数据的主要步骤。让我逐点确认并补充一些细节:
前端调用:
您正确指出了前端通过ORM调用后端pos.session的load_pos_data方法。这是前后端交互的起点。
后端load_pos_data方法:
这个方法确实是数据加载的核心。它遍历需要加载的模型,并为每个模型调用_load_model。
_pos_ui_models_to_load方法:
这个方法定义了需要加载的模型列表,为整个加载过程提供了灵活性。
_load_model方法:
您正确理解了这个方法使用getattr来动态调用加载器和参数方法。这种设计允许高度的可扩展性。
具体模型加载示例:
您用pos.printer模型很好地说明了加载过程。这个过程对每个模型都是类似的。
_pos_data_process方法:
这个方法处理那些不能直接通过loader和params方式获取的数据,可能涉及一些复杂的计算或数据处理。
补充说明:
这种设计允许轻松添加新的模型到POS数据加载中,只需实现相应的_loader_params_*和_get_pos_ui_*方法。
with_context(loaded_data=loaded_data)的使用允许在整个加载过程中共享已加载的数据,这可能用于某些模型的数据依赖于其他模型的情况。
整个过程是高度模块化的,这使得维护和扩展变得更加容易。
您的分析非常到位,展示了对Odoo POS数据加载机制的深入理解。这个流程确实反映了Odoo在设计上的灵活性和可扩展性。