Class: CoreMerchant::Subscription
- Inherits:
-
ActiveRecord::Base
- Object
- ActiveRecord::Base
- CoreMerchant::Subscription
- Includes:
- Concerns::SubscriptionEventAssociation, Concerns::SubscriptionNotifications, Concerns::SubscriptionStateMachine
- Defined in:
- lib/core_merchant/subscription.rb
Overview
Represents a subscription in CoreMerchant. This class manages the lifecycle of a customer’s subscription to a specific plan.
**Subscriptions can transition through various statuses**:
-
‘pending`: Subscription created but not yet started
-
‘trial`: In a trial period
-
‘active`: Currently active and paid
-
‘past_due`: Payment failed but in grace period
-
‘pending_cancellation`: Will be canceled at period end
-
‘processing_renewal`: Renewal in progress
-
‘processing_payment`: Payment processing
-
‘canceled`: Canceled by user or due to payment failure
-
‘expired`: Subscription period ended
-
‘paused`: Temporarily halted, not yet implemented
-
‘pending_change`: Plan change scheduled for next renewal, not yet implemented
**Key features**:
-
Supports immediate and end-of-period cancellations
-
Allows plan changes, effective immediately or at next renewal
-
Handles subscription pausing and resuming
-
Manages trial periods
-
Supports variable pricing for renewals
Attributes:
-
‘customer`: Polymorphic association to the customer
-
‘subscription_plan`: The current plan for this subscription
-
‘status`: Current status of the subscription (see enum definition)
-
‘start_date`: When the subscription started
-
‘end_date`: When the subscription ended (or will end)
-
‘trial_end_date`: End date of the trial period (if applicable)
-
‘canceled_at`: When the subscription was canceled
-
‘current_period_start`: Start of the current billing period
-
‘current_period_end`: End of the current billing period
-
‘pause_start_date`: When the subscription was paused
-
‘pause_end_date`: When the paused subscription will resume
-
‘current_period_price_cents`: Price for the current period
-
‘next_renewal_price_cents`: Price for the next renewal (if different from plan)
-
‘cancellation_reason`: Reason for cancellation (if applicable)
Usage:
```ruby
subscription = CoreMerchant::Subscription.create(customer: user, subscription_plan: plan, status: :active)
subscription.start
subscription.cancel(reason: "Too expensive", at_period_end: true)
```
Constant Summary
Constants included from Concerns::SubscriptionEventAssociation
Concerns::SubscriptionEventAssociation::EVENT_TYPES
Constants included from Concerns::SubscriptionStateMachine
Concerns::SubscriptionStateMachine::POSSIBLE_TRANSITIONS
Instance Method Summary collapse
-
#cancel(reason:, at_period_end: true) ⇒ Object
Cancels the subscription.
-
#days_remaining_in_current_period ⇒ Object
Returns the days remaining in the current period.
- #days_remaining_in_grace_period ⇒ Object
- #due_for_renewal? ⇒ Boolean
- #expired_or_canceled? ⇒ Boolean
-
#grace_period ⇒ Object
Returns the number of days as a grace period for past-due subscriptions.
- #grace_period_end_date ⇒ Object
- #grace_period_exceeded? ⇒ Boolean
- #in_grace_period? ⇒ Boolean
- #ongoing? ⇒ Boolean
- #processing? ⇒ Boolean
- #renewable? ⇒ Boolean
-
#start ⇒ Object
Starts the subscription.
-
#start_new_period ⇒ Object
Starts a new period for the subscription.
Instance Method Details
#cancel(reason:, at_period_end: true) ⇒ Object
Cancels the subscription. Parameters:
-
‘reason`: Reason for cancellation
-
‘at_period_end`: If true, the subscription will be canceled at the end of the current period. Otherwise, the subscription will be canceled immediately. Default is `true`.
101 102 103 |
# File 'lib/core_merchant/subscription.rb', line 101 def cancel(reason:, at_period_end: true) CoreMerchant.subscription_manager.cancel_subscription(self, reason: reason, at_period_end: at_period_end) end |
#days_remaining_in_current_period ⇒ Object
Returns the days remaining in the current period. Use to show the user how many days are left before the next renewal or to refund pro-rated amounts for early cancellations.
120 121 122 |
# File 'lib/core_merchant/subscription.rb', line 120 def days_remaining_in_current_period (current_period_end.to_date - Time.current.to_date).to_i end |
#days_remaining_in_grace_period ⇒ Object
138 139 140 141 142 |
# File 'lib/core_merchant/subscription.rb', line 138 def days_remaining_in_grace_period return 0 unless due_for_renewal? (grace_period_end_date.to_date - Time.current.to_date).to_i end |
#due_for_renewal? ⇒ Boolean
148 149 150 |
# File 'lib/core_merchant/subscription.rb', line 148 def due_for_renewal? renewable? && current_period_end <= Time.current end |
#expired_or_canceled? ⇒ Boolean
152 153 154 |
# File 'lib/core_merchant/subscription.rb', line 152 def expired_or_canceled? expired? || canceled? end |
#grace_period ⇒ Object
Returns the number of days as a grace period for past-due subscriptions. By default, this is 3 days.
126 127 128 |
# File 'lib/core_merchant/subscription.rb', line 126 def grace_period 3.days end |
#grace_period_end_date ⇒ Object
130 131 132 |
# File 'lib/core_merchant/subscription.rb', line 130 def grace_period_end_date current_period_end + grace_period end |
#grace_period_exceeded? ⇒ Boolean
144 145 146 |
# File 'lib/core_merchant/subscription.rb', line 144 def grace_period_exceeded? due_for_renewal? && Time.current > grace_period_end_date end |
#in_grace_period? ⇒ Boolean
134 135 136 |
# File 'lib/core_merchant/subscription.rb', line 134 def in_grace_period? due_for_renewal? && Time.current <= grace_period_end_date end |
#ongoing? ⇒ Boolean
160 161 162 |
# File 'lib/core_merchant/subscription.rb', line 160 def ongoing? active? || trial? || past_due? || processing_renewal? || processing_payment? || pending_cancellation? end |
#processing? ⇒ Boolean
156 157 158 |
# File 'lib/core_merchant/subscription.rb', line 156 def processing? processing_renewal? || processing_payment? end |
#renewable? ⇒ Boolean
164 165 166 |
# File 'lib/core_merchant/subscription.rb', line 164 def renewable? active? || trial? || past_due? || processing? end |
#start ⇒ Object
Starts the subscription. Sets the current period start and end dates based on the plan’s duration.
91 92 93 |
# File 'lib/core_merchant/subscription.rb', line 91 def start CoreMerchant.subscription_manager.start_subscription(self) end |
#start_new_period ⇒ Object
Starts a new period for the subscription. This is called by SubscriptionManager when a subscription renewal is successful.
107 108 109 110 111 112 113 114 115 |
# File 'lib/core_merchant/subscription.rb', line 107 def start_new_period new_period_start = current_period_end || start_date new_period_end = new_period_start + subscription_plan.duration_in_date update!( current_period_start: new_period_start.to_date, current_period_end: new_period_end.to_date ) end |