InvenTree TME 条码插件实战指南:自动识别 TME 产品条码的集成方案
【免费下载链接】InvenTreeOpen Source Inventory Management System项目地址: https://gitcode.com/GitHub_Trending/in/InvenTree
InvenTree 是一个开源库存管理系统,其内置插件机制允许通过扫描供应商条码自动识别入库物料。本文聚焦其中的TME Barcode Plugin(TME 条码插件),讲解它如何解析 TME 官网(tme.eu)产品包装上的 QR Code 与 DataMatrix 条码、将条码字段映射为 InvenTree 内部数据、并据此匹配供应商零件与采购订单。读完本文,你将掌握该插件的激活配置流程、底层条码解析与匹配原理、以及可验证的测试用例,能够在自己的 InvenTree 实例中复现这套"扫码收货"工作流。
插件功能定位
TME Barcode Plugin 为 TME 产品提供条码支持。当从 TME 收到物料时,扫描产品包装上的条码即可在 InvenTree 中自动识别该产品,无需手动录入零件编号、订单号等信息。
该插件属于 InvenTree 的内置供应商条码插件家族(与 DigiKey、Mouser、LCSC 同类),其设计遵循一个关键约束——Barcode Plugins 索引文档 明确指出:
这些插件只处理条码内的数据本身,不与其供应商网站或 API 进行任何集成。条码数据用于根据插件设置匹配 InvenTree 中已存在的产品。
也就是说,扫描识别是纯离线、纯本地数据匹配的:条码里有什么字段,插件就解析什么字段,再拿着这些字段去数据库里查找对应的SupplierPart(供应商零件)。
从源码看,插件的类定义位于 tme.py,完整声明如下:
class TMEPlugin(SupplierBarcodeMixin, SettingsMixin, InvenTreePlugin): NAME = 'TMEBarcodePlugin' SLUG = 'tmeplugin' TITLE = _('Supplier Integration - TME') DESCRIPTION = _('Provides support for scanning TME barcodes') VERSION = '1.0.1' AUTHOR = _('InvenTree contributors')它同时继承了三个基类:InvenTreePlugin(插件基础)、SettingsMixin(提供可配置设置项)以及SupplierBarcodeMixin(提供供应商条码解析与匹配的默认实现)。
底层架构:SupplierBarcodeMixin 解析管线
官方文档说明该插件实现了 BarcodeMixin mixin 以提供自定义条码支持。在源码中,SupplierBarcodeMixin定义于 mixins.py,它继承自BarcodeMixin,职责是"为供应商条码的扫描函数提供默认实现",自定义供应商条码插件只需实现extract_barcode_fields一个方法。
SupplierBarcodeMixin定义了一套标准字段名常量,作为各供应商条码字段与 InvenTree 内部数据的统一中间语言:
| 常量 | 内部字段名 | 含义 |
|---|---|---|
CUSTOMER_ORDER_NUMBER | customer_order_number | 客户订单号 |
SUPPLIER_ORDER_NUMBER | supplier_order_number | 供应商订单号 |
PACKING_LIST_NUMBER | packing_list_number | 装箱单号 |
SHIP_DATE | ship_date | 发货日期 |
CUSTOMER_PART_NUMBER | customer_part_number | 客户零件号 |
SUPPLIER_PART_NUMBER | supplier_part_number | 供应商零件号(SKU) |
PURCHASE_ORDER_LINE | purchase_order_line | 采购订单行 |
QUANTITY | quantity | 数量 |
DATE_CODE | date_code | 日期代码 |
LOT_CODE | lot_code | 批次代码 |
COUNTRY_OF_ORIGIN | country_of_origin | 原产国 |
MANUFACTURER | manufacturer | 制造商 |
MANUFACTURER_PART_NUMBER | manufacturer_part_number | 制造商零件号(MPN) |
整个条码处理管线分为两层:
- 解析层:
extract_barcode_fields(barcode_data)将原始条码字符串解析成上述标准字段字典; - 匹配层:
get_supplier_part()、get_manufacturer_part()等方法基于解析出的字段,结合插件配置的供应商,到数据库中查询唯一的匹配记录。
TME 插件只在解析层做了高度定制(因为它面对的条码格式特殊),匹配层则完全复用 mixin 的通用实现。
激活与供应商关联配置
第一步:激活插件
TME 插件是一个可选(optional)插件,默认未启用,必须先在 InvenTree 管理后台(admin center)中启用。官方文档中的激活说明如下:
This plugin is anoptionalplugin, and must be enabled in the InvenTree admin center.
在测试代码 test_supplier_barcodes.py 中,也体现了这一前提——所有扫描测试的第一步都是通过插件注册表将插件状态置为启用:
registry.set_plugin_state('tmeplugin', True)其中'tmeplugin'正是TMEPlugin.SLUG。只有启用后,条码扫描接口才会把条码数据路由给该插件处理。
第二步:在插件设置中指定供应商
激活后,用户必须在插件设置里指定该插件关联的供应商(supplier):从设置页的下拉列表中选择对应的供应商条目。
在源码层面,这个设置项由SettingsMixin的SETTINGS字典声明:
DEFAULT_SUPPLIER_NAME = 'TME' SETTINGS = { 'SUPPLIER_ID': { 'name': _('Supplier'), 'description': _("The Supplier which acts as 'TME'"), 'model': 'company.company', 'model_filters': {'is_supplier': True}, } }关于SUPPLIER_ID这个设置项,需要注意三点:
model: 'company.company':设置值关联到公司(Company)模型;model_filters: {'is_supplier': True}:下拉列表只展示被标记为"供应商"(is_supplier=True)的公司,避免误选普通客户或制造商;- 匹配隔离:插件只会在这个供应商的范围内查找
SupplierPart,从而确保不同供应商的同名 SKU 互不干扰。
自动猜测供应商的兜底逻辑
SupplierBarcodeMixin.get_supplier()还实现了自动猜测逻辑(mixins.py):如果SUPPLIER_ID未设置,它会用DEFAULT_SUPPLIER_NAME = 'TME'做名称模糊匹配(name__icontains),且要求is_supplier=True;只有当匹配到的供应商恰好只有一个时,才会自动写入SUPPLIER_ID并返回该供应商,否则返回None。这个兜底逻辑降低了一开始就手动指定供应商的配置负担。
支持的 TME 条码格式与字段映射
TME 插件最核心的技术价值在于extract_barcode_fields(),它同时支持三种条码形态,并按优先级依次判定(tme.py):
def extract_barcode_fields(self, barcode_data: str) -> dict[str, str]: barcode_fields = {} if self.TME_IS_QRCODE_REGEX.fullmatch(barcode_data): # 1) TME 自定义 QR Code 格式 for item in barcode_data.split(' '): if ':' in item: key, value = item.split(':') if key in self.TME_QRCODE_FIELDS: barcode_fields[self.TME_QRCODE_FIELDS[key]] = value elif self.TME_IS_OLD_BARCODE2D_REGEX.fullmatch(barcode_data): # 2) TME 旧版 2D 条码格式 for item in barcode_data.split(' '): for k, v in self.ecia_field_map().items(): if item.startswith(k): barcode_fields[v] = item[len(k):] else: # 3) 标准 ECIA / ISO-IEC 15434 2D 条码 barcode_fields = self.parse_ecia_barcode2d(barcode_data) # 订单号特殊处理 if SupplierBarcodeMixin.SUPPLIER_ORDER_NUMBER in barcode_fields: order_number = barcode_fields[SupplierBarcodeMixin.SUPPLIER_ORDER_NUMBER] order_number = order_number.split('/')[0] barcode_fields[SupplierBarcodeMixin.SUPPLIER_ORDER_NUMBER] = order_number return barcode_fields格式一:TME 自定义 QR Code
TME 新版产品标签使用自定义 QR Code,典型内容如下(来自测试用例TME_QRCODE):
QTY:1 PN:WBP-302 PO:19361337/1 CPO:PO-2023-06-08-001337 MFR:WISHERENTERPRI SE MPN:WBP-302 RoHS https://www.tme.eu/details/WBP-302判断依据是正则TME_IS_QRCODE_REGEX(([^\s:]+:[^\s:]+\s+)+(\S+(\s|$)+)+)。解析时按空格切分,遇到含:的字段段再做键值拆分,最终通过TME_QRCODE_FIELDS映射为 InvenTree 标准字段:
| TME 条码字段 | 映射到的标准字段 | 含义 |
|---|---|---|
PN | supplier_part_number | 供应商零件号(SKU) |
CPO | customer_order_number | 客户订单号 |
PO | supplier_order_number | 供应商订单号 |
MPN | manufacturer_part_number | 制造商零件号 |
QTY | quantity | 数量 |
注意:测试样本中的RoHS、MFR、URL 等非映射字段会被安全忽略,不会进入结果字典,也不会导致解析失败。
格式二:TME 旧版 2D 条码
TME 旧款包装使用另一种 2D 条码,典型内容如下(来自测试用例TME_DATAMATRIX_CODE):
PWBP-302 1PMPNWBP-302 Q1 K19361337/1该格式由正则TME_IS_OLD_BARCODE2D_REGEX((([^\s]+)(\s+|$))+)识别(会匹配几乎所有空格分隔内容,所以它排在 QR Code 判定之后,作为第二优先级)。解析逻辑与 ECIA 格式共用同一张字段映射表(ecia_field_map()):逐项检查每个空格分隔的字段段是否以映射表中的前缀开头,若命中则去掉前缀得到字段值。
对照 ECIA 映射表(完整定义见 mixins.py),上面的样本可拆解为:
PWBP-302→ 前缀P→supplier_part_number = WBP-3021PMPNWBP-302→ 前缀1P→manufacturer_part_number = MPNWBP-302Q1→ 前缀Q→quantity = 1K19361337/1→ 前缀K→customer_order_number = 19361337/1
格式三:标准 ECIA / ISO-IEC 15434 2D 条码
若前两种正则都不匹配,插件会回退到行业通用的 ECIA 规范 2D 条码解析(parse_ecia_barcode2d),该规范参考 ECIA 官方文档,同时支持 ISO/IEC 15434 格式。这类条码以固定头[)>\x1e06\x1d开始、以\x1e\x04结尾,字段之间以\x1d分隔。
标准 ECIA 字段前缀映射表(ecia_field_map())如下,这也是 TME 旧版条码解析所复用的同一张表:
| 条码前缀 | 标准字段 |
|---|---|
K | customer_order_number |
1K | supplier_order_number |
11K | packing_list_number |
6D | ship_date |
9D/10D | date_code |
4K/14K | purchase_order_line |
P/30P | supplier_part_number |
1P | manufacturer_part_number |
1T | lot_code |
4L | country_of_origin |
1V | manufacturer |
Q | quantity |
订单号的归一化处理
无论走哪条解析分支,extract_barcode_fields()最后都会对supplier_order_number(供应商订单号)做一次归一化:取其/之前的部分。例如样本中的PO:19361337/1会被归一化为19361337。这样做的目的是剥离 TME 订单号中形如/1的订单行后缀,使订单号能与 InvenTree 中采购订单的supplier_reference精确对齐。
条码匹配与扫码收货流程
供应商零件匹配(get_supplier_part)
解析出标准字段后,SupplierBarcodeMixin.get_supplier_part()负责完成数据库匹配(mixins.py),其匹配策略为:
- 必须至少具备 SKU(
supplier_part_number)或 MPN(manufacturer_part_number),否则直接返回None; - 若插件配置了供应商,则先按
supplier过滤SupplierPart,实现供应商间隔离; - 若有 SKU,则按
SKU精确过滤; - 若过滤后仍有多个结果且存在 MPN,则进一步按
manufacturer_part__MPN收窄范围; - 要求唯一匹配——只有恰好命中一条
SupplierPart时才返回,多匹配或零匹配都返回None。
扫码接口与采购收货
SupplierBarcodeMixin将上述能力封装为scan()/scan_receive_item()等默认扫描实现。在 InvenTree 中,前端扫码后请求条码扫描 API(api-barcode-scan),插件注册表会按顺序让已启用的供应商条码插件尝试解析;匹配成功后返回插件名、供应商零件乃至库存项信息。
当条码包含采购订单信息(如 TME 条码中的PO字段)时,还可走api-barcode-po-receive流程直接按采购订单收货入库。测试类SupplierBarcodePOReceiveTests(test_supplier_barcodes.py)覆盖了该流程的关键规则:
- 采购订单必须已下达(placed),否则拒绝收货并提示 "received against an order marked as...";
- 同一物料不可重复收货,第二次会返回
Item has already been received; - 库存入库位置按"请求指定位置 → 订单行目标位置 → 零件默认位置"的优先级解析;
- 条码缺失数量字段时,接口返回
action_required并预填剩余待收数量; - 用户需具备
purchase_order.add角色权限,否则返回 403。
测试验证:插件行为的可靠依据
TME 插件的解析行为有明确的自动化测试保障,位于 test_supplier_barcodes.py:
test_tme_qrcode:POSTTME_QRCODE到扫描接口,断言响应中的plugin为TMEBarcodePlugin,并匹配到SKU = 'WBP-302'的供应商零件;test_tme_barcode2d:POSTTME_DATAMATRIX_CODE(旧版 2D 条码样本),同样解析成功并匹配WBP-302。
测试数据里两种条码格式都能解析出相同的 SKU,这验证了extract_barcode_fields中"QR Code 优先、旧 2D 次之、ECIA 兜底"的多分支设计的正确性。你可以直接复用这两个样本(QTY:1 PN:WBP-302 PO:19361337/1 ...与PWBP-302 1PMPNWBP-302 Q1 K19361337/1)在自己的实例上验证插件是否正常工作。
集成前提与限制
- 前置数据:TME 插件只做条码解析与本地匹配,不会自动创建供应商、供应商零件或采购订单。扫描前必须在 InvenTree 中预先创建好 TME 供应商(供应商文档)、对应的
SupplierPart(SKU 需与条码中的PN一致)以及已下达的采购订单。 - 无网络集成:插件不访问 TME API,条码中的 URL 等字段仅作为文本出现,不会被请求或校验。
- 启用状态:插件必须先在管理后台启用,并在设置中关联供应商(或满足自动猜测条件),否则扫描不会命中该插件。
小结
TME Barcode Plugin 是 InvenTree"扫码收货"体系中的一块拼图,它用约七十行核心逻辑(tme.py)优雅地兼容了 TME 自定义 QR Code、旧版 2D 条码与行业标准 ECIA 条码三种格式,再借助SupplierBarcodeMixin的通用匹配层完成供应商零件与采购订单的自动关联。理解这套"解析字段 → 标准字段映射 → 数据库唯一匹配"的管线,不仅能帮你正确配置 TME 扫描流程,也能为开发其他供应商条码插件提供直接参考——只需继承SupplierBarcodeMixin并实现自己的extract_barcode_fields即可。
【免费下载链接】InvenTreeOpen Source Inventory Management System项目地址: https://gitcode.com/GitHub_Trending/in/InvenTree
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考