Odoo POS收据打印qweb模板 - xiaohao0576/odoo-doc GitHub Wiki

从Odoo 19.3之后, POS模块的收据qWeb xml,可以同时在后端和前端使用

关键文件是: addons/point_of_sale/static/src/app/utils/convert_python_template.js

以后让AI帮忙修改POS收银小票的qWeb时,需要注意以下事项

  • 先阅读文件: addons/point_of_sale/static/src/app/utils/convert_python_template.js ,注意哪些qWeb指令才是前端和后端都合法的语法
  • 使用后端和前端通用的qWeb语法,通过继承扩展的方式,去修改现有的收据模板
  • qWeb模板中用到的数据,需要分别在前端js和后端python中都实现一次。
  • 前端的数据生成入口在: addons/point_of_sale/static/src/app/utils/printer/generate_printer_data.js
  • 后端的数据生成入口在: addons/point_of_sale/receipt/pos_order_receipt.py
  • 在写qWeb定位节点的时候,使用xpath是最灵活的,但不是唯一的选择,还可以使用field或者用tag名定位,见文件: odoo/tools/template_inheritance.py , 具体函数: def locate_node(arch, spec):
  • 在后端的qweb中,可以使用request,json,quote_plus, image_data_uri等对象,但前端js环境不能使用这些函数。见源文件: odoo/addons/base/models/ir_qweb.py , 具体函数: def _prepare_environment(self, values):

locate_node函数源码

def locate_node(arch, spec):
    """ Locate a node in a source (parent) architecture.

    Given a complete source (parent) architecture (i.e. the field
    `arch` in a view), and a 'spec' node (a node in an inheriting
    view that specifies the location in the source view of what
    should be changed), return (if it exists) the node in the
    source view matching the specification.

    :param arch: a parent architecture to modify
    :param spec: a modifying node in an inheriting view
    :return: a node in the source matching the spec
    """
    if spec.tag == 'xpath':
        expr = spec.get('expr')
        if expr is None:
            raise ValidationError(_lt("Missing 'expr' attribute in xpath specification"))
        try:
            xPath = etree.ETXPath(expr)
        except etree.XPathSyntaxError as e:
            raise ValidationError(_lt("Invalid Expression while parsing xpath “%s”", expr)) from e
        nodes = xPath(arch)
        return nodes[0] if nodes else None
    elif spec.tag == 'field':
        # Only compare the field name: a field can be only once in a given view
        # at a given level (and for multilevel expressions, we should use xpath
        # inheritance spec anyway).
        for node in arch.iter('field'):
            if node.get('name') == spec.get('name'):
                return node
        return None

    for node in arch.iter(spec.tag):
        if all(node.get(attr) == spec.get(attr) for attr in spec.attrib if attr != 'position'):
            return node
    return None