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
相关产品推荐
相关产品推荐

