Verify Huihui organization payment callbacks against paid orders

This commit is contained in:
stefanfeng
2026-10-20 11:04:27 +08:00
parent 643abd13ea
commit ce18df29b7
4 changed files with 176 additions and 18 deletions
+96 -7
View File
@@ -810,12 +810,10 @@ async def payment_callback(
return ok({"received": True, "paid": True})
@router.post("/token/payment/huihui/virtual/notify")
async def huihui_virtual_payment_notify(request: Request, db: Session = Depends(get_db)):
"""Server-to-server virtual-payment notice using the Huihui HMAC contract."""
secret = os.getenv("HUIHUI_VIRTUAL_CALLBACK_SECRET", "").strip()
if len(secret) < 32:
raise HTTPException(status_code=503, detail="virtual payment callback is not configured")
async def _signed_huihui_notice(request: Request, *, secret_name: str, minimum_length: int) -> dict:
secret = os.getenv(secret_name, "").strip()
if len(secret) < minimum_length:
raise HTTPException(status_code=503, detail="payment callback is not configured")
timestamp = request.headers.get("x-huihui-timestamp", "").strip()
signature = request.headers.get("x-huihui-signature", "").strip().lower()
if not timestamp.isascii() or not timestamp.isdecimal() or len(timestamp) > 12:
@@ -840,6 +838,97 @@ async def huihui_virtual_payment_notify(request: Request, db: Session = Depends(
raise HTTPException(status_code=400, detail="invalid callback JSON")
if not isinstance(payload, dict):
raise HTTPException(status_code=400, detail="invalid callback JSON")
return payload
@router.post("/token/payment/huihui/org/notify")
async def huihui_org_payment_notify(request: Request, db: Session = Depends(get_db)):
"""Huihui organization recharge notice; independently verify payment before crediting."""
payload = await _signed_huihui_notice(
request, secret_name="HUIHUI_ORG_CALLBACK_SECRET", minimum_length=16,
)
order_no = str(payload.get("orderNo") or "").strip()
payment_no = str(payload.get("paymentNo") or "").strip()
status = str(payload.get("status") or "").upper()
if not order_no or not payment_no or status not in {"SUCCESS", "FAILED"}:
raise HTTPException(status_code=400, detail="missing callback fields")
order = db.query(TokenPaymentOrder).filter(
TokenPaymentOrder.provider == "huihui_org",
TokenPaymentOrder.order_no == order_no,
).first()
if order is None and order_no.isdigit():
matches = db.query(TokenPaymentOrder).filter(
TokenPaymentOrder.provider == "huihui_org",
TokenPaymentOrder.provider_order_no == order_no,
).limit(2).all()
if len(matches) == 1:
order = matches[0]
if not order:
raise HTTPException(status_code=404, detail="payment order not found")
if status == "FAILED":
return ok({"received": True, "paid": False})
user = db.query(User).filter(User.id == order.user_id).first()
plan = db.query(TokenPlan).filter(TokenPlan.id == order.plan_id).first()
try:
expected_product_id = product_id_for_plan(plan) if plan else ""
amount_cents = int(payload.get("amountCents"))
except (TypeError, ValueError, WechatVirtualPaymentError):
raise HTTPException(status_code=422, detail="invalid payment details")
if (
isinstance(payload.get("amountCents"), bool)
or not user
or not expected_product_id
or str(payload.get("productId") or "") != expected_product_id
or amount_cents != order.price_cents
):
raise HTTPException(status_code=422, detail="payment details mismatch")
if order.status in {"paid", "refunded"}:
return ok({"received": True, "duplicate": True})
if not order.provider_order_no or not user.huihui_token or not user.huihui_user_id:
raise HTTPException(status_code=503, detail="provider order verification unavailable")
try:
provider_order = HuihuiOrgPaymentClient().get_order(
token=user.huihui_token,
user_id=user.huihui_user_id,
order_no=order.provider_order_no,
)
except HuihuiPaymentError as exc:
raise HTTPException(status_code=503, detail="provider order verification unavailable") from exc
try:
provider_status = int(provider_order.get("payStatus"))
provider_type = int(provider_order.get("chargeType"))
except (TypeError, ValueError):
raise HTTPException(status_code=422, detail="invalid provider order details")
if (
str(provider_order.get("orderNo") or "") != order.provider_order_no
or str(provider_order.get("paymentNo") or "") != payment_no
or str(provider_order.get("productId") or "") != expected_product_id
or str(provider_order.get("userId") or "") != user.huihui_user_id
or provider_type != 9
or _callback_amount_cents({"chargeAmount": provider_order.get("chargeAmount")}) != order.price_cents
):
raise HTTPException(status_code=422, detail="provider order details mismatch")
if provider_status not in {2, 3, 4}:
raise HTTPException(status_code=409, detail="provider payment not confirmed")
existing_payment = db.query(PaymentTransaction).filter(
PaymentTransaction.provider == "huihui_org",
PaymentTransaction.event_type == "payment",
PaymentTransaction.transaction_no == payment_no,
).first()
if existing_payment and existing_payment.order_no != order.order_no:
raise HTTPException(status_code=409, detail="payment number belongs to another order")
_settle_paid_order(db, order, provider_status="HUIHUI_SUCCESS", transaction_no=payment_no)
db.commit()
return ok({"received": True, "paid": True})
@router.post("/token/payment/huihui/virtual/notify")
async def huihui_virtual_payment_notify(request: Request, db: Session = Depends(get_db)):
"""Server-to-server virtual-payment notice using the Huihui HMAC contract."""
payload = await _signed_huihui_notice(
request, secret_name="HUIHUI_VIRTUAL_CALLBACK_SECRET", minimum_length=32,
)
order_no = str(payload.get("orderNo") or "").strip()
payment_no = str(payload.get("paymentNo") or "").strip()
@@ -877,7 +966,7 @@ async def huihui_virtual_payment_notify(request: Request, db: Session = Depends(
PaymentTransaction.event_type == "payment",
PaymentTransaction.transaction_no == payment_no,
).first()
if existing_payment and existing_payment.order_no != order_no:
if existing_payment and existing_payment.order_no != order.order_no:
raise HTTPException(status_code=409, detail="payment number belongs to another order")
if order.status in {"paid", "refunded"}:
return ok({"received": True, "duplicate": True})