chargebee_rails 0.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/README.md +470 -0
- data/Rakefile +10 -0
- data/app/controllers/chargebee_rails/webhooks_controller.rb +40 -0
- data/config/routes.rb +9 -0
- data/lib/chargebee_rails.rb +119 -0
- data/lib/chargebee_rails/configuration.rb +47 -0
- data/lib/chargebee_rails/customer.rb +85 -0
- data/lib/chargebee_rails/engine.rb +6 -0
- data/lib/chargebee_rails/errors.rb +26 -0
- data/lib/chargebee_rails/hosted_page_subscription_manager.rb +134 -0
- data/lib/chargebee_rails/metered_billing.rb +56 -0
- data/lib/chargebee_rails/subscription.rb +163 -0
- data/lib/chargebee_rails/subscription_builder.rb +162 -0
- data/lib/chargebee_rails/version.rb +4 -0
- data/lib/chargebee_rails/webhook_handler.rb +175 -0
- data/lib/generators/chargebee_rails/install_generator.rb +58 -0
- data/lib/generators/chargebee_rails/templates/app/models/payment_method.rb +3 -0
- data/lib/generators/chargebee_rails/templates/app/models/plan.rb +4 -0
- data/lib/generators/chargebee_rails/templates/app/models/subscription.rb +7 -0
- data/lib/generators/chargebee_rails/templates/config/initializers/chargebee_rails.rb +38 -0
- data/lib/generators/chargebee_rails/templates/event_sync_log_migration.rb +8 -0
- data/lib/generators/chargebee_rails/templates/new_subscription_migration.rb +16 -0
- data/lib/tasks/chargebee_rails_tasks.rake +7 -0
- data/lib/tasks/sync_failed_events.rake +72 -0
- data/lib/tasks/sync_plans.rake +82 -0
- metadata +206 -0
@@ -0,0 +1,58 @@
|
|
1
|
+
# This generator is based on rails_admin's install generator.
|
2
|
+
# https://www.github.com/sferik/rails_admin/master/lib/generators/rails_admin/install_generator.rb
|
3
|
+
|
4
|
+
require 'rails/generators'
|
5
|
+
|
6
|
+
# http://guides.rubyonrails.org/generators.html
|
7
|
+
|
8
|
+
module ChargebeeRails
|
9
|
+
class InstallGenerator < Rails::Generators::Base
|
10
|
+
|
11
|
+
include Rails::Generators::Migration
|
12
|
+
|
13
|
+
argument :subscriber_model, :type => :string, :required => true, :desc => "Owner of the subscription"
|
14
|
+
desc "ChargebeeRails installation generator"
|
15
|
+
|
16
|
+
# The path for the custom migration templates
|
17
|
+
def self.source_paths
|
18
|
+
[File.expand_path("../templates", __FILE__)]
|
19
|
+
end
|
20
|
+
|
21
|
+
# Next migration number
|
22
|
+
def self.next_migration_number(dir)
|
23
|
+
Time.now.utc.strftime("%Y%m%d%H%M%S")
|
24
|
+
end
|
25
|
+
|
26
|
+
# Override subscriber_model to ensure it is always returned lowercase.
|
27
|
+
def subscriber_model
|
28
|
+
@subscriber_model.downcase
|
29
|
+
end
|
30
|
+
|
31
|
+
def install
|
32
|
+
|
33
|
+
# Generate chargebee_rails configuration file template
|
34
|
+
template "config/initializers/chargebee_rails.rb"
|
35
|
+
|
36
|
+
# Generate plan.
|
37
|
+
generate("model", "plan name:string plan_id:string status:string chargebee_data:text")
|
38
|
+
template "app/models/plan.rb"
|
39
|
+
|
40
|
+
# Generate subscription.
|
41
|
+
migration_template "new_subscription_migration.rb", "db/migrate/create_subscriptions.rb"
|
42
|
+
template "app/models/subscription.rb"
|
43
|
+
|
44
|
+
# Generate payment methods.
|
45
|
+
generate("model", "payment_method cb_customer_id:string auto_collection:boolean payment_type:string reference_id:string card_last4:string card_type:string status:string event_last_modified_at:datetime subscription:references")
|
46
|
+
|
47
|
+
# Generate chargebee rails event.
|
48
|
+
migration_template "event_sync_log_migration.rb", "db/migrate/create_event_sync_log.rb"
|
49
|
+
|
50
|
+
# Add related fields to the subscription owner table
|
51
|
+
generate("migration", "add_chargebee_id_to_#{subscriber_model} chargebee_id:string event_last_modified_at:datetime chargebee_data:text")
|
52
|
+
|
53
|
+
# Specify the relationship between subscription and owner
|
54
|
+
inject_into_class "app/models/#{subscriber_model}.rb", subscriber_model.camelize.constantize,
|
55
|
+
" include ChargebeeRails::Customer\n\n # Added by ChargebeeRails.\n has_one :subscription\n serialize :chargebee_data, JSON\n"
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
ChargebeeRails.configure do |config|
|
2
|
+
# This will be the default plan when a subscription is not provided with one
|
3
|
+
# make sure that this plan exists in your active record model
|
4
|
+
# config.default_plan_id = 'your_default_plan_id'
|
5
|
+
|
6
|
+
# Specify the default end of term value for subscription related changes like
|
7
|
+
# subscription updation and cancellation. Setting this as true will make the
|
8
|
+
# changes for subscription at end of term or at next renewal. Reference -
|
9
|
+
# https://apidocs.chargebee.com/docs/api/subscriptions#update_a_subscription
|
10
|
+
# config.end_of_term = false
|
11
|
+
|
12
|
+
# Set default proration for subscription related changes Reference -
|
13
|
+
# https://apidocs.chargebee.com/docs/api/subscriptions#update_a_subscription
|
14
|
+
# config.proration = true
|
15
|
+
|
16
|
+
# Configure the default behavior of including delayed charges while estimating
|
17
|
+
# Reference - https://apidocs.chargebee.com/docs/api/estimates#update_subscription_estimate
|
18
|
+
# config.include_delayed_charges = { changes_estimate: false, renewal_estimate: true }
|
19
|
+
|
20
|
+
# setup chargebee with your site and api_key
|
21
|
+
config.chargebee_site = 'CHARGEBEE_SITE'
|
22
|
+
config.chargebee_api_key = 'CHARGEBEE_API_KEY'
|
23
|
+
|
24
|
+
# Webhook related configurations
|
25
|
+
# Set the controller name that is used to override the webhook events
|
26
|
+
# config.webhook_handler = 'webhook_overriding_controller_name'
|
27
|
+
|
28
|
+
# Configure your own webhook path for ChargeBee events
|
29
|
+
# the default_path is 'chargebee_rails_event'
|
30
|
+
# config.webhook_api_path = 'your_webhook_path'
|
31
|
+
|
32
|
+
# Set this as true if you have enabled basic http authentication for your
|
33
|
+
# webhook api
|
34
|
+
# config.secure_webhook_api = true
|
35
|
+
|
36
|
+
# Set the authentication credentials for securing your webhook api
|
37
|
+
# config.webhook_authentication = {user: nil, secret: nil}
|
38
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
class CreateSubscriptions < ActiveRecord::Migration
|
2
|
+
def change
|
3
|
+
create_table :subscriptions do |t|
|
4
|
+
t.string :chargebee_id
|
5
|
+
t.references :plan, index: true, foreign_key: true
|
6
|
+
t.integer :plan_quantity, default: 1
|
7
|
+
t.references :<%= subscriber_model %>, index: true, foreign_key: true
|
8
|
+
t.string :status
|
9
|
+
t.datetime :event_last_modified_at
|
10
|
+
t.text :chargebee_data
|
11
|
+
|
12
|
+
|
13
|
+
t.timestamps null: false
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
require 'chargebee_rails/webhook_handler'
|
2
|
+
|
3
|
+
namespace :chargebee_rails do
|
4
|
+
include ChargebeeRails::WebhookHandler
|
5
|
+
|
6
|
+
desc "Sync Failed Events"
|
7
|
+
task sync_failed_events: :environment do
|
8
|
+
# Keep collecting the failed events until no offset is present
|
9
|
+
loop do
|
10
|
+
event_list = retrieve_failed_events
|
11
|
+
@offset = event_list.next_offset
|
12
|
+
failed_events << event_list.flat_map(&:event)
|
13
|
+
break unless @offset.present?
|
14
|
+
end
|
15
|
+
@failed_events = failed_events.flatten
|
16
|
+
puts "Syncing events..."
|
17
|
+
sync_failed_events
|
18
|
+
update_event_synced_at
|
19
|
+
end
|
20
|
+
|
21
|
+
def failed_events
|
22
|
+
@failed_events ||= []
|
23
|
+
end
|
24
|
+
|
25
|
+
# Retrieve the failed events from chargebee
|
26
|
+
def retrieve_failed_events
|
27
|
+
options[:start_time] = events_last_synced_at.to_i # Integer timestamp of the last time this rake task ran
|
28
|
+
options[:offset] = @offset if @offset.present? # Pass the offset if it is present
|
29
|
+
ChargeBee::Event.list(options)
|
30
|
+
end
|
31
|
+
|
32
|
+
# Send all the failed events to the ChargebeeRails::WebhookHandler
|
33
|
+
def sync_failed_events
|
34
|
+
failed_events.each do |chargebee_event|
|
35
|
+
handle(chargebee_event)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
# Build the options to retrieve the failed events from chargebee
|
40
|
+
def options
|
41
|
+
@options ||= {
|
42
|
+
limit: 100,
|
43
|
+
webhook_status: 'failed',
|
44
|
+
end_time: Time.now.to_i
|
45
|
+
}
|
46
|
+
end
|
47
|
+
|
48
|
+
# Get the time the rake task was last run
|
49
|
+
def events_last_synced_at
|
50
|
+
select_query = "SELECT * FROM event_sync_logs;"
|
51
|
+
event_sync_logs = ActiveRecord::Base.connection.execute(select_query)
|
52
|
+
Time.parse(event_sync_logs.first['updated_at']) if event_sync_logs.first.present?
|
53
|
+
end
|
54
|
+
|
55
|
+
# Update the event_sync_logs table with the time once the rake task is completed
|
56
|
+
def update_event_synced_at
|
57
|
+
events_last_synced_at.present? ? update_record : insert_new_record
|
58
|
+
end
|
59
|
+
|
60
|
+
# Set the updated_at column of the existing event_sync_log record
|
61
|
+
def update_record
|
62
|
+
update_query = "UPDATE event_sync_logs SET updated_at='#{Time.now}' WHERE id=1 ;"
|
63
|
+
ActiveRecord::Base.connection.execute(update_query)
|
64
|
+
end
|
65
|
+
|
66
|
+
# Create new event_sync_logs record for the first time the rake task is run
|
67
|
+
def insert_new_record
|
68
|
+
insert_query = "INSERT INTO event_sync_logs (id, created_at, updated_at) VALUES (1, '#{Time.now}', '#{Time.now}');"
|
69
|
+
ActiveRecord::Base.connection.execute(insert_query)
|
70
|
+
end
|
71
|
+
|
72
|
+
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
namespace :chargebee_rails do
|
2
|
+
|
3
|
+
desc "chargebee plans sync with application"
|
4
|
+
task :sync_plans => :environment do
|
5
|
+
# Prompt user input to get confirmation of the plan sync
|
6
|
+
begin
|
7
|
+
STDOUT.puts "\n This will sync plans in your application with chargebee, do you want to continue ? [y/n]"
|
8
|
+
input = STDIN.gets.strip.downcase
|
9
|
+
end until %w(y n).include?(input)
|
10
|
+
if input == "y"
|
11
|
+
# Keep collecting the plans from chargebee until an offset is not provided
|
12
|
+
loop do
|
13
|
+
plan_list = retrieve_plan_list
|
14
|
+
@offset = plan_list.next_offset
|
15
|
+
cb_plans << plan_list.flat_map(&:plan)
|
16
|
+
break unless @offset.present?
|
17
|
+
end
|
18
|
+
@cb_plans = cb_plans.flatten
|
19
|
+
sync_plans
|
20
|
+
else
|
21
|
+
STDOUT.puts "Plan sync aborted!"
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
def cb_plans
|
28
|
+
@cb_plans ||= []
|
29
|
+
end
|
30
|
+
|
31
|
+
def sync_plans
|
32
|
+
# puts "Removed #{remove_plans.count} plan(s)"
|
33
|
+
puts "Created #{create_new_plans.count} plan(s)"
|
34
|
+
# puts "Updated all #{update_all_plans.count} plan(s)"
|
35
|
+
end
|
36
|
+
|
37
|
+
# Retrieve the plan list from chargebee
|
38
|
+
def retrieve_plan_list
|
39
|
+
options = { limit: 100 }
|
40
|
+
options[:offset] = @offset if @offset.present?
|
41
|
+
ChargeBee::Plan.list(options)
|
42
|
+
end
|
43
|
+
|
44
|
+
# Remove plans from application that do not exist in chargebee
|
45
|
+
def remove_plans
|
46
|
+
cb_plan_ids = cb_plans.flat_map(&:id)
|
47
|
+
Plan.all.reject { |plan| cb_plan_ids.include?(plan.plan_id) }
|
48
|
+
.each { |plan| puts "Deleting Plan - #{plan.plan_id}"; plan.destroy }
|
49
|
+
end
|
50
|
+
|
51
|
+
# Create new plans that are not present in app but are available in chargebee
|
52
|
+
def create_new_plans
|
53
|
+
plan_ids = Plan.all.map(&:plan_id)
|
54
|
+
cb_plans.reject { |cb_plan| plan_ids.include?(cb_plan.id) }
|
55
|
+
.each { |new_plan| puts "Creating Plan - #{new_plan.id}"; Plan.create(plan_params(new_plan)) }
|
56
|
+
end
|
57
|
+
|
58
|
+
# Update all existing plans in the application
|
59
|
+
def update_all_plans
|
60
|
+
cb_plans.map do |cb_plan|
|
61
|
+
Plan.find_by(plan_id: cb_plan.id).update(plan_params(cb_plan))
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
# Build the plan params to be created or updated in the application
|
66
|
+
def plan_params plan
|
67
|
+
{
|
68
|
+
name: plan.name,
|
69
|
+
plan_id: plan.id,
|
70
|
+
status: plan.status,
|
71
|
+
chargebee_data: {
|
72
|
+
price: plan.price,
|
73
|
+
period: plan.period,
|
74
|
+
period_unit: plan.period_unit,
|
75
|
+
trial_period: plan.trial_period,
|
76
|
+
trial_period_unit: plan.trial_period_unit,
|
77
|
+
charge_model: plan.charge_model,
|
78
|
+
free_quantity: plan.free_quantity
|
79
|
+
}
|
80
|
+
}
|
81
|
+
end
|
82
|
+
end
|
metadata
ADDED
@@ -0,0 +1,206 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: chargebee_rails
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.3
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Chargebee
|
8
|
+
- Spritle
|
9
|
+
autorequire:
|
10
|
+
bindir: exe
|
11
|
+
cert_chain: []
|
12
|
+
date: 2016-08-11 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: chargebee
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
requirements:
|
18
|
+
- - "~>"
|
19
|
+
- !ruby/object:Gem::Version
|
20
|
+
version: '2.0'
|
21
|
+
- - ">="
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: 2.0.5
|
24
|
+
type: :runtime
|
25
|
+
prerelease: false
|
26
|
+
version_requirements: !ruby/object:Gem::Requirement
|
27
|
+
requirements:
|
28
|
+
- - "~>"
|
29
|
+
- !ruby/object:Gem::Version
|
30
|
+
version: '2.0'
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 2.0.5
|
34
|
+
- !ruby/object:Gem::Dependency
|
35
|
+
name: rails
|
36
|
+
requirement: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '3.1'
|
41
|
+
type: :development
|
42
|
+
prerelease: false
|
43
|
+
version_requirements: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '3.1'
|
48
|
+
- !ruby/object:Gem::Dependency
|
49
|
+
name: bundler
|
50
|
+
requirement: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '1.10'
|
55
|
+
type: :development
|
56
|
+
prerelease: false
|
57
|
+
version_requirements: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '1.10'
|
62
|
+
- !ruby/object:Gem::Dependency
|
63
|
+
name: rake
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '10.0'
|
69
|
+
type: :development
|
70
|
+
prerelease: false
|
71
|
+
version_requirements: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '10.0'
|
76
|
+
- !ruby/object:Gem::Dependency
|
77
|
+
name: rspec
|
78
|
+
requirement: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: 3.3.0
|
83
|
+
type: :development
|
84
|
+
prerelease: false
|
85
|
+
version_requirements: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - "~>"
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: 3.3.0
|
90
|
+
- !ruby/object:Gem::Dependency
|
91
|
+
name: webmock
|
92
|
+
requirement: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ">="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
97
|
+
type: :development
|
98
|
+
prerelease: false
|
99
|
+
version_requirements: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - ">="
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0'
|
104
|
+
- !ruby/object:Gem::Dependency
|
105
|
+
name: mocha
|
106
|
+
requirement: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ">="
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
111
|
+
type: :development
|
112
|
+
prerelease: false
|
113
|
+
version_requirements: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - ">="
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
- !ruby/object:Gem::Dependency
|
119
|
+
name: vcr
|
120
|
+
requirement: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - ">="
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '0'
|
125
|
+
type: :development
|
126
|
+
prerelease: false
|
127
|
+
version_requirements: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - ">="
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: '0'
|
132
|
+
- !ruby/object:Gem::Dependency
|
133
|
+
name: pry
|
134
|
+
requirement: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - ">="
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: '0'
|
139
|
+
type: :development
|
140
|
+
prerelease: false
|
141
|
+
version_requirements: !ruby/object:Gem::Requirement
|
142
|
+
requirements:
|
143
|
+
- - ">="
|
144
|
+
- !ruby/object:Gem::Version
|
145
|
+
version: '0'
|
146
|
+
description: |-
|
147
|
+
This gem provides developers with the ability to easily
|
148
|
+
integrate chargebee's subscription management into their
|
149
|
+
application backed by active record models.
|
150
|
+
email:
|
151
|
+
- chargebee@spritle.com
|
152
|
+
executables: []
|
153
|
+
extensions: []
|
154
|
+
extra_rdoc_files: []
|
155
|
+
files:
|
156
|
+
- README.md
|
157
|
+
- Rakefile
|
158
|
+
- app/controllers/chargebee_rails/webhooks_controller.rb
|
159
|
+
- config/routes.rb
|
160
|
+
- lib/chargebee_rails.rb
|
161
|
+
- lib/chargebee_rails/configuration.rb
|
162
|
+
- lib/chargebee_rails/customer.rb
|
163
|
+
- lib/chargebee_rails/engine.rb
|
164
|
+
- lib/chargebee_rails/errors.rb
|
165
|
+
- lib/chargebee_rails/hosted_page_subscription_manager.rb
|
166
|
+
- lib/chargebee_rails/metered_billing.rb
|
167
|
+
- lib/chargebee_rails/subscription.rb
|
168
|
+
- lib/chargebee_rails/subscription_builder.rb
|
169
|
+
- lib/chargebee_rails/version.rb
|
170
|
+
- lib/chargebee_rails/webhook_handler.rb
|
171
|
+
- lib/generators/chargebee_rails/install_generator.rb
|
172
|
+
- lib/generators/chargebee_rails/templates/app/models/payment_method.rb
|
173
|
+
- lib/generators/chargebee_rails/templates/app/models/plan.rb
|
174
|
+
- lib/generators/chargebee_rails/templates/app/models/subscription.rb
|
175
|
+
- lib/generators/chargebee_rails/templates/config/initializers/chargebee_rails.rb
|
176
|
+
- lib/generators/chargebee_rails/templates/event_sync_log_migration.rb
|
177
|
+
- lib/generators/chargebee_rails/templates/new_subscription_migration.rb
|
178
|
+
- lib/tasks/chargebee_rails_tasks.rake
|
179
|
+
- lib/tasks/sync_failed_events.rake
|
180
|
+
- lib/tasks/sync_plans.rake
|
181
|
+
homepage: ''
|
182
|
+
licenses:
|
183
|
+
- MIT
|
184
|
+
metadata: {}
|
185
|
+
post_install_message:
|
186
|
+
rdoc_options: []
|
187
|
+
require_paths:
|
188
|
+
- lib
|
189
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
190
|
+
requirements:
|
191
|
+
- - ">="
|
192
|
+
- !ruby/object:Gem::Version
|
193
|
+
version: '0'
|
194
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
195
|
+
requirements:
|
196
|
+
- - ">="
|
197
|
+
- !ruby/object:Gem::Version
|
198
|
+
version: '0'
|
199
|
+
requirements: []
|
200
|
+
rubyforge_project:
|
201
|
+
rubygems_version: 2.4.8
|
202
|
+
signing_key:
|
203
|
+
specification_version: 4
|
204
|
+
summary: A subscription management gem for Rails with ChargeBee.
|
205
|
+
test_files: []
|
206
|
+
has_rdoc:
|