feat(webhook): MOM 回调的部门归属分流 —— 只放行 IRIS 与空白值
MOM 现在同时对接 IRIS 与 LICA 两个 Track 实例,按载荷里的 company_name 分流。
实现:
· MomInboundPayload / MomOutboundPayload 补 company_name 字段
(不补的话会被 Pydantic 静默丢弃,分流无从谈起)
· 新增 _is_foreign_company(),在**鉴权之后、匹配产品之前**拦截
· 拦截时返回 200 + matched=False + reason="ignored_company" —— 与「未命中」
保持同一契约,避免 MOM 侧把它当成故障反复重推
⚠️ 判定刻意做成「只排除已知的外来公司」(黑名单),而非「白名单只认 IRIS」:
MOM 在无法确定公司归属时会回落到扁平配置,该配置指向本实例 —— 这类消息的
company_name 会是空 / 缺失。若按白名单把空白也拒掉,它们就彻底丢了:MOM
那边已收到 200、认为投递成功,不会再重推。同理,未见过的新值也一律照常处理。
reason 的取值 "ignored_company" 与 LICA 实例(~/track-lica)保持一致 —— MOM 侧
不解析它,但排查时两边日志要对着看,字段名不一致会白白浪费时间。
实测:
· LICA 载荷 → {"ok":true,"matched":false,"reason":"ignored_company"}
· IRIS/空串/缺失 → 照常处理
· 无 X-API-Key 仍返回 401(鉴权未被绕过)
This commit is contained in:
@ -36,6 +36,7 @@ class MomInboundPayload(BaseModel):
|
||||
event: str | None = None # 事件名,如 inbound.created / outbound.revoked
|
||||
action: str | None = None # 显式动作指令,如 revoke_outbound
|
||||
source_table: str | None = None # stock_product / stock_semi
|
||||
company_name: str | None = None # 目标公司(IRIS / LICA),MOM 据此分流到不同 Track 实例
|
||||
|
||||
|
||||
# 「撤回出库」信号词 —— 只在 action / event 里做子串匹配。
|
||||
@ -44,6 +45,28 @@ class MomInboundPayload(BaseModel):
|
||||
_OUTBOUND_REVOKE_TOKENS = ("revoke", "rollback", "revert", "cancel")
|
||||
|
||||
|
||||
# ── 公司归属分流 ──────────────────────────────────────────────────────────
|
||||
# MOM 现在会在载荷里带 company_name,同一套物理库可能同时向多个 Track 实例
|
||||
# (IRIS / LICA)回调。本实例服务的是 IRIS,故只放行 IRIS 与空白值。
|
||||
#
|
||||
# ⚠️ 判定刻意做成「只排除已知的外来公司」,而非「白名单只认 IRIS」:
|
||||
# MOM 在无法确定公司归属时会回落到扁平配置,该配置指向本实例 —— 这类
|
||||
# 消息的 company_name 会是空 / 缺失。若此处按白名单把空白也拒掉,它们
|
||||
# 就彻底丢了:MOM 那边已收到 200、认为投递成功,不会再重推。
|
||||
# 同理,未见过的新值(不是 IRIS 也不是 LICA)也一律照常处理。
|
||||
_FOREIGN_COMPANIES = {"LICA"}
|
||||
|
||||
|
||||
def _is_foreign_company(company_name: str | None) -> bool:
|
||||
"""载荷是否属于本实例不该处理的其它公司。
|
||||
|
||||
返回 True 表示应原样忽略(仍回 200,避免 MOM 反复重推)。
|
||||
"""
|
||||
# 大小写 / 首尾空白都容忍:MOM 侧常量书写方式未必冻结,误判的代价是
|
||||
# 一条消息被错误地当成本公司处理(有唯一匹配约束,最坏是 matched=False)。
|
||||
return (company_name or "").strip().upper() in _FOREIGN_COMPANIES
|
||||
|
||||
|
||||
def _is_outbound_revoke(payload: MomInboundPayload) -> bool:
|
||||
"""payload 是否携带**显式**的撤回出库信号。
|
||||
|
||||
@ -136,12 +159,20 @@ async def mom_inbound_webhook(
|
||||
- 常规入库:用 serial_number(优先)或 sku 匹配「当前位于 virtual_warehouse」
|
||||
的产品,命中则标记"已实收"(overall_status=已入库 + 记录 task_logs)。
|
||||
- 撤回出库:MOM 把误出库的设备物理回滚到仓库 → 本接口强制执行特权回滚。
|
||||
- 公司归属:company_name 明确写着其它公司(LICA)时原样忽略;空白 / 缺失
|
||||
一律照常处理(见 _is_foreign_company 的说明)。
|
||||
- 未命中返回 200(MOM 可能操作了非 Track 生产的物料,直接忽略)。
|
||||
"""
|
||||
# ── 鉴权 ──
|
||||
if not settings.TRACK_WEBHOOK_KEY or x_api_key != settings.TRACK_WEBHOOK_KEY:
|
||||
raise HTTPException(status_code=401, detail="Unauthorized: invalid X-API-Key")
|
||||
|
||||
# ── 公司归属:不是本实例的消息原样忽略(仍回 200,避免 MOM 当作失败而重推) ──
|
||||
# ⚠️ 键名 reason / 取值 "ignored_company" 与 LICA 实例(~/track-lica)保持一致:
|
||||
# MOM 侧不解析它,但排查时两边日志对着看,字段名不一致会白白浪费时间。
|
||||
if _is_foreign_company(payload.company_name):
|
||||
return {"ok": True, "matched": False, "reason": "ignored_company"}
|
||||
|
||||
explicit_revoke = _is_outbound_revoke(payload)
|
||||
|
||||
# ── 匹配产品 ──
|
||||
@ -329,6 +360,7 @@ class MomOutboundPayload(BaseModel):
|
||||
sku: str | None = None # 规格型号 spec_model(serial 缺失时的兜底匹配)
|
||||
operator: str | None = None # 出库操作人(写入 task_logs.operator_id)
|
||||
outbound_time: datetime | None = None # 出库时间
|
||||
company_name: str | None = None # 目标公司(IRIS / LICA),MOM 据此分流到不同 Track 实例
|
||||
|
||||
|
||||
@router.post("/mom-outbound")
|
||||
@ -342,12 +374,20 @@ async def mom_outbound_webhook(
|
||||
- 鉴权:Header X-API-Key 必须等于环境变量 TRACK_WEBHOOK_KEY。
|
||||
- 用 serial_number(优先)或 sku 匹配"在仓库/已入库"的产品;
|
||||
命中则标记"已出库"(overall_status=已出库 + status=OUTBOUND + 记录 task_logs)。
|
||||
- 公司归属:company_name 明确写着其它公司(LICA)时原样忽略;空白 / 缺失
|
||||
一律照常处理(见 _is_foreign_company 的说明)。
|
||||
- 未命中返回 200(MOM 出库的可能是非 Track 生产的物料,直接忽略)。
|
||||
"""
|
||||
# ── 鉴权 ──
|
||||
if not settings.TRACK_WEBHOOK_KEY or x_api_key != settings.TRACK_WEBHOOK_KEY:
|
||||
raise HTTPException(status_code=401, detail="Unauthorized: invalid X-API-Key")
|
||||
|
||||
# ── 公司归属:不是本实例的消息原样忽略(仍回 200,避免 MOM 当作失败而重推) ──
|
||||
# ⚠️ 键名 reason / 取值 "ignored_company" 与 LICA 实例(~/track-lica)保持一致:
|
||||
# MOM 侧不解析它,但排查时两边日志对着看,字段名不一致会白白浪费时间。
|
||||
if _is_foreign_company(payload.company_name):
|
||||
return {"ok": True, "matched": False, "reason": "ignored_company"}
|
||||
|
||||
# ── 按 serial_number(优先)或 sku 匹配"在仓库/已入库"的产品 ──
|
||||
product = None
|
||||
where_cond = or_(
|
||||
|
||||
Reference in New Issue
Block a user