fix: 手动打款驳回按申请扣款额全额退回各身份余额
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
32
yonghu/migrations/0022_backfill_tixianjilu_shenqing_jine.py
Normal file
32
yonghu/migrations/0022_backfill_tixianjilu_shenqing_jine.py
Normal file
@@ -0,0 +1,32 @@
|
||||
from decimal import Decimal
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
def backfill_shenqing_jine(apps, schema_editor):
|
||||
Tixianjilu = apps.get_model('yonghu', 'Tixianjilu')
|
||||
TixianShenheJilu = apps.get_model('yonghu', 'TixianShenheJilu')
|
||||
|
||||
for row in Tixianjilu.objects.filter(shenqing_jine__isnull=True).iterator():
|
||||
amount = None
|
||||
if row.shenhe_jilu_id:
|
||||
audit = TixianShenheJilu.objects.filter(pk=row.shenhe_jilu_id).only('shenqing_jine').first()
|
||||
if audit and audit.shenqing_jine is not None:
|
||||
amount = Decimal(str(audit.shenqing_jine))
|
||||
if amount is None:
|
||||
jine = Decimal(str(row.jine or 0))
|
||||
fee = Decimal(str(row.shouxufei or 0))
|
||||
amount = jine + fee
|
||||
if amount > 0:
|
||||
Tixianjilu.objects.filter(pk=row.pk).update(shenqing_jine=amount)
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('yonghu', '0021_tixianjilu_shenqing_jine_shouxufei'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RunPython(backfill_shenqing_jine, migrations.RunPython.noop),
|
||||
]
|
||||
@@ -822,31 +822,69 @@ def reject_audit_and_refund(user_main, audit, reason):
|
||||
bhliyou=reason,
|
||||
fail_reason=reason,
|
||||
)
|
||||
refund_balance(user_main, audit.leixing, audit.shenqing_jine)
|
||||
if audit.tixianjilu_id:
|
||||
tixian = Tixianjilu.objects.filter(pk=audit.tixianjilu_id).first()
|
||||
refund_amount = get_tixianjilu_refund_amount(tixian) if tixian else _quantize_money(audit.shenqing_jine)
|
||||
else:
|
||||
refund_amount = _quantize_money(audit.shenqing_jine)
|
||||
refund_balance(user_main, audit.leixing, refund_amount)
|
||||
|
||||
logger.info(
|
||||
'提现驳回退款 shenhe_danhao=%s yonghuid=%s leixing=%s refund=%s reason=%s',
|
||||
audit.shenhe_danhao, audit.yonghuid, audit.leixing, audit.shenqing_jine, reason,
|
||||
audit.shenhe_danhao, audit.yonghuid, audit.leixing, refund_amount, reason,
|
||||
)
|
||||
|
||||
return True, reason
|
||||
|
||||
|
||||
def _quantize_money(value):
|
||||
return decimal.Decimal(str(value or 0)).quantize(
|
||||
decimal.Decimal('0.01'), rounding=decimal.ROUND_HALF_UP,
|
||||
)
|
||||
|
||||
|
||||
def get_tixianjilu_refund_amount(tixian):
|
||||
"""手动提现驳回应退还的申请扣款额(非到账额)。"""
|
||||
if getattr(tixian, 'shenqing_jine', None) not in (None, ''):
|
||||
return decimal.Decimal(str(tixian.shenqing_jine))
|
||||
fee = getattr(tixian, 'shouxufei', None) or decimal.Decimal('0')
|
||||
base = decimal.Decimal(str(tixian.jine or 0))
|
||||
if fee:
|
||||
return base + decimal.Decimal(str(fee))
|
||||
return base
|
||||
"""
|
||||
驳回应退还的申请扣款额(申请时从对应身份余额扣减的全额,含手续费部分;非实际到账额)。
|
||||
优先级:tixian.shenqing_jine → 关联审核单.shenqing_jine → jine + shouxufei
|
||||
"""
|
||||
sj = getattr(tixian, 'shenqing_jine', None)
|
||||
if sj is not None and str(sj).strip() != '':
|
||||
amount = _quantize_money(sj)
|
||||
if amount > 0:
|
||||
return amount
|
||||
|
||||
shenhe_jilu_id = getattr(tixian, 'shenhe_jilu_id', None)
|
||||
if shenhe_jilu_id:
|
||||
audit = (
|
||||
TixianShenheJilu.objects.filter(pk=shenhe_jilu_id)
|
||||
.only('shenqing_jine')
|
||||
.first()
|
||||
)
|
||||
if audit and audit.shenqing_jine is not None:
|
||||
amount = _quantize_money(audit.shenqing_jine)
|
||||
if amount > 0:
|
||||
return amount
|
||||
|
||||
fee = _quantize_money(getattr(tixian, 'shouxufei', None) or 0)
|
||||
base = _quantize_money(getattr(tixian, 'jine', None) or 0)
|
||||
amount = base + fee
|
||||
if amount <= 0:
|
||||
raise ValueError(f'提现记录{tixian.id}无法确定驳回退款金额')
|
||||
return amount
|
||||
|
||||
|
||||
def refund_manual_tixianjilu(user_main, tixian):
|
||||
"""手动提现记录驳回退款(须在 transaction.atomic 内)。"""
|
||||
leixing = int(tixian.leixing)
|
||||
if leixing not in (1, 2, 3, 4, 5, 6):
|
||||
raise ValueError(f'提现记录{tixian.id}提现类型无效: {leixing}')
|
||||
amount = get_tixianjilu_refund_amount(tixian)
|
||||
refund_balance(user_main, tixian.leixing, amount)
|
||||
refund_balance(user_main, leixing, amount)
|
||||
logger.info(
|
||||
'手动提现驳回退款 tixian_id=%s yonghuid=%s leixing=%s amount=%s',
|
||||
tixian.id, tixian.yonghuid, leixing, amount,
|
||||
)
|
||||
|
||||
|
||||
def record_manual_withdraw_success_stats(user_main, tixian):
|
||||
@@ -896,33 +934,45 @@ def record_manual_withdraw_success_stats(user_main, tixian):
|
||||
|
||||
|
||||
def refund_balance(user_main, leixing, jine):
|
||||
"""审核驳回时退还申请扣款额 shenqing_jine(须在 transaction.atomic 内)"""
|
||||
if leixing == 1:
|
||||
dashou = UserDashou.objects.select_for_update().get(user=user_main)
|
||||
dashou.yue += jine
|
||||
dashou.save()
|
||||
elif leixing == 2:
|
||||
guanshi = UserGuanshi.objects.select_for_update().get(user=user_main)
|
||||
guanshi.yue += jine
|
||||
guanshi.save()
|
||||
elif leixing == 3:
|
||||
zuzhang = UserZuzhang.objects.select_for_update().get(user=user_main)
|
||||
zuzhang.ketixian_jine += jine
|
||||
zuzhang.save()
|
||||
elif leixing == 4:
|
||||
kaoheguan = UserShenheguan.objects.select_for_update().get(user=user_main)
|
||||
kaoheguan.yue += jine
|
||||
kaoheguan.save()
|
||||
elif leixing == 5:
|
||||
dashou = UserDashou.objects.select_for_update().get(user=user_main)
|
||||
dashou.yajin += jine
|
||||
dashou.save()
|
||||
elif leixing == 6:
|
||||
shangjia = UserShangjia.objects.select_for_update().get(user=user_main)
|
||||
shangjia.yue += jine
|
||||
shangjia.save()
|
||||
else:
|
||||
raise ValueError('无效的提现类型')
|
||||
"""审核/手动驳回:将申请扣款额全额退回对应身份余额(须在 transaction.atomic 内)。"""
|
||||
amount = _quantize_money(jine)
|
||||
if amount <= 0:
|
||||
raise ValueError(f'退款金额必须大于0,实际: {amount}')
|
||||
|
||||
try:
|
||||
leixing = int(leixing)
|
||||
except (TypeError, ValueError):
|
||||
raise ValueError(f'无效的提现类型: {leixing}')
|
||||
|
||||
refund_targets = {
|
||||
1: (UserDashou, 'yue'),
|
||||
2: (UserGuanshi, 'yue'),
|
||||
3: (UserZuzhang, 'ketixian_jine'),
|
||||
4: (UserShenheguan, 'yue'),
|
||||
5: (UserDashou, 'yajin'),
|
||||
6: (UserShangjia, 'yue'),
|
||||
}
|
||||
target = refund_targets.get(leixing)
|
||||
if not target:
|
||||
raise ValueError(f'无效的提现类型: {leixing}')
|
||||
|
||||
Model, field_name = target
|
||||
try:
|
||||
profile = Model.objects.select_for_update().get(user=user_main)
|
||||
except Model.DoesNotExist:
|
||||
raise ValueError(f'用户{user_main.yonghuid}缺少身份账户(leixing={leixing})')
|
||||
|
||||
before = _quantize_money(getattr(profile, field_name))
|
||||
after = before + amount
|
||||
setattr(profile, field_name, after)
|
||||
update_fields = [field_name]
|
||||
if hasattr(profile, 'update_time'):
|
||||
update_fields.append('update_time')
|
||||
profile.save(update_fields=update_fields)
|
||||
logger.info(
|
||||
'提现驳回退款 yonghuid=%s leixing=%s amount=%s field=%s before=%s after=%s',
|
||||
user_main.yonghuid, leixing, amount, field_name, before, after,
|
||||
)
|
||||
|
||||
|
||||
def deduct_balance(user_main, leixing, jine):
|
||||
|
||||
@@ -5725,32 +5725,29 @@ class AdtixianqkView(APIView):
|
||||
'data': None
|
||||
}, status=status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
# 获取提现记录
|
||||
try:
|
||||
withdrawal = Tixianjilu.objects.get(id=tixian_id)
|
||||
except Tixianjilu.DoesNotExist:
|
||||
return Response({
|
||||
'code': 404,
|
||||
'message': '提现记录不存在',
|
||||
'data': None
|
||||
}, status=status.HTTP_404_NOT_FOUND)
|
||||
|
||||
# 检查状态,只有待审核的可以处理
|
||||
if withdrawal.zhuangtai != 1:
|
||||
return Response({
|
||||
'code': 400,
|
||||
'message': '该提现申请已被处理',
|
||||
'data': None
|
||||
}, status=status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
# 使用事务确保数据一致性
|
||||
with transaction.atomic():
|
||||
# 更新提现记录
|
||||
try:
|
||||
withdrawal = Tixianjilu.objects.select_for_update().get(id=tixian_id)
|
||||
except Tixianjilu.DoesNotExist:
|
||||
return Response({
|
||||
'code': 404,
|
||||
'message': '提现记录不存在',
|
||||
'data': None
|
||||
}, status=status.HTTP_404_NOT_FOUND)
|
||||
|
||||
if withdrawal.zhuangtai != 1:
|
||||
return Response({
|
||||
'code': 400,
|
||||
'message': '该提现申请已被处理',
|
||||
'data': None
|
||||
}, status=status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
withdrawal.zhuangtai = result
|
||||
withdrawal.shenheid = request.user.yonghuid
|
||||
|
||||
if result == 3: # 拒绝
|
||||
user_main = UserMain.objects.get(yonghuid=withdrawal.yonghuid)
|
||||
user_main = UserMain.objects.select_for_update().get(yonghuid=withdrawal.yonghuid)
|
||||
from yonghu.tixian_shenhe_services import refund_manual_tixianjilu
|
||||
refund_manual_tixianjilu(user_main, withdrawal)
|
||||
withdrawal.bhliyou = reason
|
||||
@@ -12099,8 +12096,9 @@ class KefuWithdrawActionView(APIView):
|
||||
bhliyou=reason,
|
||||
bo_hui_ren_id=kefu_user.yonghuid,
|
||||
)
|
||||
# 退还申请时扣除的 shenqing_jine(全额申请扣款),手续费不单独返还
|
||||
refund_balance(user, audit.leixing, audit.shenqing_jine)
|
||||
from .tixian_shenhe_services import get_tixianjilu_refund_amount
|
||||
refund_amount = get_tixianjilu_refund_amount(tixian)
|
||||
refund_balance(user, audit.leixing, refund_amount)
|
||||
tixian.shenheid = kefu_user.yonghuid
|
||||
tixian.bhliyou = reason
|
||||
tixian.save(update_fields=['shenheid', 'bhliyou', 'update_time'])
|
||||
@@ -12126,7 +12124,7 @@ class KefuWithdrawActionView(APIView):
|
||||
raise ValueError(f'提现记录{tixian_id}:自动打款请走自动流程')
|
||||
|
||||
try:
|
||||
user = UserMain.objects.get(yonghuid=tixian.yonghuid)
|
||||
user = UserMain.objects.select_for_update().get(yonghuid=tixian.yonghuid)
|
||||
except UserMain.DoesNotExist:
|
||||
raise ValueError(f'用户{tixian.yonghuid}不存在')
|
||||
|
||||
|
||||
Reference in New Issue
Block a user