Add subcription feature 9

This commit is contained in:
Urtzi Alfaro
2026-01-16 20:25:45 +01:00
parent fa7b62bd6c
commit 3a7d57ef90
19 changed files with 1833 additions and 985 deletions

View File

@@ -1324,7 +1324,9 @@ class StripeClient(PaymentProvider):
async def update_subscription(
self,
subscription_id: str,
new_price_id: str
new_price_id: str,
proration_behavior: str = 'create_prorations',
preserve_trial: bool = False
) -> Dict[str, Any]:
"""
Update subscription price (plan upgrade/downgrade)
@@ -1332,35 +1334,69 @@ class StripeClient(PaymentProvider):
Args:
subscription_id: Subscription ID
new_price_id: New price ID
proration_behavior: How to handle proration ('create_prorations', 'none', 'always_invoice')
- 'none': No proration charges (useful during trial)
- 'create_prorations': Create prorated charges (default)
- 'always_invoice': Always create an invoice
preserve_trial: If True, preserves the trial period after upgrade
Returns:
Subscription update result
Subscription update result including trial info
"""
try:
subscription = stripe.Subscription.retrieve(subscription_id)
updated_subscription = stripe.Subscription.modify(
subscription_id,
items=[{
# Check if subscription is currently trialing
is_trialing = subscription.status == 'trialing'
trial_end = subscription.trial_end
# Build the modification params
modify_params = {
'items': [{
'id': subscription['items']['data'][0].id,
'price': new_price_id,
}],
proration_behavior='create_prorations',
idempotency_key=f"update_sub_{uuid.uuid4()}"
'proration_behavior': proration_behavior,
'idempotency_key': f"update_sub_{uuid.uuid4()}"
}
# Preserve trial period if requested and currently trialing
# When changing plans during trial, Stripe will by default end the trial
# By explicitly setting trial_end, we preserve it
if preserve_trial and is_trialing and trial_end:
modify_params['trial_end'] = trial_end
logger.info(
"Preserving trial period during upgrade",
extra={
"subscription_id": subscription_id,
"trial_end": trial_end
}
)
updated_subscription = stripe.Subscription.modify(
subscription_id,
**modify_params
)
logger.info(
"Subscription updated",
extra={
"subscription_id": subscription_id,
"new_price_id": new_price_id
"new_price_id": new_price_id,
"proration_behavior": proration_behavior,
"was_trialing": is_trialing,
"new_status": updated_subscription.status
}
)
return {
'subscription_id': updated_subscription.id,
'status': updated_subscription.status,
'current_period_end': updated_subscription.current_period_end
'current_period_start': updated_subscription.current_period_start,
'current_period_end': updated_subscription.current_period_end,
'trial_end': updated_subscription.trial_end,
'is_trialing': updated_subscription.status == 'trialing',
'customer_id': updated_subscription.customer
}
except stripe.error.StripeError as e:
@@ -1537,6 +1573,13 @@ class StripeClient(PaymentProvider):
try:
invoices = stripe.Invoice.list(customer=customer_id, limit=10)
# Debug: Log all invoice IDs and amounts to see what Stripe returns
logger.info("stripe_invoices_retrieved",
customer_id=customer_id,
invoice_count=len(invoices.data),
invoice_ids=[inv.id for inv in invoices.data],
invoice_amounts=[inv.amount_due for inv in invoices.data])
return {
'invoices': [
{
@@ -1545,7 +1588,12 @@ class StripeClient(PaymentProvider):
'amount_paid': inv.amount_paid / 100,
'status': inv.status,
'created': inv.created,
'invoice_pdf': inv.invoice_pdf
'invoice_pdf': inv.invoice_pdf,
'hosted_invoice_url': inv.hosted_invoice_url,
'number': inv.number,
'currency': inv.currency,
'description': inv.description,
'trial': inv.amount_due == 0 # Mark trial invoices
}
for inv in invoices.data
]