core_merchant 0.10.3 → 0.11.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b1b4b1cbf5077a524194ccfd967de5ffa09300f0044eb1510f29685f3f423a61
4
- data.tar.gz: 9cbf2263f4dc11a235a7d4fb3bac772d9b596ee819eda49462dc5c1d7495bf83
3
+ metadata.gz: 22e2c74252e4e4b93cfcda94ce010339441225e0214b5feb3ae595adc539e421
4
+ data.tar.gz: a7bfb337cb13efebae8aba09f9e7eb0df7186b815fd489faca0d25709a195cc8
5
5
  SHA512:
6
- metadata.gz: d6c14e092f4f7bd2097163bb731c50cc24e4142a5c4857544237d908a3b0c71c54a9297ea905fe30adb2bcc218b649bbbbe5cd9381321097926c75ac27322732
7
- data.tar.gz: 898f6dfe26822e55091af5ab6a320d4e087feee85925a174e6937ef1597ef701072589a9ebcb48cf4446cfd20e3a5aacff1c62870e1191a3e544d8de651d22df
6
+ metadata.gz: 891a264116088a5fbbf92b0878b7d704a17d8f92052332d498816256ee2414e0b55c765d8994ca4c4731aa8cccf99926099ef00006022c7c202fced43e3e1932
7
+ data.tar.gz: 6fe89dc891685e3f124b75c01f10ead88effdcbfbdf6d1a6d12d2894f0eaff8c92c74328e9ef69367ce3b169b9f7bff0e46f9b28a41e0ee415a338c053c30ff4
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- core_merchant (0.10.1)
4
+ core_merchant (0.10.3)
5
5
  activesupport (~> 7.0)
6
6
  rails (~> 7.0)
7
7
 
data/README.md CHANGED
@@ -57,6 +57,36 @@ $ gem install core_merchant
57
57
  ```
58
58
 
59
59
  # Usage
60
+ The steps below will guide you through setting up CoreMerchant in your Rails application. After completing these steps, you will be able to create subscription plans, manage subscriptions, and handle subscription events.
61
+
62
+ ```ruby
63
+ # Create a subscription plan
64
+ plan = CoreMerchant::SubscriptionPlan.create(name_key: 'basic', price_cents: 9_99, duration: '1m')
65
+
66
+ # Subscribe a customer to the plan
67
+ customer = current_user
68
+ subscription = CoreMerchant::Subscription.create(customer: customer, plan: plan)
69
+
70
+ # Start the subscription
71
+ CoreMerchant.subscription_manager.start_subscription(subscription)
72
+
73
+ # Use a listener to handle subscription events
74
+ class MySubscriptionListener
75
+ include CoreMerchant::SubscriptionListener
76
+
77
+ def on_subscription_started(subscription)
78
+ puts "Subscription started for #{subscription.customer.email}, subscribed to #{subscription.plan.name}"
79
+ end
80
+
81
+ def on_subscription_due_for_renewal(subscription)
82
+ puts "Subscription due for renewal for #{subscription.customer.email}, renewing until #{subscription.current_period_end_date}"
83
+
84
+ # After payment is processed
85
+ CoreMerchant.subscription_manager.payment_successful_for_renewal(subscription)
86
+ end
87
+ end
88
+ ```
89
+
60
90
  ## Initialization
61
91
  Run the generator to create the initializer file and the migrations:
62
92
  ```
@@ -51,7 +51,7 @@ module CoreMerchant
51
51
  # subscription.start
52
52
  # subscription.cancel(reason: "Too expensive", at_period_end: true)
53
53
  # ```
54
- class Subscription < ActiveRecord::Base # rubocop:disable Metrics/ClassLength
54
+ class Subscription < ActiveRecord::Base
55
55
  include CoreMerchant::Concerns::SubscriptionStateMachine
56
56
  include CoreMerchant::Concerns::SubscriptionNotifications
57
57
  include CoreMerchant::Concerns::SubscriptionEventAssociation
@@ -89,18 +89,7 @@ module CoreMerchant
89
89
  # Starts the subscription.
90
90
  # Sets the current period start and end dates based on the plan's duration.
91
91
  def start
92
- new_period_start = start_date
93
- new_period_end = new_period_start + subscription_plan.duration_in_date
94
-
95
- transaction do
96
- transition_to_active!
97
- update!(
98
- current_period_start: new_period_start.to_date,
99
- current_period_end: new_period_end.to_date
100
- )
101
- end
102
-
103
- notify_subscription_manager(:started)
92
+ CoreMerchant.subscription_manager.start_subscription(self)
104
93
  end
105
94
 
106
95
  # Cancels the subscription.
@@ -110,26 +99,13 @@ module CoreMerchant
110
99
  # Otherwise, the subscription will be canceled immediately.
111
100
  # Default is `true`.
112
101
  def cancel(reason:, at_period_end: true)
113
- transaction do
114
- if at_period_end
115
- transition_to_pending_cancellation!
116
- else
117
- transition_to_canceled!
118
- end
119
- update!(
120
- canceled_at: at_period_end ? current_period_end : Time.current,
121
- cancellation_reason: reason
122
- )
123
- end
124
-
125
- notify_subscription_manager(:canceled, reason: reason, immediate: !at_period_end)
126
- cancellation_events.create!(reason: reason, at_period_end: at_period_end)
102
+ CoreMerchant.subscription_manager.cancel_subscription(self, reason: reason, at_period_end: at_period_end)
127
103
  end
128
104
 
129
105
  # Starts a new period for the subscription.
130
106
  # This is called by SubscriptionManager when a subscription renewal is successful.
131
107
  def start_new_period
132
- new_period_start = current_period_end
108
+ new_period_start = current_period_end || start_date
133
109
  new_period_end = new_period_start + subscription_plan.duration_in_date
134
110
 
135
111
  update!(
@@ -40,41 +40,95 @@ module CoreMerchant
40
40
  @listeners = []
41
41
  end
42
42
 
43
+ # Checks all subscriptions for renewals and cancellations.
44
+ # Call this method periodically (probably daily) to check for subscriptions that need attention.
45
+ # This method will notify listeners when subscriptions are due for renewal or cancellation.
43
46
  def check_subscriptions
44
47
  check_renewals
45
48
  check_cancellations
46
49
  end
47
50
 
51
+ # Adds a listener to the list of listeners.
52
+ # You probably don't need to call this method directly. Instead, set the listener in the configuration.
53
+ # config.subscription_listener_class = "MySubscriptionListener"
48
54
  def add_listener(listener)
49
55
  @listeners << listener
50
56
  end
51
57
 
58
+ # Checks all subscriptions for renewals. Called by `check_subscriptions`.
52
59
  def check_renewals
53
60
  Subscription.find_each do |subscription|
54
61
  process_for_renewal(subscription) if subscription.due_for_renewal?
55
62
  end
56
63
  end
57
64
 
65
+ # Starts the subscription.
66
+ # Sets the current period start and end dates based on the plan's duration.
67
+ def start_subscription(subscription)
68
+ subscription.transaction do
69
+ subscription.start_new_period
70
+ subscription.transition_to_active!
71
+ end
72
+
73
+ notify(subscription, :started)
74
+ end
75
+
76
+ # Cancels the subscription.
77
+ # Parameters:
78
+ # - `reason`: Reason for cancellation
79
+ # - `at_period_end`: If true, the subscription will be canceled at the end of the current period.
80
+ # Otherwise, the subscription will be canceled immediately.
81
+ # Default is `true`.
82
+ def cancel_subscription(subscription, reason:, at_period_end: true)
83
+ subscription.transaction do
84
+ if at_period_end
85
+ subscription.transition_to_pending_cancellation!
86
+ else
87
+ subscription.transition_to_canceled!
88
+ end
89
+ subscription.update!(
90
+ canceled_at: at_period_end ? subscription.current_period_end : Time.current,
91
+ cancellation_reason: reason
92
+ )
93
+ end
94
+
95
+ notify(subscription, :canceled, reason: reason, immediate: !at_period_end)
96
+ subscription.cancellation_events.create!(reason: reason, at_period_end: at_period_end)
97
+ end
98
+
99
+ # Starts the subscription renewal process.
100
+ # This method is called when a subscription is due for renewal. It will in turn call notify the listener.
101
+ # When you receive a notification that a subscription is due for renewal, you should either call
102
+ # `no_payment_needed_for_renewal`, `processing_payment_for_renewal`, `payment_successful_for_renewal`, or
103
+ # `payment_failed_for_renewal` to continue the renewal process.
58
104
  def process_for_renewal(subscription)
59
105
  return unless subscription.transition_to_processing_renewal
60
106
 
61
107
  notify(subscription, :due_for_renewal)
62
108
  end
63
109
 
110
+ # Call this method when a subscription is renewed without payment.
111
+ # It will renew the subscription and notify listeners.
64
112
  def no_payment_needed_for_renewal(subscription)
65
113
  renew_subscription(subscription)
66
114
  end
67
115
 
116
+ # Call this method when payment is being processed for a renewal. This needs to be followed by either
117
+ # `payment_successful_for_renewal` or `payment_failed_for_renewal`.
68
118
  def processing_payment_for_renewal(subscription)
69
119
  return unless subscription.transition_to_processing_payment
70
120
 
71
121
  notify(subscription, :renewal_payment_processing)
72
122
  end
73
123
 
124
+ # Call this method when payment was successful for a renewal.
125
+ # It will renew the subscription and notify listeners.
74
126
  def payment_successful_for_renewal(subscription)
75
127
  renew_subscription(subscription)
76
128
  end
77
129
 
130
+ # Call this method when payment failed for a renewal.
131
+ # It will transition the subscription to past due when in grace period, or expired if not.
78
132
  def payment_failed_for_renewal(subscription)
79
133
  is_in_grace_period = subscription.in_grace_period?
80
134
  if is_in_grace_period
@@ -86,12 +140,15 @@ module CoreMerchant
86
140
  end
87
141
  end
88
142
 
143
+ # Checks all subscriptions for cancellations. Called by `check_subscriptions`.
89
144
  def check_cancellations
90
145
  Subscription.find_each do |subscription|
91
146
  process_for_cancellation(subscription) if subscription.pending_cancellation?
92
147
  end
93
148
  end
94
149
 
150
+ # Processes a subscription for cancellation.
151
+ # This method is called when a subscription is pending cancellation.
95
152
  def process_for_cancellation(subscription)
96
153
  return unless subscription.transition_to_expired
97
154
 
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module CoreMerchant
4
- VERSION = "0.10.3"
4
+ VERSION = "0.11.0"
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: core_merchant
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.10.3
4
+ version: 0.11.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Seyithan Teymur