You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Odoo 16的POS收据中添加自定义二维码?

问题描述

我正在做一个项目,需要基于订单信息生成二维码并打印到POS收据上。已经通过以下Python代码在pos.order模块添加了自定义字段并生成保存二维码:

from odoo import models, fields, api
import logging
try:
    import qrcode
except ImportError:
    qrcode = None
try:
    import base64
except ImportError:
    base64 = None
from io import BytesIO

_logger = logging.getLogger(__name__)

class PosOrder(models.Model):
    _inherit = "pos.order"
    revenue_counter = fields.Float()
    qr_code_image = fields.Binary()
    qr_code_value = fields.Text()

    @api.model
    def action_pos_order_paid(self):
        _logger.error("It has been paid")
        res = super(PosOrder, self).action_pos_order_paid()
        _logger.error("It has been paid 2")

        if qrcode and base64:
            qr = qrcode.QRCode(
                version=1,
                error_correction=qrcode.constants.ERROR_CORRECT_L,
                box_size=3,
                border=4,
            )
            qr.add_data("Hello -- Test")
            qr.make(fit=True)
            img = qr.make_image()

            _logger.error("Image was created")

            temp = BytesIO()

            _logger.error("Temp was created")

            img.save(temp, format="PNG")
            img.save("Qr-Code.png")
            _logger.error("Temp was initialized: ")
            _logger.error("Temp was initialized: %r ", temp.getvalue())

            qr_image = base64.b64encode(temp.getvalue())
            _logger.error("QR-Code binary was created: %r ", qr_image)

            self.qr_code_value = qr_image
            self.qr_code_image = qr_image

        return res

    @api.model
    def _order_fields(self, ui_order):
        order_values = super(PosOrder, self)._order_fields(ui_order)

        order_values['qr_code_image'] = ui_order.get('qr_code_image')
        order_values['qr_code_value'] = ui_order.get('qr_code_value')

        return order_values

同时用以下XML代码修改了收据模板:

<?xml version="1.0" encoding="UTF-8"?>
<t t-name="OrderReceipt" t-inherit="point_of_sale.OrderReceipt" t-inherit-mode="extension" owl="1">
    <xpath expr="//div[@t-if='receipt.pos_qr_code']" position="replace">
        <div>
            <br /><br />
                <div class="pos-receipt-order-data">
                    Scan me to request an invoice for your purchase.
                </div>
        </div>
    </xpath>
</t>

现在的问题是自定义二维码字段无法在收据视图中生效,请问该怎么解决?当前的实现方式是否正确?

问题分析与解决方案

一、当前实现的核心问题

  • 字段赋值无效:action_pos_order_paid里直接给self.qr_code_image赋值,此时self是模型类而非具体订单记录,不会把数据保存到数据库。
  • 收据模板未渲染二维码:现有XML只替换了文本内容,没有添加图片标签关联生成的二维码字段,而且前端收据数据里根本没有qr_code_image这个值。
  • 多余的前端字段同步:_order_fields方法是用来接收POS前端传递的字段值,当前场景是后端生成二维码,这个方法完全没必要,反而可能覆盖数据。

二、修复步骤

1. 修正Python代码的字段保存逻辑

把直接赋值改成write()方法,确保数据写入具体订单记录,同时处理Text字段的编码问题:

@api.model
def action_pos_order_paid(self):
    res = super(PosOrder, self).action_pos_order_paid()
    
    # 确保self是有效订单记录集,且依赖库存在
    if qrcode and base64 and self:
        qr = qrcode.QRCode(
            version=1,
            error_correction=qrcode.constants.ERROR_CORRECT_L,
            box_size=3,
            border=4,
        )
        # 替换成实际订单信息,比如订单编号
        qr.add_data(f"订单号: {self.name}")
        qr.make(fit=True)
        img = qr.make_image()
        
        temp = BytesIO()
        img.save(temp, format="PNG")
        qr_image_bytes = base64.b64encode(temp.getvalue())
        
        # 用write保存到数据库
        self.write({
            'qr_code_image': qr_image_bytes,
            'qr_code_value': qr_image_bytes.decode('utf-8')  # Binary转字符串存Text字段
        })
    
    return res

2. 把二维码字段同步到POS前端收据数据

添加_export_for_ui方法,将自定义字段注入到前端可用的收据数据中:

@api.model
def _export_for_ui(self, order):
    result = super(PosOrder, self)._export_for_ui(order)
    # 把二维码字段加入前端收据数据
    result['qr_code_image'] = order.qr_code_image
    return result

3. 修改XML模板渲染二维码图片

调整XML,在合适位置插入二维码图片,比如收据页脚前:

<?xml version="1.0" encoding="UTF-8"?>
<t t-name="OrderReceipt" t-inherit="point_of_sale.OrderReceipt" t-inherit-mode="extension" owl="1">
    <xpath expr="//div[@class='pos-receipt-footer']" position="before">
        <div class="pos-receipt-qr-code" t-if="receipt.qr_code_image">
            <br/>
            <div class="pos-receipt-order-data">扫描二维码查看订单详情</div>
            <!-- 渲染base64格式的图片 -->
            <img t-att-src="'data:image/png;base64,' + receipt.qr_code_image" style="width:80px;height:80px;"/>
        </div>
    </xpath>
</t>

原模板里的receipt.pos_qr_code节点大概率不存在,直接在已知节点附近插入更可靠。

4. 移除多余代码

删掉_order_fields方法,因为不需要从前端接收二维码字段,避免干扰后端生成的数据。

三、额外注意事项

  • 在模块的__manifest__.py中添加依赖声明:'external_dependencies': {'python': ['qrcode']},确保Odoo能检测到依赖。
  • 重启Odoo服务,更新模块,然后清除浏览器缓存(POS前端是单页应用,缓存会导致修改不生效)。
  • 如果使用POS离线模式,需要额外处理字段同步逻辑,但支付后生成二维码的场景一般在在线模式下运行,无需额外配置。

内容的提问来源于stack exchange,提问作者Raphael

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.18 13:17:57