我正在开发一个使用 Stripe API 来管理订阅的 Python 应用程序。我提供多种不同价位的订阅计划,特别是 42 美元和 70 美元。
我正在尝试使用 Stripe 的 Python 库实现以下场景,并正在寻求有关如何继续的帮助。
场景一:订阅升级/降级
当用户想要更改他们的订阅(从 42 美元计划升级到 70 美元计划或从 70 美元计划降级到 42 美元计划)时,我想计算他们应该收取的金额如下:
新计划价格 - 旧计划价格 - 根据他们已经使用该应用程序的时间按比例分配的金额。 我希望通过 Stripe Checkout 会话进行此交易。
场景2:计费周期维护
无论用户升级还是降级他们的套餐,我希望他们的计费周期保持不变。因此,例如,如果用户在 2023 年 3 月 8 日 12:45 更改订阅,他们将立即支付按比例分配的差额,然后在 2023 年 3 月 9 日 12:45,他们将被收取全价他们的新订阅计划。
任何有关如何实施这些场景的指导将不胜感激。请注意,我专门寻找使用 Stripe Python 库的解决方案。
这是我现有的一些代码,可以让您了解我当前的方法:
@stripe_blueprint.route('/stripe/<string:product_id>/<string:recurring_type>', methods=['POST', 'GET'])
def stripe_payment(product_id, recurring_type):
global sidebar_links
user = None
subscription_id = None
expiry_date_timestamp_int = None
# product_types = ['plan', 'addon', 'one_time','top_up']
if current_user.is_authenticated:
user = load_user_or_sub(current_user)
# if the user does not have a stripe customer id, create stripe customer
customer_id = stripe.Customer.retrieve(user.stripe_customer_id)
if customer_id.get('deleted') or not user.stripe_customer_id:
logger.info(f'User {user.id} has a deleted stripe customer id or does not have a stripe customer id, creating one')
create_stripe_customer(user)
if PRODUCTS_JSON.get(product_id) is None:
return abort(404)
if recurring_type == 'monthly':
price_id = PRODUCTS_JSON[product_id]['month']['id']
elif recurring_type == "yearly":
price_id = PRODUCTS_JSON[product_id]['year']['id']
else:
return abort(404)
try:
# Retrieve and update the subscription only if the user is authenticated and they have a valid subscription
if user and user.stripe_subscription_id:
subscription = stripe.Subscription.retrieve(user.stripe_subscription_id)
if subscription['status'] != 'canceled':
# Assuming subscription_expiry_date is the string representation of your user's subscription expiry date
subscription_expiry_date_str = user.subscription_expired_date
# subscription_expiry_date_str = "03/08/2023 12:40"
# Convert the string to a datetime object
expiry_date_obj = datetime.strptime(subscription_expiry_date_str, "%d/%m/%Y %H:%M")
# Convert the datetime object to a Unix timestamp
expiry_date_timestamp = time.mktime(expiry_date_obj.timetuple())
# Convert the Unix timestamp to an integer
expiry_date_timestamp_int = int(expiry_date_timestamp)
checkout_session = checkout.Session.create(
line_items=[{"price": price_id, "quantity": 1}],
client_reference_id=user.user_hash_identifier if user else None,
payment_method_types=['card'],
mode="subscription",
billing_address_collection='required',
allow_promotion_codes=True,
customer=user.stripe_customer_id if user else None,
metadata={'recurring_type': recurring_type},
subscription_data={"billing_cycle_anchor": expiry_date_timestamp_int, "proration_behavior": "create_prorations"} if expiry_date_timestamp_int else None,
locale='auto',
success_url=url_for('stripe_blueprint.order_success', _external=True) + '?session_id={CHECKOUT_SESSION_ID}',
cancel_url=url_for('stripe_blueprint.order_cancel', _external=True),
)
except Exception as e:
logger.error(f'User {user.id} failed to pay for {id} due to {e}')
return str(e)
return redirect(checkout_session.url, code=303)