Files
shaguabijia-app-server/docs/database/withdraw_order.md
T
2026-07-09 14:23:59 +08:00

5.1 KiB
Raw Blame History

withdraw_order — 提现单(现金 → 微信零钱)

模型 app/models/wallet.py · 仓库 app/repositories/wallet.py · 接口 wallet-withdraw / wallet-withdraw-status / wallet-withdraw-orders · admin admin-withdraws-list / admin-withdraw-refresh · ← 索引 · 总览

用户把现金余额提到微信零钱的工单。含人工审核(2026-06 起):发起即扣现金、进 reviewing 待审核、不打款;管理员后台审核通过才真正发起微信商家转账,拒绝则退款。

状态机:

发起 ──扣现金+建单──▶ reviewing
reviewing ──admin 审核通过──▶ pending(微信转账在途) ──▶ success / failed(失败自动退款)
reviewing ──admin 审核拒绝──▶ rejected(已退款)

用在哪 / 增删改查

  • C(插入):POST /wallet/withdraw(create_withdraw)→ 校验额度([10 分, 5,000,000 分])+ 必须已绑微信 → 原子扣现金 + 写 cash_transaction(withdraw,) + 建单 status='reviewing',同事务。out_bill_no 客户端可传作幂等键(同号重发返回现状,不重复扣款建单)。
  • U(更新,改 status / 微信回执):
    • admin 审核通过 approve_withdrawpending → 调微信转账 → success(到账)/ 失败 _settle_after_ambiguous(查单后定夺)。
    • admin 审核拒绝 reject_withdraw → 退款 + rejected
    • 用户/系统查单 refresh_withdraw_status(GET /wallet/withdraw/status)、对账 reconcile_pending_withdraws(定时任务扫 >15min 的 pending)→ 按微信侧状态归一化 success/failed
    • 落微信回执:wechat_state / transfer_bill_no / package_info
  • D:无。
  • R:GET /wallet/withdraw/orders(用户提现单列表);admin 提现管理列表/查单。

字段

类型 约束 / 默认 说明(取值 / join)
id Integer PK, autoincrement
user_id Integer FK→user.id, index, NOT NULL 归属用户
out_bill_no String(64) UNIQUE, index, NOT NULL 商户单号(幂等键 + 微信查单键)。客户端可传([0-9A-Za-z_-]{8,32}),不传则服务端 uuid4().hexcash_transaction.ref_id / invite_cash_transaction.ref_id 引用(按 source 落对应账本)
source String(16) NOT NULL, default coin_cash 提现账户来源(#121 分账):coin_cash(金币兑换的现金,扣 coin_account.cash_balance_cents、流水落 cash_transaction)/ invite_cash(邀请奖励金,扣 invite_cash_balance_cents、流水落 invite_cash_transaction)
amount_cents Integer NOT NULL 提现金额(分)
user_name String(64) nullable 提现实名;微信达额转账要求实名,发起时存下、审核打款时传给微信
status String(16) NOT NULL, default reviewing 归一化状态:reviewing(待审核,已扣款未打款)/ pending(打款在途)/ success / failed(打款失败已退)/ rejected(审核拒绝已退)
wechat_state String(32) nullable 微信侧原始状态:WAIT_USER_CONFIRM / SUCCESS / FAIL / CANCELLED / CLOSED
transfer_bill_no String(64) nullable 微信转账单号(转账成功后回填)
package_info String(512) nullable 待用户确认时返回 App 拉起微信确认页用(确认模式有,免确认转账无)
fail_reason String(256) nullable 失败/拒绝技术原因(不外露,用户只看流水 remark)
created_at DateTime(tz) server_default now(), index 发起时间
updated_at DateTime(tz) server_default now(), onupdate now() 更新时间

关系 / Join Key

  • user_iduser.id(多对一)。
  • out_bill_no ← 被流水 ref_id 引用,账本按 source:coin_cash 单 → cash_transaction(withdraw / withdraw_refund +);invite_cash 单 → invite_cash_transaction(invite_withdraw / invite_withdraw_refund +)。admin GET /admin/api/withdraws/ledger-check 按 source 分账做「单 ↔ 流水」对账(#121)。
  • 打款方式依赖 wechat_transfer_authorization(用户有生效授权 → 免确认转账,否则确认模式)。

索引与约束

  • PK id;UNIQUE+index out_bill_no;index user_idcreated_at
  • 部分唯一索引 ux_withdraw_order_user_active(user_id),条件 status IN ('reviewing', 'pending'):每个用户同时只能有一笔在途(待审核 / 打款中)提现单,DB 层挡并发重复提现。

注意

  • 资金安全:原子扣款(WHERE cash_balance_cents >= amount)+ out_bill_no 幂等 + 结果不明时先查单再决定,绝不盲目退款(防退款后又到账)+ 孤儿 pending 单 reconcile_pending_withdraws 对账兜底。
  • WITHDRAW_MIN_CENTS=10(0.1 元,微信商家转账地板价),可经 app_config.withdraw_min_cents 后台调。
  • "待审核期间钱已扣减",防用户拿同一笔余额重复发起多笔提现。