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.
@@ -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: