Files
Django/users/fadan_fenhong_utils.py

188 lines
8.3 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# yonghu/fadan_fenhong_utils.py
# 罚款缴纳分红处理公共方法(支持更新罚单中的申请人分红金额)
import logging
from decimal import Decimal
from django.db import transaction
from orders.models import Penalty, PenaltyBonus, PenaltyBonusRate
from users.models import UserShangjia
logger = logging.getLogger(__name__)
# 身份映射字典
IDENTITY_MAP = {
1: {'fenhong': 2, 'lilv': 1}, # 客服
2: {'fenhong': 5, 'lilv': 2}, # 售后
3: {'fenhong': 3, 'lilv': 3}, # 管理员
4: {'fenhong': 4, 'lilv': 4}, # 店铺
5: {'fenhong': 1, 'lilv': 5}, # 商家
}
def process_fadan_fenhong(fadan_id):
"""
罚款缴纳后的分红处理(在回调中调用)
参数:
fadan_id: 罚单 ID
返回:
(success, message)
"""
try:
# 1. 获取罚单对象(必须是已缴纳状态)
try:
fadan = Penalty.objects.get(id=fadan_id, Status=2)
except Penalty.DoesNotExist:
logger.error(f"罚单 {fadan_id} 不存在或状态不是已缴纳")
return False, "罚单不存在或状态异常"
# 防重复分红(微信回调重试时不可二次加钱)
if fadan.ApplicantBonusAmount and Decimal(str(fadan.ApplicantBonusAmount)) > 0:
logger.info(
f"罚单 {fadan_id} 已分红 {fadan.ApplicantBonusAmount} 元,跳过重复处理"
)
return True, "已分红"
# 2. 获取申请处罚者ID和身份源身份数字
shenqing_chufa = fadan.ApplicantID
src_shenfen = fadan.ApplicantIdentity
if not shenqing_chufa:
logger.info(f"罚单 {fadan_id} 无申请处罚者,不进行分红")
# 即使无申请者也可将分红金额字段设为0默认已是0
return True, "无申请处罚者,无需分红"
# 3. 映射身份数字
if src_shenfen not in IDENTITY_MAP:
logger.error(f"未知的申请处罚者身份: {src_shenfen},罚单 {fadan_id}")
return False, f"未知身份 {src_shenfen}"
mapped = IDENTITY_MAP[src_shenfen]
fenhong_shenfen = mapped['fenhong'] # 用于 FadanFenhong.shenfen
lilv_shenfen = mapped['lilv'] # 用于 FadanFenhongLilv.shenfen
# 4. 获取罚款金额
fakuan_jine = fadan.FineAmount
if fakuan_jine <= 0:
logger.info(f"罚单 {fadan_id} 罚款金额为0不产生分红")
fadan.ApplicantBonusAmount = Decimal('0.00')
fadan.save(update_fields=['ApplicantBonusAmount'])
return True, "罚款金额为0无分红"
# 5. 确定分红利率
rate = _get_fenhong_rate(shenqing_chufa, fenhong_shenfen, lilv_shenfen, club_id=fadan.ClubID)
if rate is None:
logger.warning(f"未找到身份 {src_shenfen} (映射后 fenhong_shenfen={fenhong_shenfen}, lilv_shenfen={lilv_shenfen}) 的分红利率,罚单 {fadan_id} 不进行分红")
fadan.ApplicantBonusAmount = Decimal('0.00')
fadan.save(update_fields=['ApplicantBonusAmount'])
return True, "未配置分红利率,无分红"
# 6. 计算分红金额
fenhong_jine = (Decimal(str(fakuan_jine)) * Decimal(str(rate))).quantize(Decimal('0.01'))
if fenhong_jine <= 0:
logger.info(f"罚单 {fadan_id} 计算分红金额为0无需处理")
fadan.ApplicantBonusAmount = Decimal('0.00')
fadan.save(update_fields=['ApplicantBonusAmount'])
return True, "分红金额为0"
club_id = fadan.ClubID or 'xq'
# 7. 根据申请处罚者身份执行不同的分红逻辑
# src_shenfen == 5 代表商家(源身份)
if src_shenfen == 5:
# 商家:分红统计累加 + 余额入账可提现分红字段保持0钱进商家余额
with transaction.atomic():
fadan = Penalty.objects.select_for_update().get(id=fadan_id, Status=2)
if fadan.ApplicantBonusAmount and Decimal(str(fadan.ApplicantBonusAmount)) > 0:
logger.info(f"罚单 {fadan_id} 事务内检测到已分红,跳过")
return True, "已分红"
if not UserShangjia.objects.filter(user__UserUID=shenqing_chufa).exists():
logger.error(f"商家 {shenqing_chufa} 扩展表不存在,无法分红入账")
return False, "商家资料不存在,无法分红"
fenhong_record, created = PenaltyBonus.objects.get_or_create(
BeneficiaryID=shenqing_chufa,
Identity=fenhong_shenfen,
ClubID=club_id,
defaults={
'TotalAmount': Decimal('0.00'),
'WithdrawableAmount': Decimal('0.00'),
'BonusCount': 0,
'IndividualRate': rate,
'is_individual_rate': False
}
)
fenhong_record.TotalAmount += fenhong_jine
# 可提现分红不累加保持0
fenhong_record.BonusCount += 1
fenhong_record.save()
# 直接增加商家余额UserShangjia.yue
shangjia = UserShangjia.objects.select_for_update().get(user__UserUID=shenqing_chufa)
shangjia.yue += fenhong_jine
shangjia.save(update_fields=['yue'])
logger.info(f"商家 {shenqing_chufa} 余额增加 {fenhong_jine}")
# 更新罚单中的申请人分红金额
fadan.ApplicantBonusAmount = fenhong_jine
fadan.save(update_fields=['ApplicantBonusAmount'])
else:
# 其他身份(客服、售后、管理员、店铺):累加可提现分红
with transaction.atomic():
fadan = Penalty.objects.select_for_update().get(id=fadan_id, Status=2)
if fadan.ApplicantBonusAmount and Decimal(str(fadan.ApplicantBonusAmount)) > 0:
logger.info(f"罚单 {fadan_id} 事务内检测到已分红,跳过")
return True, "已分红"
fenhong_record, created = PenaltyBonus.objects.get_or_create(
BeneficiaryID=shenqing_chufa,
Identity=fenhong_shenfen,
ClubID=club_id,
defaults={
'TotalAmount': Decimal('0.00'),
'WithdrawableAmount': Decimal('0.00'),
'BonusCount': 0,
'IndividualRate': rate,
'is_individual_rate': False
}
)
fenhong_record.TotalAmount += fenhong_jine
fenhong_record.WithdrawableAmount += fenhong_jine
fenhong_record.BonusCount += 1
fenhong_record.save()
# 更新罚单中的申请人分红金额
fadan.ApplicantBonusAmount = fenhong_jine
fadan.save(update_fields=['ApplicantBonusAmount'])
logger.info(f"罚单 {fadan_id} 分红处理成功: 申请者 {shenqing_chufa}, 分红金额 {fenhong_jine} 元, 源身份 {src_shenfen}, 映射后分红身份 {fenhong_shenfen}")
return True, "分红处理成功"
except Exception as e:
logger.error(f"罚单 {fadan_id} 分红处理异常: {str(e)}", exc_info=True)
return False, f"分红处理异常: {str(e)}"
def _get_fenhong_rate(fenhongzhe_id, fenhong_shenfen, lilv_shenfen, club_id='xq'):
"""
获取分红利率(优先使用个人单独配置,否则使用全局身份配置)
"""
try:
individual = PenaltyBonus.objects.get(
BeneficiaryID=fenhongzhe_id,
Identity=fenhong_shenfen,
ClubID=club_id,
is_individual_rate=True
)
return individual.IndividualRate
except PenaltyBonus.DoesNotExist:
pass
try:
global_rate = PenaltyBonusRate.objects.get(Identity=lilv_shenfen)
return global_rate.Rate
except PenaltyBonusRate.DoesNotExist:
return None