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

Odoo框架中库存拣货视图集成扫码功能遇阻求助

问题分析与解决方案

你的核心问题在于:你实现的是一个独立的客户端动作(AbstractAction),这个动作只有在单独打开它的页面时才会监听扫码事件,但拣货视图是Odoo原生的表单视图,两者是完全独立的上下文,所以扫码事件无法在拣货视图内触发。


一、缺失的配置与修正方案

要让扫码功能在拣货视图内生效,你需要扩展拣货表单视图的控制器,把扫码事件监听器绑定到拣货视图的生命周期里,而不是做一个独立的Action。以下是完整的修正步骤:

1. 修改JS文件:绑定事件到拣货视图控制器

替换static/js/barcode_scanner.js的内容,改为扩展web.FormController,仅在拣货单(stock.picking)视图中监听扫码事件:

odoo.define('stock.barcode_scanner', function(require) {
    'use strict';

    var FormController = require('web.FormController');
    var core = require('web.core');

    FormController.include({
        start: function() {
            var self = this;
            // 先执行父类的start方法,确保视图初始化完成
            return this._super.apply(this, arguments).then(function() {
                // 仅在拣货单视图中绑定扫码事件
                if (self.modelName === 'stock.picking') {
                    core.bus.on('barcode_scanned', self, self._onBarcodeScanned);
                }
            });
        },

        destroy: function() {
            // 视图销毁时移除事件监听,避免内存泄漏
            if (this.modelName === 'stock.picking') {
                core.bus.off('barcode_scanned', this, this._onBarcodeScanned);
            }
            this._super.apply(this, arguments);
        },

        _onBarcodeScanned: function(barcode) {
            var self = this;
            // 临时移除监听,避免重复触发
            core.bus.off('barcode_scanned', this, this._onBarcodeScanned);
            
            // 调用后端方法,传递当前拣货单ID和扫描的条码
            this._rpc({
                model: 'stock.picking',
                method: 'product_scan',
                args: [self.model.data[self.handle].res_id, barcode],
            })
            .then(function(result) {
                if (result.action) {
                    self.do_action(result.action);
                } else if (result.warning) {
                    self.do_warn(result.warning);
                }
                // 刷新视图,显示新增的已完成产品明细
                self.reload();
                // 重新绑定事件,继续监听下一次扫码
                core.bus.on('barcode_scanned', self, self._onBarcodeScanned);
            }, function() {
                // 请求失败时重新绑定事件
                core.bus.on('barcode_scanned', self, self._onBarcodeScanned);
            });
        },
    });

    return {};
});

2. 修改Python方法:关联当前拣货单

更新models/stock_picking.py的product_scan方法,接收拣货单ID,实现添加已完成产品的逻辑:

import logging
from odoo import models, api, _

_logger = logging.getLogger(__name__)

class Picking(models.Model):
    _inherit = "stock.picking"
    _description = "Extended Picking"

    @api.model
    def product_scan(self, picking_id, barcode):
        _logger.info("Scanned barcode %s for picking ID %s", barcode, picking_id)
        # 获取当前拣货单记录
        picking = self.browse(picking_id)
        if not picking.exists():
            return {'warning': _('Target picking order not found')}
        
        # 查找匹配条码的产品
        product = self.env['product.product'].search([('barcode', '=', barcode)], limit=1)
        if not product:
            return {'warning': _('No product found with barcode: %(barcode)s', {'barcode': barcode})}
        
        # 检查拣货单中是否已有该产品的明细行
        existing_line = picking.move_line_ids.filtered(lambda ml: ml.product_id == product)
        if existing_line:
            # 增加已完成数量
            existing_line.qty_done += 1
        else:
            # 创建新的拣货明细行
            self.env['stock.move.line'].create({
                'picking_id': picking.id,
                'product_id': product.id,
                'product_uom_id': product.uom_id.id,
                'qty_done': 1,
                'location_id': picking.location_id.id,
                'location_dest_id': picking.location_dest_id.id,
            })
        
        return {'warning': _('Successfully added product: %(product_name)s', {'product_name': product.name})}

3. 移除无用的客户端动作

删除views/stock_picking_views.xml中的stock_barcode_scanner_action记录,因为我们不再需要独立的动作页面,功能直接嵌入拣货视图。


二、关于功能实现的疑问

这个功能完全可以在Odoo原生视图(表单/列表)上实现,不需要局限于独立的JS框架视图。

你之前的错误思路是把扫码功能做成了一个独立的页面动作,但Odoo的视图系统支持通过扩展控制器、视图钩子或者组件的方式,将自定义逻辑嵌入到原生视图中。只要把事件监听器绑定到目标视图的生命周期(start/destroy)里,就能在该视图的上下文内触发扫码逻辑。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.14 08:45:46