feat: 提现驳回可选返还手续费与入账冻结(单笔/批量)

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
XingQue
2026-07-29 00:57:12 +08:00
parent 8e7481e25d
commit 36e1bf902a
4 changed files with 184 additions and 19 deletions

View File

@@ -29,6 +29,7 @@ ROLE_SHENHEGUAN = 'shenheguan'
SOURCE_ORDER_SETTLE = 'order_settle'
SOURCE_FENHONG = 'fenhong'
SOURCE_KAOHE_FEE = 'kaohe_fee'
SOURCE_WITHDRAW_REJECT = 'withdraw_reject'
_CFG_CACHE_TTL = 60
@@ -103,11 +104,11 @@ def _source_allowed(cfg: ClubFundFreezeConfig, source_type: str, role: str = '')
return True
if source_type in items:
return True
# 管事/组长几乎没有 order_settle 入账;历史配置只勾了「订单结算」时仍允许分红冻结
# 管事/组长几乎没有 order_settle 入账;历史配置只勾了「订单结算」时仍允许分红/驳回退款冻结
role = (role or '').strip().lower()
if (
role in (ROLE_GUANSHI, ROLE_ZUZHANG, ROLE_SHENHEGUAN)
and source_type == SOURCE_FENHONG
and source_type in (SOURCE_FENHONG, SOURCE_WITHDRAW_REJECT)
and set(items) == {'order_settle'}
):
return True
@@ -184,12 +185,14 @@ def credit_role_balance(
czjilu_id: str = '',
freeze_reason: str = '',
also_credit_zonge: bool = False,
ignore_source_scope: bool = False,
) -> Dict[str, Any]:
"""
统一入账。返回 {available, frozen, ledger_id, skipped_freeze}。
调用方须在外层 transaction.atomic() 内,并已持有/即将更新的业务一致性。
profile: 已加载的角色扩展实例UserDashou 等);若空则按 role+user_id 查。
ignore_source_scope: True 时跳过 source_scope 检查(仍受 enabled / 金额规则约束)。
"""
role = (role or '').strip().lower()
cid = _club(club_id)
@@ -206,16 +209,15 @@ def credit_role_balance(
raise ValueError(f'找不到角色资料 role={role} user_id={user_id}')
cfg = get_freeze_config(cid, role)
freeze_on = bool(
cfg and cfg.enabled and _source_allowed(cfg, source_type, role=role) and biz_id
)
source_ok = True if ignore_source_scope else _source_allowed(cfg, source_type, role=role) if cfg else False
freeze_on = bool(cfg and cfg.enabled and source_ok and biz_id)
skip_reason = ''
if not freeze_on:
if not cfg:
skip_reason = 'no_config'
elif not cfg.enabled:
skip_reason = 'disabled'
elif not _source_allowed(cfg, source_type, role=role):
elif not source_ok:
skip_reason = f'source_not_in_scope:{source_type}'
elif not biz_id:
skip_reason = 'empty_biz_id'