fix: accept legacy Huihui callback path for org orders
This commit is contained in:
@@ -847,6 +847,10 @@ async def huihui_org_payment_notify(request: Request, db: Session = Depends(get_
|
|||||||
payload = await _signed_huihui_notice(
|
payload = await _signed_huihui_notice(
|
||||||
request, secret_name="HUIHUI_ORG_CALLBACK_SECRET", minimum_length=16,
|
request, secret_name="HUIHUI_ORG_CALLBACK_SECRET", minimum_length=16,
|
||||||
)
|
)
|
||||||
|
return _process_huihui_org_notice(payload, db)
|
||||||
|
|
||||||
|
|
||||||
|
def _process_huihui_org_notice(payload: dict, db: Session):
|
||||||
order_no = str(payload.get("orderNo") or "").strip()
|
order_no = str(payload.get("orderNo") or "").strip()
|
||||||
payment_no = str(payload.get("paymentNo") or "").strip()
|
payment_no = str(payload.get("paymentNo") or "").strip()
|
||||||
status = str(payload.get("status") or "").upper()
|
status = str(payload.get("status") or "").upper()
|
||||||
@@ -926,6 +930,16 @@ async def huihui_org_payment_notify(request: Request, db: Session = Depends(get_
|
|||||||
@router.post("/token/payment/huihui/virtual/notify")
|
@router.post("/token/payment/huihui/virtual/notify")
|
||||||
async def huihui_virtual_payment_notify(request: Request, db: Session = Depends(get_db)):
|
async def huihui_virtual_payment_notify(request: Request, db: Session = Depends(get_db)):
|
||||||
"""Server-to-server virtual-payment notice using the Huihui HMAC contract."""
|
"""Server-to-server virtual-payment notice using the Huihui HMAC contract."""
|
||||||
|
# Older Huihui integrations still post organization recharge notices to this
|
||||||
|
# path. Only use the organization key when no virtual-payment key exists;
|
||||||
|
# the organization handler independently checks the order's provider.
|
||||||
|
if len(os.getenv("HUIHUI_VIRTUAL_CALLBACK_SECRET", "").strip()) < 32 and len(
|
||||||
|
os.getenv("HUIHUI_ORG_CALLBACK_SECRET", "").strip()
|
||||||
|
) >= 16:
|
||||||
|
payload = await _signed_huihui_notice(
|
||||||
|
request, secret_name="HUIHUI_ORG_CALLBACK_SECRET", minimum_length=16,
|
||||||
|
)
|
||||||
|
return _process_huihui_org_notice(payload, db)
|
||||||
payload = await _signed_huihui_notice(
|
payload = await _signed_huihui_notice(
|
||||||
request, secret_name="HUIHUI_VIRTUAL_CALLBACK_SECRET", minimum_length=32,
|
request, secret_name="HUIHUI_VIRTUAL_CALLBACK_SECRET", minimum_length=32,
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -111,17 +111,23 @@ def test_huihui_org_callback_verifies_provider_before_granting_points(authorizat
|
|||||||
"productId": "Basic", "userId": context["owner"].huihui_user_id,
|
"productId": "Basic", "userId": context["owner"].huihui_user_id,
|
||||||
}
|
}
|
||||||
|
|
||||||
def send(body_payload, *, signature=True):
|
def send(body_payload, *, signature=True, callback_path=path):
|
||||||
body = json.dumps(body_payload, separators=(",", ":")).encode()
|
body = json.dumps(body_payload, separators=(",", ":")).encode()
|
||||||
headers = _huihui_virtual_headers(secret, body) if signature else {"X-Huihui-Signature": "bad"}
|
headers = _huihui_virtual_headers(secret, body) if signature else {"X-Huihui-Signature": "bad"}
|
||||||
return client.post(path, content=body, headers=headers)
|
return client.post(callback_path, content=body, headers=headers)
|
||||||
|
|
||||||
with patch.dict(os.environ, {"HUIHUI_ORG_CALLBACK_SECRET": secret}), patch(
|
with patch.dict(os.environ, {
|
||||||
|
"HUIHUI_ORG_CALLBACK_SECRET": secret,
|
||||||
|
"HUIHUI_VIRTUAL_CALLBACK_SECRET": "",
|
||||||
|
}), patch(
|
||||||
"routers.tokens.HuihuiOrgPaymentClient"
|
"routers.tokens.HuihuiOrgPaymentClient"
|
||||||
) as client_factory:
|
) as client_factory:
|
||||||
provider = client_factory.return_value
|
provider = client_factory.return_value
|
||||||
provider.get_order.return_value = provider_data
|
provider.get_order.return_value = provider_data
|
||||||
assert send(payload, signature=False).status_code == 401
|
assert send(payload, signature=False).status_code == 401
|
||||||
|
legacy_path = "/api/token/payment/huihui/virtual/notify"
|
||||||
|
assert send(payload, signature=False, callback_path=legacy_path).status_code == 401
|
||||||
|
assert send({**payload, "orderNo": "unknown"}, callback_path=legacy_path).status_code == 404
|
||||||
assert send({**payload, "amountCents": 99}).status_code == 422
|
assert send({**payload, "amountCents": 99}).status_code == 422
|
||||||
assert send(payload).status_code == 409
|
assert send(payload).status_code == 409
|
||||||
provider.get_order.return_value = {**provider_data, "payStatus": 2}
|
provider.get_order.return_value = {**provider_data, "payStatus": 2}
|
||||||
@@ -129,7 +135,7 @@ def test_huihui_org_callback_verifies_provider_before_granting_points(authorizat
|
|||||||
provider.get_order.return_value = {**provider_data, "payStatus": 2, "chargeAmount": 2}
|
provider.get_order.return_value = {**provider_data, "payStatus": 2, "chargeAmount": 2}
|
||||||
assert send(payload).status_code == 422
|
assert send(payload).status_code == 422
|
||||||
provider.get_order.return_value = {**provider_data, "payStatus": 2}
|
provider.get_order.return_value = {**provider_data, "payStatus": 2}
|
||||||
first = send(payload)
|
first = send(payload, callback_path=legacy_path)
|
||||||
second = send(payload)
|
second = send(payload)
|
||||||
|
|
||||||
assert first.status_code == 200
|
assert first.status_code == 200
|
||||||
|
|||||||
@@ -5,6 +5,8 @@
|
|||||||
- 会会组织充值订单(当前 H5 收银台):`POST https://fat-digital.99hui.com/api/token/payment/huihui/org/notify`(测试环境)
|
- 会会组织充值订单(当前 H5 收银台):`POST https://fat-digital.99hui.com/api/token/payment/huihui/org/notify`(测试环境)
|
||||||
- 微信直连虚拟支付订单:`POST https://digital.99hui.com/api/token/payment/huihui/virtual/notify`(生产环境示例)
|
- 微信直连虚拟支付订单:`POST https://digital.99hui.com/api/token/payment/huihui/virtual/notify`(生产环境示例)
|
||||||
|
|
||||||
|
测试环境兼容提示:如果会会仍将上述组织充值订单发往 `/api/token/payment/huihui/virtual/notify`,而该环境未配置独立的虚拟支付密钥,旧地址会使用组织充值密钥验签并走相同的组织订单复核流程。该兼容入口不会处理微信直连虚拟支付订单;新接入仍应使用 `/org/notify`,生产环境不依赖此兼容行为。
|
||||||
|
|
||||||
回调报文及签名协议尚未与会会确认。以下是本项目实现的拟议对接契约,会会服务端必须按此格式发送才能完成联调。接口代码部署与会会联调通过是两个独立状态。它不替代现有微信直连回调 `/api/token/payment/wechat/virtual/notify`。
|
回调报文及签名协议尚未与会会确认。以下是本项目实现的拟议对接契约,会会服务端必须按此格式发送才能完成联调。接口代码部署与会会联调通过是两个独立状态。它不替代现有微信直连回调 `/api/token/payment/wechat/virtual/notify`。
|
||||||
|
|
||||||
请求体为 JSON,成功支付示例:
|
请求体为 JSON,成功支付示例:
|
||||||
|
|||||||
Reference in New Issue
Block a user