feat: 罚款分红费率按俱乐部可读可配,接入提现设置

个人利率优先,其次 club_fadan_fenhong_lilv,再回退全局表;组队均摊仍按每张罚单金额×费率。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
XingQue
2026-07-27 19:54:58 +08:00
parent 75fb69e6da
commit 1c67f98866
2 changed files with 84 additions and 2 deletions

View File

@@ -8,9 +8,10 @@ from rest_framework.response import Response
from backend.models import WithdrawalDailyStats from backend.models import WithdrawalDailyStats
from config.models import TixianQuotaDefault from config.models import TixianQuotaDefault
from jituan.constants import CLUB_ID_DEFAULT, DATA_SCOPE_ALL from jituan.constants import CLUB_ID_DEFAULT, DATA_SCOPE_ALL
from jituan.models import ClubLilubiao, ClubTixianQuota, ClubWithdrawConfig from jituan.models import ClubFadanFenhongLilv, ClubLilubiao, ClubTixianQuota, ClubWithdrawConfig
from jituan.services.club_config import get_commission_rate from jituan.services.club_config import get_commission_rate
from jituan.services.club_context import resolve_club_id_from_request, resolve_club_scope from jituan.services.club_context import resolve_club_id_from_request, resolve_club_scope
from orders.models import PenaltyBonusRate
# 提现手续费率 → lilubiao config_type / CommissionRate Platform # 提现手续费率 → lilubiao config_type / CommissionRate Platform
LEIXING_RATE_KEY = { LEIXING_RATE_KEY = {
@@ -22,6 +23,15 @@ LEIXING_RATE_KEY = {
6: '10', # 商家余额 6: '10', # 商家余额
} }
# 罚款分红身份(与 fadan_fenhong_lilv.shenfen 一致)
PENALTY_BONUS_SHENFEN = {
1: '客服',
2: '售后',
3: '管理员',
4: '店铺',
5: '商家',
}
# 提现身份 leixing → 平台日总限额配置 leixingclub_tixian_quota / TixianQuotaDefault UserType # 提现身份 leixing → 平台日总限额配置 leixingclub_tixian_quota / TixianQuotaDefault UserType
WITHDRAW_TOTAL_QUOTA_LEIXING = {1: 4, 2: 5, 3: 6, 4: 7, 5: 8, 6: 9} WITHDRAW_TOTAL_QUOTA_LEIXING = {1: 4, 2: 5, 3: 6, 4: 7, 5: 8, 6: 9}
@@ -70,6 +80,39 @@ def _set_lilv(club_id, config_type, rate):
row.save(update_fields=['lilv', 'UpdateTime']) row.save(update_fields=['lilv', 'UpdateTime'])
def _get_penalty_bonus_rate(club_id, shenfen):
"""有效罚款分红费率:俱乐部 > 全局表。"""
club_id = _normalize_club_id(club_id)
shenfen = int(shenfen)
row = ClubFadanFenhongLilv.query.filter(club_id=club_id, shenfen=shenfen).first()
if row is not None and row.lilv is not None:
return float(row.lilv)
try:
g = PenaltyBonusRate.objects.get(Identity=shenfen)
if g.Rate is not None:
return float(g.Rate)
except PenaltyBonusRate.DoesNotExist:
pass
return 0.0
def _set_penalty_bonus_rate(club_id, shenfen, rate):
club_id = _normalize_club_id(club_id)
shenfen = int(shenfen)
row, created = ClubFadanFenhongLilv.query.get_or_create(
club_id=club_id,
shenfen=shenfen,
defaults={'lilv': rate},
)
if not created:
row.lilv = rate
row.save(update_fields=['lilv', 'UpdateTime'])
def get_penalty_bonus_rates_map(club_id):
return {s: _get_penalty_bonus_rate(club_id, s) for s in PENALTY_BONUS_SHENFEN}
def get_tixian_feilv(club_id, leixing): def get_tixian_feilv(club_id, leixing):
"""读取提现手续费率(各俱乐部可不同)。""" """读取提现手续费率(各俱乐部可不同)。"""
rate_key = LEIXING_RATE_KEY.get(leixing) rate_key = LEIXING_RATE_KEY.get(leixing)
@@ -176,6 +219,7 @@ def build_withdraw_settings_payload(request):
'withdraw_mode': get_withdraw_mode(club_id), 'withdraw_mode': get_withdraw_mode(club_id),
'rates': rate_map, 'rates': rate_map,
'order_rates': order_rate_map, 'order_rates': order_rate_map,
'penalty_bonus_rates': get_penalty_bonus_rates_map(club_id),
'quotas': quota_map, 'quotas': quota_map,
'total_limits': total_limit_map, 'total_limits': total_limit_map,
'today_totals': today_totals, 'today_totals': today_totals,
@@ -189,6 +233,7 @@ def apply_withdraw_settings_update(request, permissions):
club_id = _club_id(request) club_id = _club_id(request)
rates = request.data.get('rates', {}) rates = request.data.get('rates', {})
order_rates = request.data.get('order_rates', request.data.get('commission_rates', {})) order_rates = request.data.get('order_rates', request.data.get('commission_rates', {}))
penalty_bonus_rates = request.data.get('penalty_bonus_rates', {})
quotas = request.data.get('quotas', {}) quotas = request.data.get('quotas', {})
total_limits = request.data.get('total_limits', {}) total_limits = request.data.get('total_limits', {})
@@ -229,6 +274,15 @@ def apply_withdraw_settings_update(request, permissions):
} }
return Response({'code': 403, 'msg': f'无权限修改{order_names[role]}费率'}) return Response({'code': 403, 'msg': f'无权限修改{order_names[role]}费率'})
for shenfen in PENALTY_BONUS_SHENFEN:
if _rate_key_present(penalty_bonus_rates, shenfen) and not any(
p in permissions for p in ('5500a', '5500b', '5500c')
):
return Response({
'code': 403,
'msg': f'无权限修改{PENALTY_BONUS_SHENFEN[shenfen]}罚款分红费率',
})
for role in [1, 2, 3, 4, 5, 6]: for role in [1, 2, 3, 4, 5, 6]:
val = rates.get(str(role), rates.get(role)) val = rates.get(str(role), rates.get(role))
if val is not None: if val is not None:
@@ -239,6 +293,17 @@ def apply_withdraw_settings_update(request, permissions):
if val is not None: if val is not None:
_set_lilv(club_id, order_rate_code_map[role], Decimal(str(val))) _set_lilv(club_id, order_rate_code_map[role], Decimal(str(val)))
for shenfen in PENALTY_BONUS_SHENFEN:
val = penalty_bonus_rates.get(str(shenfen), penalty_bonus_rates.get(shenfen))
if val is not None:
rate = Decimal(str(val))
if rate < 0 or rate > 1:
return Response({
'code': 400,
'msg': f'{PENALTY_BONUS_SHENFEN[shenfen]}罚款分红费率须在 0~1 之间(如 0.6 表示 60%',
})
_set_penalty_bonus_rate(club_id, shenfen, rate)
for role in [1, 2, 3]: for role in [1, 2, 3]:
if str(role) in quotas: if str(role) in quotas:
val = quotas[str(role)] val = quotas[str(role)]

View File

@@ -43,9 +43,22 @@ def _read_global_fenhong_rate(lilv_shenfen):
return None return None
def _read_club_fenhong_rate(club_id, lilv_shenfen):
"""俱乐部级罚款分红费率club_fadan_fenhong_lilv"""
from jituan.models import ClubFadanFenhongLilv
club_id = _normalize_club_id(club_id)
row = ClubFadanFenhongLilv.query.filter(
club_id=club_id, shenfen=int(lilv_shenfen),
).first()
if row is not None and row.lilv is not None and Decimal(str(row.lilv)) > 0:
return row.lilv
return None
def _get_fenhong_rate(fenhongzhe_id, fenhong_shenfen, lilv_shenfen, club_id='xq'): def _get_fenhong_rate(fenhongzhe_id, fenhong_shenfen, lilv_shenfen, club_id='xq'):
""" """
获取分红利率:个人单独利率 > 0 优先;否则回退全局 fadan_fenhong_lilv。 获取分红利率:个人单独利率 > 0 优先;否则俱乐部配置;再回退全局 fadan_fenhong_lilv。
""" """
club_id = _normalize_club_id(club_id) club_id = _normalize_club_id(club_id)
try: try:
@@ -61,6 +74,10 @@ def _get_fenhong_rate(fenhongzhe_id, fenhong_shenfen, lilv_shenfen, club_id='xq'
except PenaltyBonus.DoesNotExist: except PenaltyBonus.DoesNotExist:
pass pass
club_rate = _read_club_fenhong_rate(club_id, lilv_shenfen)
if club_rate is not None:
return club_rate
return _read_global_fenhong_rate(lilv_shenfen) return _read_global_fenhong_rate(lilv_shenfen)