255 lines
8.0 KiB
Python
255 lines
8.0 KiB
Python
"""
|
|
支付视图
|
|
"""
|
|
from flask import Blueprint, render_template, request, jsonify, session, redirect, url_for, flash
|
|
from app.models.payment import Payment
|
|
from app.models.order import Order
|
|
from app.utils.decorators import login_required
|
|
from config.database import db
|
|
from datetime import datetime
|
|
import time
|
|
import random
|
|
|
|
payment_bp = Blueprint('payment', __name__, url_prefix='/payment')
|
|
|
|
|
|
@payment_bp.route('/process', methods=['POST'])
|
|
@login_required
|
|
def process():
|
|
"""处理支付请求"""
|
|
try:
|
|
user_id = session['user_id']
|
|
payment_sn = request.json.get('payment_sn')
|
|
payment_method = request.json.get('payment_method')
|
|
|
|
if not payment_sn:
|
|
return jsonify({'success': False, 'message': '支付流水号不能为空'})
|
|
|
|
# 获取支付记录
|
|
payment = Payment.query.filter_by(payment_sn=payment_sn).first()
|
|
if not payment:
|
|
return jsonify({'success': False, 'message': '支付记录不存在'})
|
|
|
|
order = payment.order
|
|
if order.user_id != user_id:
|
|
return jsonify({'success': False, 'message': '订单不存在'})
|
|
|
|
if not order.can_pay():
|
|
return jsonify({'success': False, 'message': '订单不可支付'})
|
|
|
|
# 根据支付方式处理
|
|
if payment_method == 'wechat':
|
|
# 微信支付
|
|
result = process_wechat_pay(payment)
|
|
elif payment_method == 'alipay':
|
|
# 支付宝支付
|
|
result = process_alipay(payment)
|
|
elif payment_method == 'bank':
|
|
# 银行卡支付
|
|
result = process_bank_pay(payment)
|
|
elif payment_method == 'simulate':
|
|
# 模拟支付
|
|
result = process_simulate_pay(payment)
|
|
else:
|
|
return jsonify({'success': False, 'message': '不支持的支付方式'})
|
|
|
|
return jsonify(result)
|
|
|
|
except Exception as e:
|
|
return jsonify({'success': False, 'message': f'支付处理失败: {str(e)}'})
|
|
|
|
|
|
def process_wechat_pay(payment):
|
|
"""处理微信支付"""
|
|
# TODO: 接入真实的微信支付API
|
|
# 目前返回模拟的支付二维码
|
|
|
|
# 模拟生成支付二维码数据
|
|
qr_code_url = f"weixin://wxpay/bizpayurl?pr={payment.payment_sn}"
|
|
|
|
return {
|
|
'success': True,
|
|
'payment_type': 'qrcode',
|
|
'qr_code_url': qr_code_url,
|
|
'payment_sn': payment.payment_sn,
|
|
'amount': float(payment.amount),
|
|
'message': '请使用微信扫码支付'
|
|
}
|
|
|
|
|
|
def process_alipay(payment):
|
|
"""处理支付宝支付"""
|
|
# TODO: 接入真实的支付宝API
|
|
# 目前返回模拟的跳转链接
|
|
|
|
pay_url = f"https://mapi.alipay.com/gateway.do?service=create_direct_pay_by_user&payment_sn={payment.payment_sn}"
|
|
|
|
return {
|
|
'success': True,
|
|
'payment_type': 'redirect',
|
|
'pay_url': pay_url,
|
|
'payment_sn': payment.payment_sn,
|
|
'amount': float(payment.amount),
|
|
'message': '正在跳转到支付宝...'
|
|
}
|
|
|
|
|
|
def process_bank_pay(payment):
|
|
"""处理银行卡支付"""
|
|
# TODO: 接入银行支付网关
|
|
# 目前返回模拟的网银链接
|
|
|
|
bank_url = f"https://pay.bank.com/pay?order={payment.payment_sn}"
|
|
|
|
return {
|
|
'success': True,
|
|
'payment_type': 'redirect',
|
|
'pay_url': bank_url,
|
|
'payment_sn': payment.payment_sn,
|
|
'amount': float(payment.amount),
|
|
'message': '正在跳转到网银...'
|
|
}
|
|
|
|
|
|
def process_simulate_pay(payment):
|
|
"""处理模拟支付"""
|
|
return {
|
|
'success': True,
|
|
'payment_type': 'simulate',
|
|
'payment_sn': payment.payment_sn,
|
|
'amount': float(payment.amount),
|
|
'message': '模拟支付模式,可直接完成支付'
|
|
}
|
|
|
|
|
|
@payment_bp.route('/callback/wechat', methods=['POST'])
|
|
def wechat_callback():
|
|
"""微信支付回调"""
|
|
try:
|
|
# TODO: 验证微信支付回调签名
|
|
# 目前模拟处理
|
|
|
|
callback_data = request.get_data()
|
|
# 解析回调数据,获取支付结果
|
|
|
|
# 模拟成功的回调处理
|
|
return handle_payment_success(request.form.get('payment_sn'), 'wechat_success_' + str(datetime.now().timestamp()))
|
|
|
|
except Exception as e:
|
|
return f"FAIL: {str(e)}"
|
|
|
|
|
|
@payment_bp.route('/callback/alipay', methods=['POST'])
|
|
def alipay_callback():
|
|
"""支付宝支付回调"""
|
|
try:
|
|
# TODO: 验证支付宝回调签名
|
|
# 目前模拟处理
|
|
|
|
return handle_payment_success(request.form.get('payment_sn'), 'alipay_success_' + str(datetime.now().timestamp()))
|
|
|
|
except Exception as e:
|
|
return f"FAIL: {str(e)}"
|
|
|
|
|
|
def handle_payment_success(payment_sn, third_party_sn):
|
|
"""处理支付成功"""
|
|
try:
|
|
payment = Payment.query.filter_by(payment_sn=payment_sn).first()
|
|
if not payment:
|
|
return "FAIL: Payment not found"
|
|
|
|
if payment.status == Payment.STATUS_SUCCESS:
|
|
return "SUCCESS" # 已经处理过的支付
|
|
|
|
# 更新支付状态
|
|
payment.status = Payment.STATUS_SUCCESS
|
|
payment.third_party_sn = third_party_sn
|
|
payment.paid_at = datetime.utcnow()
|
|
|
|
# 更新订单状态
|
|
order = payment.order
|
|
order.status = Order.STATUS_PENDING_SHIPMENT
|
|
|
|
db.session.commit()
|
|
|
|
return "SUCCESS"
|
|
|
|
except Exception as e:
|
|
db.session.rollback()
|
|
return f"FAIL: {str(e)}"
|
|
|
|
|
|
@payment_bp.route('/check_status/<payment_sn>')
|
|
@login_required
|
|
def check_status(payment_sn):
|
|
"""检查支付状态"""
|
|
try:
|
|
user_id = session['user_id']
|
|
payment = Payment.query.filter_by(payment_sn=payment_sn).first()
|
|
|
|
if not payment or payment.order.user_id != user_id:
|
|
return jsonify({'success': False, 'message': '支付记录不存在'})
|
|
|
|
return jsonify({
|
|
'success': True,
|
|
'status': payment.status,
|
|
'status_text': payment.get_status_text(),
|
|
'paid_at': payment.paid_at.isoformat() if payment.paid_at else None
|
|
})
|
|
|
|
except Exception as e:
|
|
return jsonify({'success': False, 'message': f'查询失败: {str(e)}'})
|
|
|
|
|
|
@payment_bp.route('/simulate_success/<payment_sn>', methods=['POST'])
|
|
@login_required
|
|
def simulate_success(payment_sn):
|
|
"""模拟支付成功(开发测试用)"""
|
|
try:
|
|
user_id = session['user_id']
|
|
payment = Payment.query.filter_by(payment_sn=payment_sn).first()
|
|
|
|
if not payment or payment.order.user_id != user_id:
|
|
return jsonify({'success': False, 'message': '支付记录不存在'})
|
|
|
|
if payment.status == Payment.STATUS_SUCCESS:
|
|
return jsonify({'success': False, 'message': '订单已支付'})
|
|
|
|
# 模拟支付成功
|
|
result = handle_payment_success(payment_sn, f'SIMULATE_{int(time.time())}_{random.randint(1000, 9999)}')
|
|
|
|
if result == "SUCCESS":
|
|
return jsonify({'success': True, 'message': '支付成功'})
|
|
else:
|
|
return jsonify({'success': False, 'message': result})
|
|
|
|
except Exception as e:
|
|
return jsonify({'success': False, 'message': f'模拟支付失败: {str(e)}'})
|
|
|
|
|
|
@payment_bp.route('/simulate_fail/<payment_sn>', methods=['POST'])
|
|
@login_required
|
|
def simulate_fail(payment_sn):
|
|
"""模拟支付失败(开发测试用)"""
|
|
try:
|
|
user_id = session['user_id']
|
|
payment = Payment.query.filter_by(payment_sn=payment_sn).first()
|
|
|
|
if not payment or payment.order.user_id != user_id:
|
|
return jsonify({'success': False, 'message': '支付记录不存在'})
|
|
|
|
if payment.status == Payment.STATUS_SUCCESS:
|
|
return jsonify({'success': False, 'message': '订单已支付,无法模拟失败'})
|
|
|
|
# 模拟支付失败
|
|
payment.status = Payment.STATUS_FAILED
|
|
payment.third_party_sn = f'SIMULATE_FAIL_{int(time.time())}_{random.randint(1000, 9999)}'
|
|
db.session.commit()
|
|
|
|
return jsonify({'success': True, 'message': '模拟支付失败'})
|
|
|
|
except Exception as e:
|
|
db.session.rollback()
|
|
return jsonify({'success': False, 'message': f'模拟支付失败操作失败: {str(e)}'})
|