feat(track): 入库/出库 webhook 按公司路由到对应实例

三个触发点此前都不带 company_name,无从路由:
  · product_service / semi_service:入库通知补 material.company_name
  · outbound_service:track_notifications 元组加 company(取自
    stock_record.base.company_name;维修单走 repair.base,两处
    relationship 均已定义),发送时带进 payload

出库路径同时**去掉**了显式传入的 url=TRACK_OUTBOUND_WEBHOOK_URL ——
url 参数优先级最高,保留它会让出库永远打到默认实例,company 路由形同
虚设。url 参数本身保留,需要强制覆盖时仍可用。

实测:
  LICA 入库:待仓库收货 → 已入库,IRIS 库该 SN 0 行
  LICA 出库:已入库 → 已出库,IRIS 库该 SN 0 行
  IRIS 回归:对已入库设备重发入库通知,状态幂等不变
  精确隔离:发一条 IRIS 通知,lica_backend 日志 +0 行、track_backend +19 行

注意:不做"两个实例都推一遍"——两个 Track 的 webhook key 是同一把、
两边都会鉴权通过,而 Track 按 serial_number/sku 匹配,相同型号设备会
同时命中两库,把 IRIS 的设备误标成已入库,且产生 2 倍审计与流转节点。
This commit is contained in:
yueli
2026-09-22 13:13:54 +08:00
parent 0f929468a8
commit 91db54982c
3 changed files with 20 additions and 7 deletions

View File

@ -226,6 +226,8 @@ class ProductInboundService:
'sku': material.spec_model or material.name,
'serial_number': new_stock.serial_number,
'quantity': float(new_stock.in_quantity or 0),
# ★ 公司名决定通知哪个 Track 实例IRIS / LICA缺失则回落默认
'company_name': getattr(material, 'company_name', None),
'operator': get_current_operator(),
})
return new_stock

View File

@ -265,6 +265,8 @@ class SemiInboundService:
'sku': material.spec_model or material.name,
'serial_number': webhook_sn,
'quantity': float(new_stock.in_quantity or 0),
# ★ 公司名决定通知哪个 Track 实例IRIS / LICA缺失则回落默认
'company_name': getattr(material, 'company_name', None),
'operator': get_current_operator(),
})
return new_stock

View File

@ -359,7 +359,11 @@ class OutboundService:
repair.shipping_date = current_time
# 收集 Track 联动信息(维修单带 serial_number
track_notifications.append((getattr(repair, 'serial_number', None), source_table, quantity))
# ★ 连同 company_name 一起攒起来,发送时按公司路由到对应 Track 实例
track_notifications.append((
getattr(repair, 'serial_number', None), source_table, quantity,
getattr(getattr(repair, 'base', None), 'company_name', None),
))
# 创建出库记录
new_record = TransOutbound(
@ -394,7 +398,11 @@ class OutboundService:
raise ValueError(f"库存记录不存在 (ID: {stock_id})")
# 收集 Track 联动信息(库存表 serial_number = Track 身份证)
track_notifications.append((getattr(stock_record, 'serial_number', None), source_table, quantity))
# ★ 连同 company_name 一起攒起来,发送时按公司路由到对应 Track 实例
track_notifications.append((
getattr(stock_record, 'serial_number', None), source_table, quantity,
getattr(getattr(stock_record, 'base', None), 'company_name', None),
))
new_record = TransOutbound(
sku=item.get('sku'),
@ -419,11 +427,11 @@ class OutboundService:
db.session.commit()
# ★ 出库后通知 Track发货出库 → Track 标记"已出库"
# 仅在配置 TRACK_OUTBOUND_WEBHOOK_URL 时生效notify_track 自身容错不阻断业务
# 按每条的 company_name 路由到对应实例IRIS / LICA
# 这里刻意**不**显式传 url显式 url 优先级最高,会一律打到默认实例,
# 导致 LICA 的出库永远收不到联动。notify_track 自身容错,不阻断业务。
try:
from flask import current_app
outbound_url = current_app.config.get('TRACK_OUTBOUND_WEBHOOK_URL')
for sn, src_tbl, qty in track_notifications:
for sn, src_tbl, qty, company in track_notifications:
if not sn:
continue
notify_track({
@ -432,8 +440,9 @@ class OutboundService:
'serial_number': str(sn),
'quantity': float(qty or 0),
'outbound_type': common_data['outbound_type'],
'company_name': company,
'operator': get_current_operator(),
}, url=outbound_url)
})
except Exception as e:
import logging
logging.getLogger(__name__).warning(f"⚠️ Track 出库通知失败: {e}")