很多团队上线 POS 时,对扫码的期待往往只有一句话:
扫一下,能出商品就算成功。
这在业务上太粗了。Odoo POS 的扫码不是“查一个 product.barcode”,而是一套“先解析语义、再决定动作”的规则系统。 也正因为如此,扫码问题经常不是商品没建出来,而是条码被解析成了错误的类型,或者压根没有进入正确的 parser。
先说结论:Odoo POS 的扫码链路分两层——先由 barcode nomenclature 解析“这串码代表什么”,再由前端回调决定“拿它干什么”。 识别失败时,真正要看的不是商品主数据本身,而是规则、GS1 兼容性、fallback parser、包装条码与前端注册的动作映射。
第一层不是找商品,而是先判定“条码语义”
在 static/src/app/services/barcode_reader_service.js 里,POS 收到扫描结果后不会直接搜 product.product。它先交给 BarcodeParser.parse_barcode(),把这串码解释成一个“类型化结果”。
在 models/barcode_rule.py 里,POS 扩展了多种条码类型,包括:
weight:称重商品;price:带价商品;discount:带折扣商品;client:客户;cashier:收银员。
也就是说,同样是扫一个码,Odoo 先决定它是“商品条码”还是“客户码/员工码/动作码”,再决定回调到哪个业务处理器。 这就是为什么有时你明明扫的是一串合法数字,却不会加商品,而是切换客户、登录员工,或者直接弹未知条码警告。
GS1 不是“高级点的条码”,而是可携带业务数据的编码结构
很多零售团队会碰到一个现象:
- 某些秤码一扫就能带出重量;
- 某些价签一扫就自动带出价格;
- 某些码明明很长,POS 却提示不兼容。
原因通常在 GS1。
在 barcode_reader_service.js 中,Odoo 对 GS1 条码有单独判断:如果解析结果是数组,但里面没有 product 元素,就会抛出 GS1BarcodeError。这背后的意思很明确:GS1 可以带很多段信息,但至少得先把“商品是谁”说清楚。
所以“扫码长度很长”不代表可用;“供应商说这是 GS1”也不代表 Odoo 就一定能吃下。只要核心应用标识和规则没对齐,POS 就会把它视为不兼容格式。
fallback nomenclature 的作用,不是补商品,而是补解析器
这点特别容易被误解。
源码里如果主 parser 抛出 GS1BarcodeError,而 session 里配置了 fallback_nomenclature_id,POS 会再用一套 fallback parser 重试。注意,它补的不是商品库,而是“第二套条码解释规则”。
这意味着 fallback 更适合解决下面这类混扫场景:
- 门店同时存在 GS1 秤码和老式内部价签;
- 总部推 GS1,但部分旧设备还在吐 legacy barcode;
- 同一收银台既扫商品,也扫会员卡和员工卡。
如果你的问题本质上是“条码没建到商品上”,配置 fallback 并不会救你;但如果问题是“这串码根本没被主 parser 正确解释”,fallback 往往就是关键。
包装条码与嵌入式数量,为什么常常被误诊成库存问题
pos_store.js 和 pos_order_line.js 里有一条很容易被忽视的路径:POS 不只认商品主条码,也会认 product.uom 上的包装条码。源码甚至会根据包装对应的 UoM 因子,自动换算出数量。
这就解释了一个现场高频坑:
一扫不是“加一个”,而是“加一箱 / 一包 / 一托盘”。
很多人第一反应去查库存单位,实际上应该先查:
- 这把枪扫到的是商品主条码,还是包装条码;
- 包装条码绑定的 UoM 因子是不是错了;
- 门店是不是把“外箱码”当成“单品码”贴在了前台。
所以数量异常不一定是 stock bug,很可能只是条码语义被设计成了包装级别。
为什么有的扫描会直接改数量、改金额、改折扣
因为 POS 支持“嵌入式业务量”。
在默认条码模式里,weight / price / discount 三类规则都不是简单查主数据,而是把条码里某一段解析成业务值,再应用到订单行。这也是称重、生鲜、预打折标贴能在前台成立的原因。
但它也带来一个边界:如果商品、规则和位数定义没完全一致,POS 并不是“差一点也能凑合”,而是会稳定地产生错误数量或错误金额。 这类错单往往最危险,因为系统不会报错,只会“算错但看起来很顺”。
最容易踩的四个误区
误区一:未知条码就等于商品没建
不对。也可能是条码被解析成了一个没有注册回调的类型,或者压根没命中当前 nomenclature。
误区二:GS1 报不兼容时,补个商品条码就能解决
不对。报错说明 parser 没把它解释成一个合法 GS1 结构,先看规则而不是先补主数据。
误区三:fallback 是“兜底搜索”
不是。它是兜底解析器,不是兜底商品查询。
误区四:称重码错数一定是秤没校准
不一定。很多时候是 Odoo 这边的位数、前缀、decimal 规则或包装 UoM 定义不匹配。
实战排错顺序,建议按这五步走
遇到 POS 扫码异常,不要一上来重建商品。更高效的顺序是:
- 先确认 session 正在使用哪套 nomenclature,有没有配置 fallback;
- 再判断条码应属哪一类:product、client、cashier、weight、price、discount;
- 检查是不是包装条码而非商品主条码,尤其是整箱销售场景;
- 如果是 GS1 或秤码,核对前缀、位数、decimal 规则与样码;
- 最后再回头看商品、客户、员工主数据是否存在且已加载进 POS。
这个顺序的意义在于:先排“解释器”,再排“数据”。因为在 Odoo POS 里,绝大多数扫码怪问题,本质都不是数据库里没有这件商品,而是系统把这串码理解成了别的东西,或者根本没理解。
你真正要管的,不是扫码枪,而是条码语义治理
门店现场往往把扫码问题归咎于枪、浏览器或网络,但从 Odoo 源码看,扫码链路真正的稳定性来自三件事:
- 条码规则有没有统一;
- 新旧编码体系有没有清晰切换;
- 包装、称重、折扣、客户、员工条码是否互不冲突。
所以 POS 扫码项目做得好不好,看的不是“能不能扫”,而是:同一把枪扫进来的每一串码,是否都只有一种明确、可预期的业务含义。
这才是 Odoo POS 条码体系真正的深水区。
DISCUSSION
评论区