diff --git a/blueprints/payment.py b/blueprints/payment.py index 8d06c8d..5ce046e 100644 --- a/blueprints/payment.py +++ b/blueprints/payment.py @@ -1,6 +1,6 @@ from flask import Blueprint, request, redirect, url_for, session, jsonify, render_template 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.logger import system_logger import uuid @@ -16,6 +16,57 @@ POINTS_PACKAGES = { '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']) def create_payment(): 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() # 如果订单存在且状态为PENDING,则更新为PAID - if order and order.status == 'PENDING': - 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=out_trade_no, points=order.points, user_id=user.id) - + if order: + _process_success_order(order, trade_no) db.session.commit() 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() # 二次校验状态,防止异步回调/定时任务已经处理 - if order_locked and order_locked.status == 'PENDING': - order_locked.status = 'PAID' - order_locked.trade_no = alipay_result.get('trade_no') - if not order_locked.paid_at: - order_locked.paid_at = get_bj_now() - - # 增加用户积分 - user = db.session.get(User, order_locked.user_id) - if user: - user.points += order_locked.points - system_logger.info(f"主动查询-订单支付成功", order_id=out_trade_no, points=order_locked.points, user_id=user.id) - - db.session.commit() - - 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') - }) - 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 - }) + # 二次校验状态,防止异步回调/定时任务已经处理 + if order_locked: + processed = _process_success_order(order_locked, alipay_result.get('trade_no')) + if processed: + db.session.commit() + + 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') + }) + else: + # 订单已经是完成状态,不做处理 + 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: 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}" 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() - if order and order.status == 'PENDING': - 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=out_trade_no, points=order.points, user_id=user.id) - + if order: + _process_success_order(order, trade_no) db.session.commit() return "success" - elif order: - return "success" else: return "fail" except Exception as e: @@ -327,59 +351,12 @@ def payment_notify(): return "fail" raise e order = Order.query.filter_by(out_trade_no=out_trade_no).first() - if order and order.status == 'PENDING': - 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=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" + if order: + _process_success_order(order, trade_no) + db.session.commit() + return "success" else: - return "fail" + return "fail" else: return "fail"