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:
@ -226,6 +226,8 @@ class ProductInboundService:
|
|||||||
'sku': material.spec_model or material.name,
|
'sku': material.spec_model or material.name,
|
||||||
'serial_number': new_stock.serial_number,
|
'serial_number': new_stock.serial_number,
|
||||||
'quantity': float(new_stock.in_quantity or 0),
|
'quantity': float(new_stock.in_quantity or 0),
|
||||||
|
# ★ 公司名决定通知哪个 Track 实例(IRIS / LICA),缺失则回落默认
|
||||||
|
'company_name': getattr(material, 'company_name', None),
|
||||||
'operator': get_current_operator(),
|
'operator': get_current_operator(),
|
||||||
})
|
})
|
||||||
return new_stock
|
return new_stock
|
||||||
|
|||||||
@ -265,6 +265,8 @@ class SemiInboundService:
|
|||||||
'sku': material.spec_model or material.name,
|
'sku': material.spec_model or material.name,
|
||||||
'serial_number': webhook_sn,
|
'serial_number': webhook_sn,
|
||||||
'quantity': float(new_stock.in_quantity or 0),
|
'quantity': float(new_stock.in_quantity or 0),
|
||||||
|
# ★ 公司名决定通知哪个 Track 实例(IRIS / LICA),缺失则回落默认
|
||||||
|
'company_name': getattr(material, 'company_name', None),
|
||||||
'operator': get_current_operator(),
|
'operator': get_current_operator(),
|
||||||
})
|
})
|
||||||
return new_stock
|
return new_stock
|
||||||
|
|||||||
@ -359,7 +359,11 @@ class OutboundService:
|
|||||||
repair.shipping_date = current_time
|
repair.shipping_date = current_time
|
||||||
|
|
||||||
# 收集 Track 联动信息(维修单带 serial_number)
|
# 收集 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(
|
new_record = TransOutbound(
|
||||||
@ -394,7 +398,11 @@ class OutboundService:
|
|||||||
raise ValueError(f"库存记录不存在 (ID: {stock_id})")
|
raise ValueError(f"库存记录不存在 (ID: {stock_id})")
|
||||||
|
|
||||||
# 收集 Track 联动信息(库存表 serial_number = Track 身份证)
|
# 收集 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(
|
new_record = TransOutbound(
|
||||||
sku=item.get('sku'),
|
sku=item.get('sku'),
|
||||||
@ -419,11 +427,11 @@ class OutboundService:
|
|||||||
db.session.commit()
|
db.session.commit()
|
||||||
|
|
||||||
# ★ 出库后通知 Track(发货出库 → Track 标记"已出库")
|
# ★ 出库后通知 Track(发货出库 → Track 标记"已出库")
|
||||||
# 仅在配置 TRACK_OUTBOUND_WEBHOOK_URL 时生效;notify_track 自身容错不阻断业务
|
# 按每条的 company_name 路由到对应实例(IRIS / LICA)。
|
||||||
|
# 这里刻意**不**显式传 url:显式 url 优先级最高,会一律打到默认实例,
|
||||||
|
# 导致 LICA 的出库永远收不到联动。notify_track 自身容错,不阻断业务。
|
||||||
try:
|
try:
|
||||||
from flask import current_app
|
for sn, src_tbl, qty, company in track_notifications:
|
||||||
outbound_url = current_app.config.get('TRACK_OUTBOUND_WEBHOOK_URL')
|
|
||||||
for sn, src_tbl, qty in track_notifications:
|
|
||||||
if not sn:
|
if not sn:
|
||||||
continue
|
continue
|
||||||
notify_track({
|
notify_track({
|
||||||
@ -432,8 +440,9 @@ class OutboundService:
|
|||||||
'serial_number': str(sn),
|
'serial_number': str(sn),
|
||||||
'quantity': float(qty or 0),
|
'quantity': float(qty or 0),
|
||||||
'outbound_type': common_data['outbound_type'],
|
'outbound_type': common_data['outbound_type'],
|
||||||
|
'company_name': company,
|
||||||
'operator': get_current_operator(),
|
'operator': get_current_operator(),
|
||||||
}, url=outbound_url)
|
})
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
import logging
|
import logging
|
||||||
logging.getLogger(__name__).warning(f"⚠️ Track 出库通知失败: {e}")
|
logging.getLogger(__name__).warning(f"⚠️ Track 出库通知失败: {e}")
|
||||||
|
|||||||
Reference in New Issue
Block a user