feat(avatar): route token recharge through Huihui org orders
This commit is contained in:
@@ -25,6 +25,7 @@ from models import (
|
||||
)
|
||||
from responses import fail, ok
|
||||
from services.huihui_payment import HuihuiPaymentClient, HuihuiPaymentError
|
||||
from services.huihui_org_payment import HuihuiOrgPaymentClient
|
||||
from services.token_billing import get_or_create_account
|
||||
from services.wechat_virtual_payment import (
|
||||
PAYMENT_EVENTS as WECHAT_PAYMENT_EVENTS,
|
||||
@@ -270,6 +271,7 @@ def _callback_amount_cents(payload) -> int | None:
|
||||
"orderAmt",
|
||||
"amount",
|
||||
"totalAmount",
|
||||
"chargeAmount",
|
||||
)
|
||||
if value in (None, ""):
|
||||
return None
|
||||
@@ -405,6 +407,47 @@ def charge(payload: dict = Body(...), authorization: str = Header(None), db: Ses
|
||||
return ok(_payment_payload(order, get_or_create_account(db, user.id)))
|
||||
|
||||
|
||||
@router.post("/token/charge/org")
|
||||
def charge_via_huihui_org(payload: dict = Body(...), authorization: str = Header(None), db: Session = Depends(get_db)):
|
||||
user = _require_user(authorization, db)
|
||||
plan = db.query(TokenPlan).filter(TokenPlan.id == payload.get("planId")).first()
|
||||
if not plan:
|
||||
return fail("套餐不存在", 404)
|
||||
method = str(payload.get("paymentMethod") or "").lower()
|
||||
if method not in PAYMENT_METHODS:
|
||||
return fail("支付方式不正确", 400)
|
||||
scene = str(payload.get("payScene") or "APP").upper()
|
||||
if scene not in PAYMENT_SCENES:
|
||||
return fail("支付场景不正确", 400)
|
||||
pay_type = 6 if scene == "LITE" else (1 if method == "wechat" else 2)
|
||||
if scene == "LITE" and method != "wechat":
|
||||
return fail("微信小程序仅支持微信支付", 400)
|
||||
cents = _price_cents(plan.price)
|
||||
try:
|
||||
result = HuihuiOrgPaymentClient().create_order(
|
||||
token=user.huihui_token, user_id=user.huihui_user_id,
|
||||
name=user.nickname, phone=user.phone, avatar=user.avatar_url,
|
||||
amount=f"{cents / 100:.2f}", pay_type=pay_type,
|
||||
)
|
||||
except HuihuiPaymentError as exc:
|
||||
return fail(str(exc), 502)
|
||||
provider_no = str(result.get("orderNo") or "")
|
||||
if not provider_no.isdigit() or int(result.get("payStatus") or 0) != 1 or int(result.get("chargeType") or 0) != 9:
|
||||
return fail("会会返回的充值订单不正确", 502)
|
||||
if _callback_amount_cents({"chargeAmount": result.get("chargeAmount")}) != cents:
|
||||
return fail("会会返回的充值金额不匹配", 502)
|
||||
order = TokenPaymentOrder(
|
||||
order_no=f"AV{datetime.utcnow().strftime('%Y%m%d%H%M%S')}{uuid.uuid4().hex[:12].upper()}",
|
||||
user_id=user.id, plan_id=plan.id, payment_method=method,
|
||||
pay_type=PAYMENT_METHODS[method], pay_way=scene, points_amount=plan.amount,
|
||||
price_cents=cents, status="pending", provider="huihui_org",
|
||||
provider_order_no=provider_no, provider_status="1",
|
||||
)
|
||||
db.add(order)
|
||||
db.commit()
|
||||
return ok(_payment_payload(order, get_or_create_account(db, user.id)))
|
||||
|
||||
|
||||
@router.get("/token/payment/{order_id}")
|
||||
def payment_status(order_id: str, authorization: str = Header(None), db: Session = Depends(get_db)):
|
||||
user = _require_user(authorization, db)
|
||||
@@ -414,6 +457,27 @@ def payment_status(order_id: str, authorization: str = Header(None), db: Session
|
||||
).first()
|
||||
if not order:
|
||||
return fail("支付订单不存在", 404)
|
||||
if order.provider == "huihui_org" and order.status == "pending":
|
||||
try:
|
||||
details = HuihuiOrgPaymentClient().get_order(
|
||||
token=user.huihui_token, user_id=user.huihui_user_id,
|
||||
order_no=order.provider_order_no,
|
||||
)
|
||||
status = int(details.get("payStatus") or 0)
|
||||
if (str(details.get("orderNo") or "") == order.provider_order_no
|
||||
and str(details.get("userId") or "") == user.huihui_user_id
|
||||
and int(details.get("chargeType") or 0) == 9
|
||||
and _callback_amount_cents({"chargeAmount": details.get("chargeAmount")}) == order.price_cents):
|
||||
order.provider_status = str(status)
|
||||
if status in (2, 3, 4):
|
||||
_settle_paid_order(db, order, provider_status=f"ORG_{status}",
|
||||
transaction_no=order.provider_order_no)
|
||||
elif status == 5:
|
||||
order.status = "closed"
|
||||
db.commit()
|
||||
db.refresh(order)
|
||||
except (HuihuiPaymentError, TypeError, ValueError):
|
||||
pass # 查询失败时保持待支付,不将未经核对的结果入账。
|
||||
if order.provider == "wechat_virtual" and order.status == "pending" and user.wechat_mp_openid:
|
||||
try:
|
||||
provider_data = query_wechat_virtual_order(
|
||||
@@ -560,6 +624,8 @@ def admin_request_refund(
|
||||
return fail("订单不存在", 404)
|
||||
if order.status != "paid" or order.refund_status not in {"", "none", "failed"}:
|
||||
return fail("该订单当前不可退款", 409)
|
||||
if order.provider == "huihui_org":
|
||||
return fail("会会组织订单的原路退款接口尚未接入,请先在会会后台处理", 409)
|
||||
account = get_or_create_account(db, order.user_id)
|
||||
if int(account.balance or 0) < int(order.points_amount or 0):
|
||||
return fail("该订单发放的积分已使用,不能执行全额退款", 409)
|
||||
|
||||
Reference in New Issue
Block a user