# 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: base_url = (current_app.config.get('TRACK_API_URL') or '').strip() api_key = (current_app.config.get('TRACK_WEBHOOK_KEY') or '').strip() if not base_url: logger.info("[TrackQuery] 未配置 TRACK_API_URL,跳过查询") return None if not api_key: logger.info("[TrackQuery] 未配置 TRACK_WEBHOOK_KEY,跳过查询") 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