feat(withdraw): OPPO 厂商通道直连推送 — 提现审核通过通知
- integrations/oppo_push.py: OPPO PUSH 服务端直连(sha256 鉴权 + auth_token 24h 缓存 + unicast 单推) - device_liveness 加 oppo_register_id 列 + 迁移; register/heartbeat 透传 + list 查询 - services/push_notify: 审核通过 fire-and-forget 推送(best-effort, 不阻塞审核响应) - admin withdraw approve(单笔+批量)挂钩(status=failed 已退款不推) - 单测 10 passed; 真调 OPPO 生产 auth/unicast 验证签名与请求构造 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -476,3 +476,81 @@ def test_withdraw_reconcile(admin_client: TestClient, finance_token: str, monkey
|
||||
)
|
||||
assert r.status_code == 200, r.text
|
||||
assert "checked" in r.json() and "resolved" in r.json()
|
||||
|
||||
|
||||
# ===== 提现审核通过 → OPPO 推送挂钩 =====
|
||||
|
||||
def test_approve_triggers_oppo_push(
|
||||
admin_client: TestClient, finance_token: str, monkeypatch
|
||||
) -> None:
|
||||
"""审核通过(非 failed)后触发一次 OPPO 推送, 带被审核单的 user_id。"""
|
||||
uid = _seed_user("13900000021")
|
||||
db = SessionLocal()
|
||||
try:
|
||||
db.add(WithdrawOrder(
|
||||
user_id=uid, out_bill_no="pushapprove0001", amount_cents=100, status="reviewing"
|
||||
))
|
||||
db.commit()
|
||||
finally:
|
||||
db.close()
|
||||
|
||||
from app.admin.routers import withdraw as withdraw_router
|
||||
|
||||
# 绕过真实微信转账: approve 直接把单置 pending 返回(不发 wxpay)
|
||||
def _fake_approve(db, obn):
|
||||
o = db.execute(
|
||||
select(WithdrawOrder).where(WithdrawOrder.out_bill_no == obn)
|
||||
).scalar_one()
|
||||
o.status = "pending"
|
||||
db.commit()
|
||||
return o
|
||||
|
||||
monkeypatch.setattr(withdraw_router.wallet_repo, "approve_withdraw", _fake_approve)
|
||||
pushed: list[int] = []
|
||||
monkeypatch.setattr(
|
||||
withdraw_router.push_notify, "notify_withdraw_approved_async",
|
||||
lambda user_id: pushed.append(user_id),
|
||||
)
|
||||
r = admin_client.post(
|
||||
"/admin/api/withdraws/pushapprove0001/approve", headers=_auth(finance_token)
|
||||
)
|
||||
assert r.status_code == 200, r.text
|
||||
assert pushed == [uid]
|
||||
|
||||
|
||||
def test_approve_failed_does_not_push(
|
||||
admin_client: TestClient, finance_token: str, monkeypatch
|
||||
) -> None:
|
||||
"""打款直接失败(status=failed, 已退款)不推"审核通过"。"""
|
||||
uid = _seed_user("13900000022")
|
||||
db = SessionLocal()
|
||||
try:
|
||||
db.add(WithdrawOrder(
|
||||
user_id=uid, out_bill_no="pushapprove0002", amount_cents=100, status="reviewing"
|
||||
))
|
||||
db.commit()
|
||||
finally:
|
||||
db.close()
|
||||
|
||||
from app.admin.routers import withdraw as withdraw_router
|
||||
|
||||
def _fake_approve_failed(db, obn):
|
||||
o = db.execute(
|
||||
select(WithdrawOrder).where(WithdrawOrder.out_bill_no == obn)
|
||||
).scalar_one()
|
||||
o.status = "failed"
|
||||
o.fail_reason = "余额不足"
|
||||
db.commit()
|
||||
return o
|
||||
|
||||
monkeypatch.setattr(withdraw_router.wallet_repo, "approve_withdraw", _fake_approve_failed)
|
||||
pushed: list[int] = []
|
||||
monkeypatch.setattr(
|
||||
withdraw_router.push_notify, "notify_withdraw_approved_async",
|
||||
lambda user_id: pushed.append(user_id),
|
||||
)
|
||||
r = admin_client.post(
|
||||
"/admin/api/withdraws/pushapprove0002/approve", headers=_auth(finance_token)
|
||||
)
|
||||
assert r.status_code == 200, r.text
|
||||
assert pushed == []
|
||||
|
||||
Reference in New Issue
Block a user