acts_as_subscription 0.0.1

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,207 @@
1
+ require 'spec/spec_helper'
2
+
3
+ describe Subscription do
4
+
5
+ before(:each) do
6
+ @free_attr = free_attributes
7
+ @paid_attr = paid_attributes
8
+ end
9
+
10
+ describe 'initialization' do
11
+
12
+ it 'should initialize the backend' do
13
+ subscription = model_factory
14
+ ActsAsSubscription::Subscription::Backend.config.should_not == nil
15
+ ActsAsSubscription::Subscription::Backend.instance.class.should == ActsAsSubscription::Subscription::Backend::DummyClient
16
+ end
17
+
18
+ it 'should create the customer code automatically' do
19
+ subscription = Subscription.new(@free_attr)
20
+ subscription.customer_code.should_not == nil
21
+ end
22
+
23
+ it 'should create a CreditCard instance' do
24
+ subscription = Subscription.new(@free_attr)
25
+ subscription.credit_card.class.should == ActiveMerchant::Billing::CreditCard
26
+ end
27
+
28
+ end
29
+
30
+ describe 'validation' do
31
+
32
+ describe 'for all plans' do
33
+
34
+ it 'should require an email' do
35
+ subscription = Subscription.new(@free_attr.merge(:email => ''))
36
+ subscription.should_not be_valid
37
+ end
38
+
39
+ it 'should require a first_name' do
40
+ subscription = Subscription.new(@free_attr.merge(:first_name => ''))
41
+ subscription.should_not be_valid
42
+ end
43
+
44
+ it 'should require a last_name' do
45
+ subscription = Subscription.new(@free_attr.merge(:last_name => ''))
46
+ subscription.should_not be_valid
47
+ end
48
+
49
+ it 'should require a customer_code' do
50
+ subscription = Subscription.new(@free_attr.merge(:customer_code => ''))
51
+ subscription.should_not be_valid
52
+ end
53
+
54
+ it 'is_free_plan? should return false if the :plan_code is missing' do
55
+ subscription = Subscription.new(@free_attr.merge(:plan_code => nil))
56
+ subscription.is_free_plan?.should == false
57
+ subscription = Subscription.new(@free_attr.merge(:plan_code => ''))
58
+ subscription.is_free_plan?.should == false
59
+ subscription = Subscription.new(@free_attr.merge(:plan_code => ' '))
60
+ subscription.is_free_plan?.should == false
61
+ end
62
+
63
+ it 'is_free_plan? should return true if the :plan_code contains the string "free"' do
64
+ subscription = Subscription.new(@free_attr.merge(:plan_code => 'free_plan'))
65
+ subscription.is_free_plan?.should == true
66
+ subscription = Subscription.new(@free_attr.merge(:plan_code => 'plan_free_plan'))
67
+ subscription.is_free_plan?.should == true
68
+ subscription = Subscription.new(@free_attr.merge(:plan_code => 'free'))
69
+ subscription.is_free_plan?.should == true
70
+ subscription = Subscription.new(@free_attr.merge(:plan_code => 'FREE'))
71
+ subscription.is_free_plan?.should == true
72
+ subscription = Subscription.new(@free_attr.merge(:plan_code => 'MY_PLAN (frEe)'))
73
+ subscription.is_free_plan?.should == true
74
+ end
75
+
76
+ end
77
+
78
+ describe 'for free plans' do
79
+
80
+ describe 'with valid parameters' do
81
+
82
+ it 'should validate' do
83
+ subscription = Subscription.new(@free_attr)
84
+ subscription.should be_valid
85
+ end
86
+
87
+ it 'should create a new record on save' do
88
+ lambda do
89
+ Subscription.create(@free_attr)
90
+ end.should change(Subscription, :count).by(1)
91
+ end
92
+
93
+ it 'should identify as a free plan' do
94
+ subscription = Subscription.new(@free_attr)
95
+ subscription.is_free_plan?.should == true
96
+ end
97
+
98
+ end
99
+
100
+ describe 'with invalid parameters' do
101
+
102
+ it 'should be invalid' do
103
+ subscription = Subscription.new(@free_attr.merge(:first_name => ''))
104
+ subscription.should_not be_valid
105
+ end
106
+
107
+ it 'should not create a new record on save' do
108
+ lambda do
109
+ Subscription.create(@free_attr.merge(:first_name => ''))
110
+ end.should_not change(Subscription, :count)
111
+ end
112
+
113
+ end
114
+
115
+ end
116
+
117
+ describe 'for paid plans' do
118
+
119
+ it 'should require a zip_code' do
120
+ subscription = Subscription.new(@paid_attr.merge(:zip_code => ''))
121
+ subscription.should_not be_valid
122
+ end
123
+
124
+ it 'should require a cc_expiration_month' do
125
+ subscription = Subscription.new(@paid_attr.merge(:cc_expiration_month => ''))
126
+ subscription.should_not be_valid
127
+ end
128
+
129
+ it 'should require a cc_expiration_year' do
130
+ subscription = Subscription.new(@paid_attr.merge(:cc_expiration_year => ''))
131
+ subscription.should_not be_valid
132
+ end
133
+
134
+ it 'should require a cc_verification_value' do
135
+ subscription = Subscription.new(@paid_attr.merge(:cc_verification_value => ''))
136
+ subscription.should_not be_valid
137
+ end
138
+
139
+ it 'should require a cc_number' do
140
+ subscription = Subscription.new(@paid_attr.merge(:cc_number => ''))
141
+ subscription.should_not be_valid
142
+ end
143
+
144
+ describe 'with valid parameters' do
145
+
146
+ it 'should validate' do
147
+ subscription = Subscription.new(@paid_attr)
148
+ subscription.should be_valid
149
+ end
150
+
151
+ it 'should create a new record on save' do
152
+ lambda do
153
+ Subscription.create(@paid_attr)
154
+ end.should change(Subscription, :count).by(1)
155
+ end
156
+
157
+ it 'should set cc_last_digits on validation' do
158
+ subscription = Subscription.new(@paid_attr)
159
+ subscription.valid?
160
+ subscription.cc_last_digits.should == @paid_attr[:cc_number].reverse[0, 4].reverse
161
+ end
162
+
163
+ it 'should identify as a paid plan' do
164
+ subscription = Subscription.new(@paid_attr)
165
+ subscription.is_free_plan?.should == false
166
+ end
167
+
168
+ it 'should update the internal CreditCard instance on validate' do
169
+ subscription = Subscription.new(@paid_attr)
170
+ subscription.credit_card.first_name.should == nil
171
+ subscription.credit_card.first_name.should == nil
172
+ subscription.credit_card.last_name.should == nil
173
+ subscription.credit_card.month.should == nil
174
+ subscription.credit_card.year.should == nil
175
+ subscription.credit_card.verification_value.should == nil
176
+ subscription.credit_card.number.should == nil
177
+ subscription.valid?
178
+ subscription.credit_card.first_name.should == @paid_attr[:first_name]
179
+ subscription.credit_card.last_name.should == @paid_attr[:last_name]
180
+ subscription.credit_card.month.should == @paid_attr[:cc_expiration_month]
181
+ subscription.credit_card.year.should == @paid_attr[:cc_expiration_year]
182
+ subscription.credit_card.verification_value.should == @paid_attr[:cc_verification_value]
183
+ subscription.credit_card.number.should == @paid_attr[:cc_number]
184
+ end
185
+
186
+ end
187
+
188
+ describe 'with invalid parameters' do
189
+
190
+ it 'should be invalid' do
191
+ subscription = Subscription.new(@paid_attr.merge(:first_name => ''))
192
+ subscription.should_not be_valid
193
+ end
194
+
195
+ it 'should not create a new record on save' do
196
+ lambda do
197
+ Subscription.create(@paid_attr.merge(:first_name => ''))
198
+ end.should_not change(Subscription, :count)
199
+ end
200
+
201
+ end
202
+
203
+ end
204
+
205
+ end # validation
206
+
207
+ end
@@ -0,0 +1,110 @@
1
+ $LOAD_PATH << "." unless $LOAD_PATH.include?(".")
2
+
3
+ begin
4
+ require 'active_record'
5
+ require 'bundler'
6
+ require 'rubygems'
7
+
8
+ if Gem::Version.new(Bundler::VERSION) <= Gem::Version.new('0.9.5')
9
+ raise RuntimeError, "Your bundler version is too old." +
10
+ "Run `gem install bundler` to upgrade."
11
+ end
12
+
13
+ # Set up load paths for all bundled gems
14
+ Bundler.setup
15
+ rescue Bundler::GemNotFound
16
+ raise RuntimeError, "Bundler couldn't find some gems." +
17
+ "Did you run `bundle install`?"
18
+ end
19
+
20
+ Bundler.require
21
+ require File.expand_path('../../lib/acts_as_subscription', __FILE__)
22
+
23
+ ENV['DB'] ||= 'sqlite3'
24
+
25
+ database_yml = File.expand_path('../support/database.yml', __FILE__)
26
+ if File.exists?(database_yml)
27
+ active_record_configuration = YAML.load_file(database_yml)[ENV['DB']]
28
+
29
+ ActiveRecord::Base.establish_connection(active_record_configuration)
30
+ ActiveRecord::Base.logger = Logger.new(File.join(File.dirname(__FILE__), "debug.log"))
31
+
32
+ ActiveRecord::Base.silence do
33
+ ActiveRecord::Migration.verbose = false
34
+
35
+ load(File.dirname(__FILE__) + '/support/schema.rb')
36
+ load(File.dirname(__FILE__) + '/support/models.rb')
37
+ end
38
+
39
+ else
40
+ raise "Please create #{database_yml} first to configure your database. Take a look at: #{database_yml}.example"
41
+ end
42
+
43
+ def backend_config(backend_name)
44
+ backend_yml = File.expand_path('../support/backend.yml', __FILE__)
45
+ if File.exists?(backend_yml)
46
+ config = YAML.load_file(backend_yml)
47
+
48
+ # Check that config is defined for this backend.
49
+ unless config[backend_name.to_s]
50
+ raise "Please create a section for '#{backend_name}' in #{backend_yml}"
51
+ end
52
+
53
+ config[backend_name.to_s]
54
+ else
55
+ raise "Please create #{backend_yml} first to configure backend authentication. Take a look at: #{backend_yml}.example"
56
+ end
57
+ end
58
+
59
+ def free_attributes
60
+ {
61
+ :email => 'dummy@recursive-design.com',
62
+ :plan_code => 'FREE',
63
+ :customer_code => UUIDTools::UUID.random_create.to_s,
64
+ :first_name => 'Testy',
65
+ :last_name => 'McTest',
66
+ }
67
+ end
68
+
69
+ def paid_attributes
70
+ {
71
+ :email => 'dummy@recursive-design.com',
72
+ :plan_code => 'PRO',
73
+ :customer_code => UUIDTools::UUID.random_create.to_s,
74
+ :first_name => 'Testy',
75
+ :last_name => 'McTest',
76
+ :cc_expiration_month => 1,
77
+ :cc_expiration_year => 2012,
78
+ :cc_number => '4111111111111111',
79
+ :cc_verification_value => '123',
80
+ :zip_code => '90210',
81
+ }
82
+ end
83
+
84
+ def model_factory(params={})
85
+ defaults = {:backend => :dummy, :user => 'user', :pass => 'pass'}
86
+ params = defaults.merge(params)
87
+ param_str = params.collect { |name, value|
88
+ if (value.class == Symbol)
89
+ value = ":#{value}"
90
+ else
91
+ value = "'#{value}'"
92
+ end
93
+ ":#{name} => #{value}" }.join(', ')
94
+ klass = eval <<-RUBY_EVAL
95
+ class Subscription < ActiveRecord::Base
96
+ include ActsAsSubscription::Subscription
97
+ acts_as_subscription #{param_str}
98
+ end
99
+ RUBY_EVAL
100
+ klass
101
+ end
102
+
103
+ def clean_database!
104
+ models = [Subscription]
105
+ models.each do |model|
106
+ ActiveRecord::Base.connection.execute "DELETE FROM #{model.table_name}"
107
+ end
108
+ end
109
+
110
+ clean_database!
@@ -0,0 +1,14 @@
1
+ cheddar_getter:
2
+ user: 'user@test.com'
3
+ pass: 'pass'
4
+ product_code: 'my_product'
5
+
6
+ recurly:
7
+ user: 'user@test.com'
8
+ pass: 'pass'
9
+ product_code: 'my_product'
10
+
11
+ chargify:
12
+ user: 'user@test.com'
13
+ pass: 'pass'
14
+ product_code: 'my_product'
@@ -0,0 +1,17 @@
1
+ sqlite3:
2
+ adapter: sqlite3
3
+ database: acts_as_subscription.sqlite3
4
+
5
+ mysql:
6
+ adapter: mysql
7
+ hostname: localhost
8
+ username: root
9
+ password:
10
+ database: acts_as_subscription
11
+
12
+ postgresql:
13
+ adapter: postgresql
14
+ hostname: localhost
15
+ username: postgres
16
+ password:
17
+ database: acts_as_subscription
@@ -0,0 +1,21 @@
1
+
2
+ class Subscription < ActiveRecord::Base
3
+
4
+ # Doesn't work without this include for gem testing - not needed for real-world use.
5
+ include ActsAsSubscription::Subscription
6
+
7
+ acts_as_subscription :backend => :dummy,
8
+ :user => 'user',
9
+ :password => 'pass',
10
+ :product_code => 'DUMMY_TEST'
11
+
12
+ end
13
+
14
+
15
+ class SubscriptionPlan < ActiveRecord::Base
16
+
17
+ include ActsAsSubscription::SubscriptionPlan
18
+
19
+ acts_as_subscription_plan
20
+
21
+ end
@@ -0,0 +1,30 @@
1
+
2
+ ActiveRecord::Schema.define :version => 0 do
3
+
4
+ create_table :subscriptions, :force => true do |t|
5
+ t.string :customer_code, :null => false
6
+ t.string :email, :null => false
7
+ t.string :first_name, :null => false
8
+ t.string :last_name, :null => false
9
+ t.string :plan_code, :null => false
10
+ t.string :zip_code
11
+ t.integer :cc_expiration_month
12
+ t.integer :cc_expiration_year
13
+ t.string :cc_last_digits
14
+ t.string :cc_verification_value
15
+ t.datetime :canceled_at
16
+ t.datetime :suspended_at
17
+ t.timestamps
18
+ end
19
+
20
+ create_table :subscription_plans, :force => true do |t|
21
+ t.string :code, :null => false
22
+ t.string :name, :null => false
23
+ t.text :description
24
+ t.string :billing_frequency, :null => false
25
+ t.float :recurring_charge, :null => false
26
+ t.boolean :active, :default => true
27
+ t.timestamps
28
+ end
29
+
30
+ end
metadata ADDED
@@ -0,0 +1,244 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: acts_as_subscription
3
+ version: !ruby/object:Gem::Version
4
+ hash: 29
5
+ prerelease: false
6
+ segments:
7
+ - 0
8
+ - 0
9
+ - 1
10
+ version: 0.0.1
11
+ platform: ruby
12
+ authors:
13
+ - Dave Perrett
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2011-02-01 00:00:00 +10:00
19
+ default_executable:
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
22
+ type: :runtime
23
+ prerelease: false
24
+ name: activemerchant
25
+ version_requirements: &id001 !ruby/object:Gem::Requirement
26
+ none: false
27
+ requirements:
28
+ - - ~>
29
+ - !ruby/object:Gem::Version
30
+ hash: 53
31
+ segments:
32
+ - 1
33
+ - 9
34
+ - 3
35
+ version: 1.9.3
36
+ requirement: *id001
37
+ - !ruby/object:Gem::Dependency
38
+ type: :runtime
39
+ prerelease: false
40
+ name: chargify_api_ares
41
+ version_requirements: &id002 !ruby/object:Gem::Requirement
42
+ none: false
43
+ requirements:
44
+ - - ~>
45
+ - !ruby/object:Gem::Version
46
+ hash: 29
47
+ segments:
48
+ - 0
49
+ - 3
50
+ - 7
51
+ version: 0.3.7
52
+ requirement: *id002
53
+ - !ruby/object:Gem::Dependency
54
+ type: :runtime
55
+ prerelease: false
56
+ name: hpricot
57
+ version_requirements: &id003 !ruby/object:Gem::Requirement
58
+ none: false
59
+ requirements:
60
+ - - ">="
61
+ - !ruby/object:Gem::Version
62
+ hash: 7
63
+ segments:
64
+ - 0
65
+ - 6
66
+ version: "0.6"
67
+ requirement: *id003
68
+ - !ruby/object:Gem::Dependency
69
+ type: :runtime
70
+ prerelease: false
71
+ name: mousetrap
72
+ version_requirements: &id004 !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ~>
76
+ - !ruby/object:Gem::Version
77
+ hash: 11
78
+ segments:
79
+ - 0
80
+ - 5
81
+ - 0
82
+ version: 0.5.0
83
+ requirement: *id004
84
+ - !ruby/object:Gem::Dependency
85
+ type: :runtime
86
+ prerelease: false
87
+ name: rails
88
+ version_requirements: &id005 !ruby/object:Gem::Requirement
89
+ none: false
90
+ requirements:
91
+ - - ~>
92
+ - !ruby/object:Gem::Version
93
+ hash: 1
94
+ segments:
95
+ - 3
96
+ - 0
97
+ - 3
98
+ version: 3.0.3
99
+ requirement: *id005
100
+ - !ruby/object:Gem::Dependency
101
+ type: :runtime
102
+ prerelease: false
103
+ name: uuidtools
104
+ version_requirements: &id006 !ruby/object:Gem::Requirement
105
+ none: false
106
+ requirements:
107
+ - - ">="
108
+ - !ruby/object:Gem::Version
109
+ hash: 3
110
+ segments:
111
+ - 0
112
+ version: "0"
113
+ requirement: *id006
114
+ - !ruby/object:Gem::Dependency
115
+ type: :development
116
+ prerelease: false
117
+ name: bundler
118
+ version_requirements: &id007 !ruby/object:Gem::Requirement
119
+ none: false
120
+ requirements:
121
+ - - ~>
122
+ - !ruby/object:Gem::Version
123
+ hash: 23
124
+ segments:
125
+ - 1
126
+ - 0
127
+ - 0
128
+ version: 1.0.0
129
+ requirement: *id007
130
+ - !ruby/object:Gem::Dependency
131
+ type: :development
132
+ prerelease: false
133
+ name: jeweler
134
+ version_requirements: &id008 !ruby/object:Gem::Requirement
135
+ none: false
136
+ requirements:
137
+ - - ~>
138
+ - !ruby/object:Gem::Version
139
+ hash: 7
140
+ segments:
141
+ - 1
142
+ - 5
143
+ - 2
144
+ version: 1.5.2
145
+ requirement: *id008
146
+ - !ruby/object:Gem::Dependency
147
+ type: :development
148
+ prerelease: false
149
+ name: rcov
150
+ version_requirements: &id009 !ruby/object:Gem::Requirement
151
+ none: false
152
+ requirements:
153
+ - - ">="
154
+ - !ruby/object:Gem::Version
155
+ hash: 41
156
+ segments:
157
+ - 0
158
+ - 9
159
+ - 9
160
+ version: 0.9.9
161
+ requirement: *id009
162
+ description: With ActsAsSubscription, you can hook your model into several subscription services, such as CheddarGetter.
163
+ email: mail@recursive-design.com
164
+ executables: []
165
+
166
+ extensions: []
167
+
168
+ extra_rdoc_files:
169
+ - LICENSE.txt
170
+ - README.rdoc
171
+ files:
172
+ - .autotest
173
+ - .rspec
174
+ - .rvmrc
175
+ - Gemfile
176
+ - LICENSE.txt
177
+ - README.rdoc
178
+ - Rakefile
179
+ - VERSION
180
+ - acts_as_subscription.gemspec
181
+ - autotest/discover.rb
182
+ - lib/acts_as_subscription.rb
183
+ - lib/acts_as_subscription/backend.rb
184
+ - lib/acts_as_subscription/backend/chargify_client.rb
185
+ - lib/acts_as_subscription/backend/cheddar_getter_client.rb
186
+ - lib/acts_as_subscription/backend/dummy_client.rb
187
+ - lib/acts_as_subscription/backend/recurly_client.rb
188
+ - lib/acts_as_subscription/error.rb
189
+ - lib/acts_as_subscription/railtie.rb
190
+ - lib/acts_as_subscription/subscription.rb
191
+ - lib/acts_as_subscription/subscription_plan.rb
192
+ - spec/backend/backend/chargify_client_spec.rb
193
+ - spec/backend/backend/cheddar_getter_client_spec.rb
194
+ - spec/backend/backend_spec.rb
195
+ - spec/models/subscription_plan_spec.rb
196
+ - spec/models/subscription_spec.rb
197
+ - spec/spec_helper.rb
198
+ - spec/support/backend.yml.example
199
+ - spec/support/database.yml
200
+ - spec/support/models.rb
201
+ - spec/support/schema.rb
202
+ has_rdoc: true
203
+ homepage: http://recursive-design.com/
204
+ licenses: []
205
+
206
+ post_install_message:
207
+ rdoc_options: []
208
+
209
+ require_paths:
210
+ - lib
211
+ required_ruby_version: !ruby/object:Gem::Requirement
212
+ none: false
213
+ requirements:
214
+ - - ">="
215
+ - !ruby/object:Gem::Version
216
+ hash: 3
217
+ segments:
218
+ - 0
219
+ version: "0"
220
+ required_rubygems_version: !ruby/object:Gem::Requirement
221
+ none: false
222
+ requirements:
223
+ - - ">="
224
+ - !ruby/object:Gem::Version
225
+ hash: 3
226
+ segments:
227
+ - 0
228
+ version: "0"
229
+ requirements: []
230
+
231
+ rubyforge_project: nowarning
232
+ rubygems_version: 1.3.7
233
+ signing_key:
234
+ specification_version: 3
235
+ summary: ActsAsSubscription is a plugin for rails that provides recurring subscription capabilities to a model.
236
+ test_files:
237
+ - spec/backend/backend/chargify_client_spec.rb
238
+ - spec/backend/backend/cheddar_getter_client_spec.rb
239
+ - spec/backend/backend_spec.rb
240
+ - spec/models/subscription_plan_spec.rb
241
+ - spec/models/subscription_spec.rb
242
+ - spec/spec_helper.rb
243
+ - spec/support/models.rb
244
+ - spec/support/schema.rb