chargebee_rails 0.1.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -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,3 @@
1
+ class PaymentMethod
2
+ belongs_to :subscription
3
+ end
@@ -0,0 +1,4 @@
1
+ class Plan < ActiveRecord::Base
2
+ has_many :subscriptions
3
+ serialize :chargebee_data, JSON
4
+ end
@@ -0,0 +1,7 @@
1
+ class Subscription < ActiveRecord::Base
2
+ belongs_to :<%= subscriber_model %>
3
+ belongs_to :plan
4
+ has_one :payment_method
5
+ include ChargebeeRails::Subscription
6
+ serialize :chargebee_data, JSON
7
+ 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,8 @@
1
+ class CreateEventSyncLog < ActiveRecord::Migration
2
+ def change
3
+ create_table :event_sync_logs do |t|
4
+
5
+ t.timestamps null: false
6
+ end
7
+ end
8
+ 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,7 @@
1
+ namespace :chargebee_rails do
2
+ # Rake task to setup the necessary tables for subscription
3
+ desc "Install ChargebeeRails"
4
+ task :install do
5
+ system 'rails g chargebee_rails:install'
6
+ end
7
+ 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: