lookup_product() 此前写死读全局 TRACK_API_URL(指向 IRIS)。LICA 员工在 LICA 业务里扫码 → 请求打到 IRIS 库 → 查不到 → MOM 报"物料不存在"。 改用 get_current_company_filter() + resolve_track_route(…, 'api') 选实例, 复用既有工具而非另写一套。无请求/JWT 上下文时(脚本、后台任务)包一层 异常保护回落默认实例,不阻断查询。 实测(身份证 0000000000000001 只存在于 LICA 库): LICA 员工 → company_filter='LICA' → 命中 sn='0000000000000001' IRIS 员工 → company_filter='IRIS' → 未命中 改造前两者都会打到 IRIS,LICA 员工必然查不到。
77 lines
3.1 KiB
Python
77 lines
3.1 KiB
Python
# app/services/track_query_service.py
|
||
"""
|
||
Track 系统产品查询服务(拉取侧)
|
||
|
||
扫码入库时,通过 httpx GET 调用 Track 的对外查询接口 /api/v1/external/products/lookup,
|
||
根据身份证(serial_number)获取产品基础信息。
|
||
|
||
容错策略:
|
||
- 未配置 TRACK_API_URL / TRACK_WEBHOOK_KEY 时返回 None。
|
||
- 全包裹 try-except,任何异常(连接拒绝/超时/网络错误/4xx/5xx)仅记录日志,
|
||
返回 None 交给上层决定如何提示,绝不抛出异常阻断业务。
|
||
"""
|
||
import logging
|
||
|
||
import httpx
|
||
from flask import current_app
|
||
|
||
logger = logging.getLogger(__name__)
|
||
|
||
# 请求超时(秒):查询属于同步交互,超时后由上层提示失败
|
||
_QUERY_TIMEOUT = 5.0
|
||
|
||
|
||
def lookup_product(code):
|
||
"""
|
||
根据身份证(16 位 serial_number)或业务序列号查询 Track 产品信息。
|
||
|
||
返回 Track 查询接口的 data 字典(含 serial_number/external_serial/material_id/
|
||
sku/material_name/spec_model/material_type/order_no),未命中或异常返回 None。
|
||
"""
|
||
try:
|
||
api_key = (current_app.config.get('TRACK_WEBHOOK_KEY') or '').strip()
|
||
if not api_key:
|
||
logger.info("[TrackQuery] 未配置 TRACK_WEBHOOK_KEY,跳过查询")
|
||
return None
|
||
|
||
# ★ 按当前用户所属公司路由到对应的 Track 实例(IRIS / LICA)。
|
||
# 复用 get_current_company_filter():超管/跨域用户返回 None → 回落默认实例。
|
||
# 改造前这里写死读 TRACK_API_URL,LICA 员工在 LICA 业务里扫码会打到 IRIS 库,
|
||
# 查不到 → MOM 误报"物料不存在"。
|
||
from app.services.track_webhook_service import resolve_track_route
|
||
from app.utils.decorators import get_current_company_filter
|
||
try:
|
||
company = get_current_company_filter()
|
||
except Exception:
|
||
# 无请求/JWT 上下文(脚本、后台任务)时回落默认实例,不阻断查询
|
||
company = None
|
||
|
||
base_url = resolve_track_route(company, 'api')
|
||
if not base_url:
|
||
logger.info("[TrackQuery] 未解析到 Track API 地址,跳过查询")
|
||
return None
|
||
|
||
url = f'{base_url}/api/v1/external/products/lookup'
|
||
headers = {
|
||
'Content-Type': 'application/json',
|
||
# ★ 鉴权字段名必须为 X-API-Key,与 Track 接收端严格对齐
|
||
'X-API-Key': api_key,
|
||
}
|
||
resp = httpx.get(url, params={'code': code}, headers=headers, timeout=_QUERY_TIMEOUT)
|
||
if resp.status_code == 200:
|
||
data = resp.json()
|
||
track_info = (data or {}).get('data')
|
||
if track_info:
|
||
logger.info("[TrackQuery] 查询命中 code=%s", code)
|
||
return track_info
|
||
logger.info("[TrackQuery] 查询返回空数据 code=%s status=%s", code, resp.status_code)
|
||
return None
|
||
logger.info(
|
||
"[TrackQuery] 查询未命中 code=%s status=%s body=%s",
|
||
code, resp.status_code, resp.text[:200],
|
||
)
|
||
return None
|
||
except Exception as e:
|
||
logger.error("[TrackQuery] 查询失败 code=%s, err=%s", code, e)
|
||
return None
|