Files
sure/app/models/family/subscribeable.rb
Juan José Mata 6b5a5b1877 fix: Show cancellation message when subscription is pending cancellation (#752)
* fix: Show cancellation message when subscription is pending cancellation

When a subscription is cancelled via Stripe, the UI incorrectly showed
"Your contribution continues on..." instead of reflecting the cancellation
status. This fix adds tracking of `cancel_at_period_end` from Stripe webhooks
and displays "Your contribution ends on..." when a subscription has been
cancelled but is still active until the billing period ends.

https://claude.ai/code/session_01Y8ELTdK1k9o315iSq43TRN

* chore: Update schema.rb with cancel_at_period_end column

https://claude.ai/code/session_01Y8ELTdK1k9o315iSq43TRN

* Schema version

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-01-23 18:55:51 +01:00

89 lines
2.1 KiB
Ruby

module Family::Subscribeable
extend ActiveSupport::Concern
included do
has_one :subscription, dependent: :destroy
end
def payment_email
primary_admin = users.admin.order(:created_at).first || users.super_admin.order(:created_at).first
unless primary_admin.present?
raise "No primary admin found for family #{id}. This is an invalid data state and should never occur."
end
primary_admin.email
end
def upgrade_required?
return false if self_hoster?
return false if subscription&.active? || subscription&.trialing?
true
end
def can_start_trial?
subscription&.trial_ends_at.blank?
end
def start_trial_subscription!
create_subscription!(
status: "trialing",
trial_ends_at: Subscription.new_trial_ends_at
)
end
def trialing?
subscription&.trialing? && days_left_in_trial.positive?
end
def has_active_subscription?
subscription&.active?
end
def can_manage_subscription?
stripe_customer_id.present?
end
def needs_subscription?
subscription.nil? && !self_hoster?
end
def next_payment_date
subscription&.current_period_ends_at
end
def subscription_pending_cancellation?
subscription&.pending_cancellation?
end
def start_subscription!(stripe_subscription_id)
if subscription.present?
subscription.update!(status: "active", stripe_id: stripe_subscription_id)
else
create_subscription!(status: "active", stripe_id: stripe_subscription_id)
end
end
def days_left_in_trial
return -1 unless subscription.present?
((subscription.trial_ends_at - Time.current).to_i / 86400) + 1
end
def percentage_of_trial_remaining
return 0 unless subscription.present?
(days_left_in_trial.to_f / Subscription::TRIAL_DAYS) * 100
end
def percentage_of_trial_completed
return 0 unless subscription.present?
(1 - days_left_in_trial.to_f / Subscription::TRIAL_DAYS) * 100
end
def sync_trial_status!
if subscription&.status == "trialing" && days_left_in_trial < 0
subscription.update!(status: "paused")
end
end
end