update pay function
This commit is contained in:
96
app.py
96
app.py
@@ -1427,6 +1427,10 @@ def calculate_subscription_price_simple(user_id, to_plan_name, to_cycle, promo_c
|
||||
remaining_value = current_price * (remaining_days / total_days)
|
||||
# 实付金额 = 新套餐价格 - 剩余价值
|
||||
final_price = max(0, price - remaining_value)
|
||||
|
||||
# 如果剩余价值 >= 新套餐价格,标记为免费升级
|
||||
if remaining_value >= price:
|
||||
final_price = 0
|
||||
elif current_plan == 'max' and to_plan_name == 'pro':
|
||||
# 降级:Max → Pro,到期后切换,全价购买
|
||||
is_downgrade = True
|
||||
@@ -1786,6 +1790,89 @@ def calculate_subscription_price():
|
||||
}), 500
|
||||
|
||||
|
||||
@app.route('/api/subscription/free-upgrade', methods=['POST'])
|
||||
@login_required
|
||||
def free_upgrade_subscription():
|
||||
"""
|
||||
免费升级订阅(当剩余价值 >= 新套餐价格时)
|
||||
|
||||
Request Body:
|
||||
{
|
||||
"plan_name": "max",
|
||||
"billing_cycle": "yearly"
|
||||
}
|
||||
"""
|
||||
try:
|
||||
data = request.get_json()
|
||||
plan_name = data.get('plan_name')
|
||||
billing_cycle = data.get('billing_cycle')
|
||||
|
||||
if not plan_name or not billing_cycle:
|
||||
return jsonify({'success': False, 'error': '参数不完整'}), 400
|
||||
|
||||
user_id = current_user.id
|
||||
|
||||
# 计算价格,验证是否可以免费升级
|
||||
price_result = calculate_subscription_price_simple(user_id, plan_name, billing_cycle, None)
|
||||
|
||||
if 'error' in price_result:
|
||||
return jsonify({'success': False, 'error': price_result['error']}), 400
|
||||
|
||||
# 检查是否为升级且实付金额为0
|
||||
if not price_result.get('is_upgrade') or price_result.get('final_amount', 1) > 0:
|
||||
return jsonify({'success': False, 'error': '当前情况不符合免费升级条件'}), 400
|
||||
|
||||
# 获取当前订阅
|
||||
subscription = UserSubscription.query.filter_by(user_id=user_id).first()
|
||||
if not subscription:
|
||||
return jsonify({'success': False, 'error': '未找到订阅记录'}), 404
|
||||
|
||||
# 计算新的到期时间(按剩余价值折算)
|
||||
remaining_value = price_result.get('remaining_value', 0)
|
||||
new_plan_price = price_result.get('new_plan_price', 0)
|
||||
|
||||
if new_plan_price > 0:
|
||||
# 计算可以兑换的新套餐天数
|
||||
value_ratio = remaining_value / new_plan_price
|
||||
|
||||
cycle_days_map = {
|
||||
'monthly': 30,
|
||||
'quarterly': 90,
|
||||
'semiannual': 180,
|
||||
'yearly': 365
|
||||
}
|
||||
new_cycle_days = cycle_days_map.get(billing_cycle, 365)
|
||||
|
||||
# 新的到期天数 = 周期天数 × 价值比例
|
||||
new_days = int(new_cycle_days * value_ratio)
|
||||
|
||||
# 更新订阅信息
|
||||
subscription.subscription_type = plan_name
|
||||
subscription.billing_cycle = billing_cycle
|
||||
subscription.start_date = datetime.utcnow()
|
||||
subscription.end_date = datetime.utcnow() + timedelta(days=new_days)
|
||||
subscription.subscription_status = 'active'
|
||||
subscription.updated_at = datetime.utcnow()
|
||||
|
||||
db.session.commit()
|
||||
|
||||
return jsonify({
|
||||
'success': True,
|
||||
'message': f'升级成功!您的{plan_name.upper()}版本将持续{new_days}天',
|
||||
'data': {
|
||||
'subscription_type': plan_name,
|
||||
'end_date': subscription.end_date.isoformat(),
|
||||
'days': new_days
|
||||
}
|
||||
})
|
||||
else:
|
||||
return jsonify({'success': False, 'error': '价格计算异常'}), 500
|
||||
|
||||
except Exception as e:
|
||||
db.session.rollback()
|
||||
return jsonify({'success': False, 'error': f'升级失败: {str(e)}'}), 500
|
||||
|
||||
|
||||
@app.route('/api/payment/create-order', methods=['POST'])
|
||||
def create_payment_order():
|
||||
"""
|
||||
@@ -1819,6 +1906,15 @@ def create_payment_order():
|
||||
amount = price_result['final_amount']
|
||||
subscription_type = price_result.get('subscription_type', 'new') # new 或 renew
|
||||
|
||||
# 检查是否为免费升级(金额为0)
|
||||
if amount <= 0 and price_result.get('is_upgrade'):
|
||||
return jsonify({
|
||||
'success': False,
|
||||
'error': '当前剩余价值可直接免费升级,请使用免费升级功能',
|
||||
'should_free_upgrade': True,
|
||||
'price_info': price_result
|
||||
}), 400
|
||||
|
||||
# 创建订单
|
||||
try:
|
||||
order = PaymentOrder(
|
||||
|
||||
@@ -270,6 +270,46 @@ export default function SubscriptionContentNew() {
|
||||
try {
|
||||
const price = priceInfo?.final_amount || getCurrentPrice(selectedPlan);
|
||||
|
||||
// 检查是否为免费升级(剩余价值足够抵扣新套餐价格)
|
||||
if (price === 0 && priceInfo?.is_upgrade) {
|
||||
const response = await fetch('/api/subscription/free-upgrade', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
credentials: 'include',
|
||||
body: JSON.stringify({
|
||||
plan_name: selectedPlan.name,
|
||||
billing_cycle: selectedCycle,
|
||||
}),
|
||||
});
|
||||
|
||||
const data = await response.json();
|
||||
if (data.success) {
|
||||
subscriptionEvents.trackPaymentSuccessful({
|
||||
planName: selectedPlan.name,
|
||||
paymentMethod: 'free_upgrade',
|
||||
amount: 0,
|
||||
orderId: 'free_upgrade',
|
||||
transactionId: 'free_upgrade',
|
||||
});
|
||||
|
||||
toast({
|
||||
title: '升级成功!',
|
||||
description: data.message,
|
||||
status: 'success',
|
||||
duration: 5000,
|
||||
isClosable: true,
|
||||
});
|
||||
|
||||
onClose();
|
||||
setTimeout(() => window.location.reload(), 2000);
|
||||
return;
|
||||
} else {
|
||||
throw new Error(data.error || '免费升级失败');
|
||||
}
|
||||
}
|
||||
|
||||
subscriptionEvents.trackPaymentInitiated({
|
||||
planName: selectedPlan.name,
|
||||
paymentMethod: 'wechat_pay',
|
||||
@@ -1122,7 +1162,9 @@ export default function SubscriptionContentNew() {
|
||||
<HStack spacing={2}>
|
||||
<Icon as={FaCheck} color="green.400" />
|
||||
<Text color="green.400" fontSize="sm" fontWeight="medium">
|
||||
升级到{selectedPlan.displayName},立即生效!按差价补缴费用
|
||||
{priceInfo.final_amount === 0
|
||||
? `恭喜!您的当前订阅剩余价值足够直接升级到${selectedPlan.displayName},无需支付额外费用!`
|
||||
: `升级到${selectedPlan.displayName},立即生效!按差价补缴费用`}
|
||||
</Text>
|
||||
</HStack>
|
||||
</Box>
|
||||
@@ -1293,7 +1335,9 @@ export default function SubscriptionContentNew() {
|
||||
bgGradient: 'linear-gradient(135deg, #F4E3A7, #D4AF37)',
|
||||
}}
|
||||
>
|
||||
创建微信支付订单
|
||||
{priceInfo?.is_upgrade && priceInfo?.final_amount === 0
|
||||
? '立即免费升级'
|
||||
: '创建微信支付订单'}
|
||||
</Button>
|
||||
</VStack>
|
||||
) : (
|
||||
|
||||
@@ -163,7 +163,7 @@ export const subscriptionConfig = {
|
||||
},
|
||||
{
|
||||
question: 'Pro用户如何升级到Max?',
|
||||
answer: '从Pro升级到Max需要补差价,升级后立即生效。系统会根据您Pro订阅的剩余价值计算需要补缴的费用。支付成功后,您将立即获得Max版本的所有功能。',
|
||||
answer: '从Pro升级到Max需要补差价,升级后立即生效。系统会根据您Pro订阅的剩余价值计算需要补缴的费用。支付成功后,您将立即获得Max版本的所有功能。\n\n特别说明:如果您的Pro订阅剩余价值超过或等于Max套餐的价格,系统将自动为您免费升级到Max版本,无需支付额外费用。升级后的有效期将根据剩余价值按比例计算。例如:您的Pro年付版本剩余价值为1200元,选择Max月付版本(998元/月),系统将为您提供约36天的Max版本使用时长(1200÷998×30天)。',
|
||||
},
|
||||
{
|
||||
question: 'Max用户可以切换到Pro吗?',
|
||||
|
||||
Reference in New Issue
Block a user