Jun 28 - Update tenant bill management
This commit is contained in:
+19
-3
@@ -109,20 +109,24 @@ def _on_checkout_completed(obj):
|
|||||||
|
|
||||||
|
|
||||||
def _on_subscription_updated(obj):
|
def _on_subscription_updated(obj):
|
||||||
"""customer.subscription.updated — sync status from Stripe."""
|
"""customer.subscription.updated — sync status and plan from Stripe."""
|
||||||
customer_id = obj.get('customer')
|
customer_id = obj.get('customer')
|
||||||
subscription_id = obj.get('id')
|
subscription_id = obj.get('id')
|
||||||
stripe_status = obj.get('status', '')
|
stripe_status = obj.get('status', '')
|
||||||
period_end_ts = obj.get('current_period_end')
|
period_end_ts = obj.get('current_period_end')
|
||||||
trial_end_ts = obj.get('trial_end')
|
trial_end_ts = obj.get('trial_end')
|
||||||
|
|
||||||
|
# Extract the price ID from the first subscription item (plan change detection).
|
||||||
|
items = obj.get('items', {}).get('data', [])
|
||||||
|
new_price_id = items[0].get('price', {}).get('id') if items else None
|
||||||
|
|
||||||
our_status = _STRIPE_STATUS_MAP.get(stripe_status)
|
our_status = _STRIPE_STATUS_MAP.get(stripe_status)
|
||||||
if our_status is None:
|
if our_status is None:
|
||||||
logger.warning('BILLING | subscription_updated_unknown_status | status=%s', stripe_status)
|
logger.warning('BILLING | subscription_updated_unknown_status | status=%s', stripe_status)
|
||||||
return
|
return
|
||||||
|
|
||||||
from control.base import control_session
|
from control.base import control_session
|
||||||
from control.models import Tenant, TenantAudit
|
from control.models import Tenant, Plan, TenantAudit
|
||||||
|
|
||||||
with control_session() as s:
|
with control_session() as s:
|
||||||
t = s.query(Tenant).filter_by(stripe_customer_id=customer_id).first()
|
t = s.query(Tenant).filter_by(stripe_customer_id=customer_id).first()
|
||||||
@@ -131,16 +135,28 @@ def _on_subscription_updated(obj):
|
|||||||
return
|
return
|
||||||
|
|
||||||
old_status = t.subscription_status
|
old_status = t.subscription_status
|
||||||
|
old_plan_id = t.plan_id
|
||||||
|
|
||||||
t.subscription_status = our_status
|
t.subscription_status = our_status
|
||||||
t.stripe_subscription_id = subscription_id
|
t.stripe_subscription_id = subscription_id
|
||||||
t.current_period_end = _ts_to_dt(period_end_ts)
|
t.current_period_end = _ts_to_dt(period_end_ts)
|
||||||
if trial_end_ts:
|
if trial_end_ts:
|
||||||
t.trial_ends_at = _ts_to_dt(trial_end_ts)
|
t.trial_ends_at = _ts_to_dt(trial_end_ts)
|
||||||
|
|
||||||
|
# Sync plan when the price changes (upgrade / downgrade via portal).
|
||||||
|
plan_detail = ''
|
||||||
|
if new_price_id:
|
||||||
|
matched_plan = s.query(Plan).filter_by(stripe_price_id=new_price_id).first()
|
||||||
|
if matched_plan and matched_plan.id != old_plan_id:
|
||||||
|
t.plan_id = matched_plan.id
|
||||||
|
plan_detail = f' plan={old_plan_id}→{matched_plan.id}({matched_plan.code})'
|
||||||
|
logger.info('BILLING | plan_changed | tenant_id=%s plan=%s→%s',
|
||||||
|
t.id, old_plan_id, matched_plan.id)
|
||||||
|
|
||||||
s.add(TenantAudit(
|
s.add(TenantAudit(
|
||||||
action='billing_subscription_updated',
|
action='billing_subscription_updated',
|
||||||
tenant_id=t.id,
|
tenant_id=t.id,
|
||||||
details=f'stripe_status={stripe_status} our_status={our_status} prev={old_status}',
|
details=f'stripe_status={stripe_status} our_status={our_status} prev={old_status}{plan_detail}',
|
||||||
))
|
))
|
||||||
|
|
||||||
logger.info('BILLING | subscription_updated | tenant_id=%s %s→%s', t.id, old_status, our_status)
|
logger.info('BILLING | subscription_updated | tenant_id=%s %s→%s', t.id, old_status, our_status)
|
||||||
|
|||||||
Reference in New Issue
Block a user