```
feat(payment): 添加邀请奖励功能并重构订单支付处理逻辑 - 引入InviteReward模型用于记录邀请奖励 - 新增_process_success_order内部函数统一处理订单成功逻辑 - 实现邀请奖励机制:被邀请人前3次充值时,邀请人获得10%积分奖励 - 在支付回调、主动查询和异步通知中统一调用新的处理函数 - 改进代码结构,消除重复的订单处理逻辑 ```
This commit is contained in:
parent
0164140c39
commit
2ea495721c
@ -1,6 +1,6 @@
|
|||||||
from flask import Blueprint, request, redirect, url_for, session, jsonify, render_template
|
from flask import Blueprint, request, redirect, url_for, session, jsonify, render_template
|
||||||
from extensions import db, redis_client
|
from extensions import db, redis_client
|
||||||
from models import Order, User, to_bj_time, get_bj_now
|
from models import Order, User, InviteReward, to_bj_time, get_bj_now
|
||||||
from services.alipay_service import AlipayService
|
from services.alipay_service import AlipayService
|
||||||
from services.logger import system_logger
|
from services.logger import system_logger
|
||||||
import uuid
|
import uuid
|
||||||
@ -16,6 +16,57 @@ POINTS_PACKAGES = {
|
|||||||
'5000': {'points': 5000, 'amount': 500.00},
|
'5000': {'points': 5000, 'amount': 500.00},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def _process_success_order(order, trade_no):
|
||||||
|
"""内部处理订单成功逻辑 (需在锁内调用,不包含 commit)"""
|
||||||
|
if order.status == 'PAID':
|
||||||
|
return False
|
||||||
|
|
||||||
|
order.status = 'PAID'
|
||||||
|
order.trade_no = trade_no
|
||||||
|
order.paid_at = get_bj_now()
|
||||||
|
|
||||||
|
# 增加用户积分
|
||||||
|
user = db.session.get(User, order.user_id)
|
||||||
|
if user:
|
||||||
|
user.points += order.points
|
||||||
|
system_logger.info(f"订单支付成功", order_id=order.out_trade_no, points=order.points, user_id=user.id)
|
||||||
|
|
||||||
|
# ========== 邀请奖励逻辑 ==========
|
||||||
|
if user.invited_by:
|
||||||
|
# 统计该被邀请人之前已经完成多少次充值(不含本次)
|
||||||
|
paid_count = Order.query.filter(
|
||||||
|
Order.user_id == user.id,
|
||||||
|
Order.status == 'PAID',
|
||||||
|
Order.id != order.id
|
||||||
|
).count()
|
||||||
|
|
||||||
|
# 只有前3次充值才有奖励
|
||||||
|
if paid_count < 3:
|
||||||
|
inviter = db.session.get(User, user.invited_by)
|
||||||
|
if inviter:
|
||||||
|
# 计算10%奖励积分(四舍五入)
|
||||||
|
reward_points = round(order.points * 0.1)
|
||||||
|
if reward_points > 0:
|
||||||
|
inviter.points += reward_points
|
||||||
|
|
||||||
|
# 记录邀请奖励
|
||||||
|
invite_reward = InviteReward(
|
||||||
|
inviter_id=inviter.id,
|
||||||
|
invitee_id=user.id,
|
||||||
|
order_id=order.id,
|
||||||
|
reward_points=reward_points,
|
||||||
|
recharge_count=paid_count + 1
|
||||||
|
)
|
||||||
|
db.session.add(invite_reward)
|
||||||
|
system_logger.info(
|
||||||
|
f"邀请奖励发放成功",
|
||||||
|
inviter_id=inviter.id,
|
||||||
|
invitee_id=user.id,
|
||||||
|
reward_points=reward_points,
|
||||||
|
recharge_count=paid_count + 1
|
||||||
|
)
|
||||||
|
return True
|
||||||
|
|
||||||
@payment_bp.route('/create', methods=['POST'])
|
@payment_bp.route('/create', methods=['POST'])
|
||||||
def create_payment():
|
def create_payment():
|
||||||
if 'user_id' not in session:
|
if 'user_id' not in session:
|
||||||
@ -88,17 +139,8 @@ def payment_return():
|
|||||||
order = Order.query.filter_by(out_trade_no=out_trade_no).with_for_update().first()
|
order = Order.query.filter_by(out_trade_no=out_trade_no).with_for_update().first()
|
||||||
|
|
||||||
# 如果订单存在且状态为PENDING,则更新为PAID
|
# 如果订单存在且状态为PENDING,则更新为PAID
|
||||||
if order and order.status == 'PENDING':
|
if order:
|
||||||
order.status = 'PAID'
|
_process_success_order(order, trade_no)
|
||||||
order.trade_no = trade_no
|
|
||||||
order.paid_at = get_bj_now()
|
|
||||||
|
|
||||||
# 增加用户积分
|
|
||||||
user = db.session.get(User, order.user_id)
|
|
||||||
if user:
|
|
||||||
user.points += order.points
|
|
||||||
system_logger.info(f"同步回调-订单支付成功", order_id=out_trade_no, points=order.points, user_id=user.id)
|
|
||||||
|
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
elif order:
|
elif order:
|
||||||
# 订单已经是完成状态,不做处理
|
# 订单已经是完成状态,不做处理
|
||||||
@ -216,36 +258,28 @@ def api_sync_order():
|
|||||||
order_locked = Order.query.filter_by(out_trade_no=out_trade_no).with_for_update().first()
|
order_locked = Order.query.filter_by(out_trade_no=out_trade_no).with_for_update().first()
|
||||||
|
|
||||||
# 二次校验状态,防止异步回调/定时任务已经处理
|
# 二次校验状态,防止异步回调/定时任务已经处理
|
||||||
if order_locked and order_locked.status == 'PENDING':
|
# 二次校验状态,防止异步回调/定时任务已经处理
|
||||||
order_locked.status = 'PAID'
|
if order_locked:
|
||||||
order_locked.trade_no = alipay_result.get('trade_no')
|
processed = _process_success_order(order_locked, alipay_result.get('trade_no'))
|
||||||
if not order_locked.paid_at:
|
if processed:
|
||||||
order_locked.paid_at = get_bj_now()
|
db.session.commit()
|
||||||
|
|
||||||
# 增加用户积分
|
return jsonify({
|
||||||
user = db.session.get(User, order_locked.user_id)
|
'code': 200,
|
||||||
if user:
|
'msg': '订单已支付,积分已增加',
|
||||||
user.points += order_locked.points
|
'status': 'PAID',
|
||||||
system_logger.info(f"主动查询-订单支付成功", order_id=out_trade_no, points=order_locked.points, user_id=user.id)
|
'points': order_locked.points,
|
||||||
|
'paid_at': order_locked.paid_at_bj.strftime('%Y-%m-%d %H:%M:%S')
|
||||||
db.session.commit()
|
})
|
||||||
|
else:
|
||||||
return jsonify({
|
# 订单已经是完成状态,不做处理
|
||||||
'code': 200,
|
return jsonify({
|
||||||
'msg': '订单已支付,积分已增加',
|
'code': 200,
|
||||||
'status': 'PAID',
|
'msg': '订单已支付',
|
||||||
'points': order_locked.points,
|
'status': 'PAID',
|
||||||
'paid_at': order_locked.paid_at_bj.strftime('%Y-%m-%d %H:%M:%S')
|
'points': order_locked.points,
|
||||||
})
|
'paid_at': order_locked.paid_at_bj.strftime('%Y-%m-%d %H:%M:%S') if order_locked.paid_at else None
|
||||||
elif order_locked and order_locked.status == 'PAID':
|
})
|
||||||
# 订单已经被处理,直接返回
|
|
||||||
return jsonify({
|
|
||||||
'code': 200,
|
|
||||||
'msg': '订单已支付',
|
|
||||||
'status': 'PAID',
|
|
||||||
'points': order_locked.points,
|
|
||||||
'paid_at': order_locked.paid_at_bj.strftime('%Y-%m-%d %H:%M:%S') if order_locked.paid_at else None
|
|
||||||
})
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
if "LockError" in str(e) or "BlockingIOError" in str(e):
|
if "LockError" in str(e) or "BlockingIOError" in str(e):
|
||||||
# 如果获取锁失败,可能是因为正在处理中,返回成功状态(前端会重试或刷新)
|
# 如果获取锁失败,可能是因为正在处理中,返回成功状态(前端会重试或刷新)
|
||||||
@ -301,20 +335,10 @@ def payment_notify():
|
|||||||
lock_key = f"lock:order:{out_trade_no}"
|
lock_key = f"lock:order:{out_trade_no}"
|
||||||
with redis_client.lock(lock_key, timeout=10, blocking_timeout=3):
|
with redis_client.lock(lock_key, timeout=10, blocking_timeout=3):
|
||||||
order = Order.query.filter_by(out_trade_no=out_trade_no).with_for_update().first()
|
order = Order.query.filter_by(out_trade_no=out_trade_no).with_for_update().first()
|
||||||
if order and order.status == 'PENDING':
|
if order:
|
||||||
order.status = 'PAID'
|
_process_success_order(order, trade_no)
|
||||||
order.trade_no = trade_no
|
|
||||||
order.paid_at = get_bj_now()
|
|
||||||
|
|
||||||
user = db.session.get(User, order.user_id)
|
|
||||||
if user:
|
|
||||||
user.points += order.points
|
|
||||||
system_logger.info(f"订单支付成功", order_id=out_trade_no, points=order.points, user_id=user.id)
|
|
||||||
|
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
return "success"
|
return "success"
|
||||||
elif order:
|
|
||||||
return "success"
|
|
||||||
else:
|
else:
|
||||||
return "fail"
|
return "fail"
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
@ -327,59 +351,12 @@ def payment_notify():
|
|||||||
return "fail"
|
return "fail"
|
||||||
raise e
|
raise e
|
||||||
order = Order.query.filter_by(out_trade_no=out_trade_no).first()
|
order = Order.query.filter_by(out_trade_no=out_trade_no).first()
|
||||||
if order and order.status == 'PENDING':
|
if order:
|
||||||
order.status = 'PAID'
|
_process_success_order(order, trade_no)
|
||||||
order.trade_no = trade_no
|
db.session.commit()
|
||||||
order.paid_at = get_bj_now()
|
return "success"
|
||||||
|
|
||||||
user = db.session.get(User, order.user_id)
|
|
||||||
if user:
|
|
||||||
user.points += order.points
|
|
||||||
system_logger.info(f"订单支付成功", order_id=out_trade_no, points=order.points, user_id=user.id)
|
|
||||||
|
|
||||||
# ========== 邀请奖励逻辑 ==========
|
|
||||||
if user.invited_by:
|
|
||||||
from models import InviteReward
|
|
||||||
# 统计该被邀请人之前已经完成多少次充值(不含本次)
|
|
||||||
paid_count = Order.query.filter(
|
|
||||||
Order.user_id == user.id,
|
|
||||||
Order.status == 'PAID',
|
|
||||||
Order.id != order.id # 排除本次订单
|
|
||||||
).count()
|
|
||||||
|
|
||||||
# 只有前3次充值才有奖励(paid_count 是之前的次数,0/1/2 表示这是第1/2/3次)
|
|
||||||
if paid_count < 3:
|
|
||||||
inviter = db.session.get(User, user.invited_by)
|
|
||||||
if inviter:
|
|
||||||
# 计算10%奖励积分(四舍五入)
|
|
||||||
reward_points = round(order.points * 0.1)
|
|
||||||
if reward_points > 0:
|
|
||||||
inviter.points += reward_points
|
|
||||||
|
|
||||||
# 记录邀请奖励
|
|
||||||
invite_reward = InviteReward(
|
|
||||||
inviter_id=inviter.id,
|
|
||||||
invitee_id=user.id,
|
|
||||||
order_id=order.id,
|
|
||||||
reward_points=reward_points,
|
|
||||||
recharge_count=paid_count + 1 # 第几次充值
|
|
||||||
)
|
|
||||||
db.session.add(invite_reward)
|
|
||||||
system_logger.info(
|
|
||||||
f"邀请奖励发放成功",
|
|
||||||
inviter_id=inviter.id,
|
|
||||||
invitee_id=user.id,
|
|
||||||
reward_points=reward_points,
|
|
||||||
recharge_count=paid_count + 1
|
|
||||||
)
|
|
||||||
# ========== 邀请奖励逻辑结束 ==========
|
|
||||||
|
|
||||||
db.session.commit()
|
|
||||||
return "success"
|
|
||||||
elif order:
|
|
||||||
return "success"
|
|
||||||
else:
|
else:
|
||||||
return "fail"
|
return "fail"
|
||||||
else:
|
else:
|
||||||
return "fail"
|
return "fail"
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user