fix: 会员充值先开通再分红防回滚,补开通与注册时间字段

This commit is contained in:
XingQue
2026-06-24 18:08:11 +08:00
parent 83519ac67b
commit 9cd7b6920a
4 changed files with 75 additions and 14 deletions

View File

@@ -911,6 +911,7 @@ class KefuGetDashouDetailView(APIView):
'wechat': '',
'phone': user_main.Phone or '',
'CreateTime': user_main.UserCreateTime,
'create_time': user_main.UserCreateTime.strftime('%Y-%m-%d %H:%M:%S') if getattr(user_main, 'UserCreateTime', None) else '',
'ip': user_main.IP or '',
'jiedanzongliang': 0,
'chengjiaozongliang': 0,
@@ -951,6 +952,7 @@ class KefuGetDashouDetailView(APIView):
'wechat': dashou.wechat or '',
'phone': user_main.Phone or '',
'CreateTime': user_main.UserCreateTime,
'create_time': user_main.UserCreateTime.strftime('%Y-%m-%d %H:%M:%S') if getattr(user_main, 'UserCreateTime', None) else '',
'ip': user_main.IP or '',
'jiedanzongliang': dashou.jiedanzongliang,
'chengjiaozongliang': dashou.chengjiaozongliang,
@@ -1554,6 +1556,7 @@ class KefuGetShangjiaDetailView(APIView):
'jinyuedingdan': shangjia.jinyuedingdan,
'jinyueliushui': str(shangjia.jinyueliushui),
'CreateTime': shangjia.CreateTime.isoformat() if shangjia.CreateTime else None,
'create_time': user.UserCreateTime.strftime('%Y-%m-%d %H:%M:%S') if getattr(user, 'UserCreateTime', None) else '',
}
return Response({'code': 0, 'data': data})
@@ -3824,6 +3827,7 @@ class GetZuzhangDetailView(APIView):
'jinyue_fenyong': str(zuzhang.jinyue_fenyong),
'fenyong_zonge': str(zuzhang.fenyong_zonge),
'CreateTime': zuzhang.CreateTime.isoformat() if zuzhang.CreateTime else None,
'create_time': user.UserCreateTime.strftime('%Y-%m-%d %H:%M:%S') if getattr(user, 'UserCreateTime', None) else '',
}
# 余额提现相关

View File

@@ -127,7 +127,12 @@ def _apply_member_fenhong(order, huiyuan, purchase_cishu):
logger.info('会员分红已处理,跳过: %s', order.dingdan_id)
return
dashou = UserDashou.query.get(user__UserUID=order.yonghuid)
try:
dashou = UserDashou.query.get(user__UserUID=order.yonghuid)
except UserDashou.DoesNotExist:
logger.warning('打手不存在,跳过会员分红: %s', order.yonghuid)
return
guanshi_id = dashou.yaoqingren
if not guanshi_id:
logger.info('打手%s无邀请管事,跳过会员分红', order.yonghuid)
@@ -282,6 +287,35 @@ def _add_first_buy_jifen(yonghuid):
logger.warning('首次购会员加积分失败,打手不存在: %s', yonghuid)
def repair_member_entitlement_if_paid(dingdan_id):
"""
订单已标为已支付(zhuangtai=3)但 huiyuangoumai 缺失时补开通会员。
用于修复历史脏数据或履约中断。
"""
order = Czjilu.query.filter(dingdan_id=dingdan_id, leixing=1).first()
if not order or order.zhuangtai != 3 or not order.huiyuan_id:
return False
exists = Huiyuangoumai.query.filter(
yonghu_id=order.yonghuid,
huiyuan_id=order.huiyuan_id,
).exists()
if exists:
return True
try:
huiyuan = Huiyuan.query.get(huiyuan_id=order.huiyuan_id)
except Huiyuan.DoesNotExist:
logger.error('补开通会员失败,会员不存在 dingdan=%s huiyuan=%s', dingdan_id, order.huiyuan_id)
return False
club_id = getattr(order, 'club_id', None) or CLUB_ID_DEFAULT
with transaction.atomic():
_apply_huiyuan_goumai(order.yonghuid, order.huiyuan_id, huiyuan, club_id)
logger.warning('已补开通会员 dingdan=%s yonghu=%s huiyuan=%s', dingdan_id, order.yonghuid, order.huiyuan_id)
return True
@transaction.atomic
def fulfill_member_recharge(dingdan_id, paid_amount_yuan=None, source='callback'):
"""
@@ -315,7 +349,10 @@ def fulfill_member_recharge(dingdan_id, paid_amount_yuan=None, source='callback'
f'支付金额{paid}与订单{order_amt}不一致', 'amount_mismatch',
)
huiyuan = Huiyuan.query.get(huiyuan_id=order.huiyuan_id)
huiyuan = Huiyuan.query.filter(huiyuan_id=order.huiyuan_id).first()
if not huiyuan:
raise MemberRechargeError(f'会员不存在: {order.huiyuan_id}', 'huiyuan_not_found')
club_id = getattr(order, 'club_id', None) or CLUB_ID_DEFAULT
is_first_purchase_of_member = not Huiyuangoumai.query.filter(
@@ -328,12 +365,12 @@ def fulfill_member_recharge(dingdan_id, paid_amount_yuan=None, source='callback'
order.yonghuid, order.huiyuan_id, order.dingdan_id, club_id,
)
jine_decimal = Decimal(str(order.jine))
try:
from jituan.services.szjilu_accounting import record_wechat_income_once
record_wechat_income_once(jine_decimal, club_id, biz_ref=f'cz:{dingdan_id}')
except Exception as exc:
logger.error('会员收支统计更新失败: %s', exc, exc_info=True)
# 先开通会员,再记账;分红失败不得回滚会员
goumai_record, _, is_first_buy_any = _apply_huiyuan_goumai(
order.yonghuid, order.huiyuan_id, huiyuan, club_id,
)
if is_first_buy_any:
_add_first_buy_jifen(order.yonghuid)
order.zhuangtai = 3
order.save(update_fields=['zhuangtai'])
@@ -341,13 +378,20 @@ def fulfill_member_recharge(dingdan_id, paid_amount_yuan=None, source='callback'
huiyuan.goumai_cishu = (huiyuan.goumai_cishu or 0) + 1
huiyuan.save(update_fields=['goumai_cishu'])
goumai_record, _, is_first_buy_any = _apply_huiyuan_goumai(
order.yonghuid, order.huiyuan_id, huiyuan, club_id,
)
if is_first_buy_any:
_add_first_buy_jifen(order.yonghuid)
jine_decimal = Decimal(str(order.jine))
try:
from jituan.services.szjilu_accounting import record_wechat_income_once
record_wechat_income_once(jine_decimal, club_id, biz_ref=f'cz:{dingdan_id}')
except Exception as exc:
logger.error('会员收支统计更新失败: %s', exc, exc_info=True)
_apply_member_fenhong(order, huiyuan, purchase_cishu)
try:
_apply_member_fenhong(order, huiyuan, purchase_cishu)
except Exception as exc:
logger.error(
'会员分红失败但会员已开通 dingdan=%s err=%s',
dingdan_id, exc, exc_info=True,
)
logger.info(
'会员充值履约完成 dingdan=%s source=%s club=%s purchase_cishu=%s first_member=%s',
@@ -419,6 +463,11 @@ def confirm_member_recharge_paid(dingdan_id, yonghuid):
goumai = Huiyuangoumai.query.filter(
yonghu_id=yonghuid, huiyuan_id=order.huiyuan_id,
).first()
if not goumai:
repair_member_entitlement_if_paid(dingdan_id)
goumai = Huiyuangoumai.query.filter(
yonghu_id=yonghuid, huiyuan_id=order.huiyuan_id,
).first()
if not goumai:
raise MemberRechargeError('订单已付但会员记录缺失,请联系客服', 'data_error')
return {

View File

@@ -1767,6 +1767,9 @@ class HuiyuanHuitiao(View):
if order.zhuangtai != 9:
logger.warning(f"会员订单状态不是未支付: {order.dingdan_id}, 当前状态: {order.zhuangtai}")
if order.zhuangtai == 3:
from jituan.services.member_recharge import repair_member_entitlement_if_paid
repair_member_entitlement_if_paid(out_trade_no)
return self.wechat_response('SUCCESS', 'OK')
wechat_amount_yuan = total_fee / 100
@@ -1968,6 +1971,9 @@ class HuiyuanLunxun(APIView):
'message': '会员订单尚未支付完成'
}, status=status.HTTP_400_BAD_REQUEST)
from jituan.services.member_recharge import repair_member_entitlement_if_paid
repair_member_entitlement_if_paid(dingdanid)
# 5. 查询会员信息
try:
huiyuan = Huiyuan.query.get(huiyuan_id=order.huiyuan_id)

View File

@@ -8585,6 +8585,7 @@ class KefuGetDashouDetailView(APIView):
'wechat': '',
'phone': user_main.Phone or '',
'CreateTime': user_main.UserCreateTime,
'create_time': user_main.UserCreateTime.strftime('%Y-%m-%d %H:%M:%S') if getattr(user_main, 'UserCreateTime', None) else '',
'ip': user_main.IP or '',
'jiedanzongliang': 0,
'chengjiaozongliang': 0,
@@ -8621,6 +8622,7 @@ class KefuGetDashouDetailView(APIView):
'wechat': dashou.wechat or '',
'phone': user_main.Phone or '',
'CreateTime': user_main.UserCreateTime,
'create_time': user_main.UserCreateTime.strftime('%Y-%m-%d %H:%M:%S') if getattr(user_main, 'UserCreateTime', None) else '',
'ip': user_main.IP or '',
'jiedanzongliang': dashou.jiedanzongliang,
'chengjiaozongliang': dashou.chengjiaozongliang,