jackpot 0.0.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.
Files changed (168) hide show
  1. data/.gitignore +16 -0
  2. data/.rspec +1 -0
  3. data/.rvmrc.example +1 -0
  4. data/.travis.yml +12 -0
  5. data/Gemfile +9 -0
  6. data/Gemfile.lock +181 -0
  7. data/MIT-LICENSE +20 -0
  8. data/README.md +134 -0
  9. data/Rakefile +25 -0
  10. data/app/assets/images/jackpot/.gitkeep +0 -0
  11. data/app/assets/javascripts/jackpot/application.js +5 -0
  12. data/app/assets/javascripts/jackpot/bootstrap.js +32 -0
  13. data/app/assets/javascripts/jackpot/customers.js +2 -0
  14. data/app/assets/javascripts/jackpot/login.js +1 -0
  15. data/app/assets/javascripts/jackpot/payments.js +2 -0
  16. data/app/assets/javascripts/jackpot/subscriptions.js +2 -0
  17. data/app/assets/stylesheets/jackpot/application.css +9 -0
  18. data/app/assets/stylesheets/jackpot/customers.css +4 -0
  19. data/app/assets/stylesheets/jackpot/jackpot.css +10 -0
  20. data/app/controllers/jackpot/application_controller.rb +4 -0
  21. data/app/controllers/jackpot/customers_controller.rb +100 -0
  22. data/app/controllers/jackpot/payments_controller.rb +20 -0
  23. data/app/controllers/jackpot/subscriptions_controller.rb +86 -0
  24. data/app/helpers/jackpot/application_helper.rb +27 -0
  25. data/app/helpers/jackpot/customers_helper.rb +7 -0
  26. data/app/helpers/jackpot/subscriptions_helper.rb +4 -0
  27. data/app/models/jackpot/card.rb +29 -0
  28. data/app/models/jackpot/customer.rb +48 -0
  29. data/app/models/jackpot/gateway.rb +28 -0
  30. data/app/models/jackpot/payment.rb +33 -0
  31. data/app/models/jackpot/subscription.rb +13 -0
  32. data/app/models/jackpot/user.rb +25 -0
  33. data/app/views/jackpot/customers/_credit_card_form.html.erb +42 -0
  34. data/app/views/jackpot/customers/_form.html.erb +17 -0
  35. data/app/views/jackpot/customers/edit.html.erb +13 -0
  36. data/app/views/jackpot/customers/index.html.erb +30 -0
  37. data/app/views/jackpot/customers/new.html.erb +8 -0
  38. data/app/views/jackpot/customers/show.html.erb +32 -0
  39. data/app/views/jackpot/payments/create.html.erb +1 -0
  40. data/app/views/jackpot/payments/index.html.erb +25 -0
  41. data/app/views/jackpot/shared/_flash_messages.html.erb +6 -0
  42. data/app/views/jackpot/shared/_navigation.html.erb +5 -0
  43. data/app/views/jackpot/subscriptions/_form.html.erb +13 -0
  44. data/app/views/jackpot/subscriptions/edit.html.erb +6 -0
  45. data/app/views/jackpot/subscriptions/index.html.erb +29 -0
  46. data/app/views/jackpot/subscriptions/new.html.erb +4 -0
  47. data/app/views/jackpot/subscriptions/show.html.erb +23 -0
  48. data/app/views/layouts/devise.html.erb +22 -0
  49. data/app/views/layouts/jackpot/application.html.erb +39 -0
  50. data/config/initializers/jackpot_devise.rb +226 -0
  51. data/config/locales/devise.en.yml +57 -0
  52. data/config/routes.rb +17 -0
  53. data/db/migrate/20111221002616_create_jackpot_payments.rb +11 -0
  54. data/db/migrate/20111230014003_add_customer_information_to_jackpot_payments.rb +5 -0
  55. data/db/migrate/20120102223341_create_jackpot_subscriptions.rb +10 -0
  56. data/db/migrate/20120103211153_create_jackpot_customers.rb +11 -0
  57. data/db/migrate/20120104164830_add_credit_card_number_to_customer.rb +5 -0
  58. data/db/migrate/20120130173242_add_credit_card_information_to_customers.rb +7 -0
  59. data/db/migrate/20120208191815_add_billing_period_to_jackpot_subscriptions.rb +5 -0
  60. data/db/migrate/20120208191934_add_good_until_date_to_jackpot_customers.rb +6 -0
  61. data/db/migrate/20120209203542_add_subscription_and_customer_to_jackpot_payments.rb +8 -0
  62. data/db/migrate/20120209212043_rename_column_token_in_jackpot_payments.rb +5 -0
  63. data/db/migrate/20120210144038_devise_create_jackpot_users.rb +49 -0
  64. data/jackpot.gemspec +33 -0
  65. data/lib/jackpot.rb +23 -0
  66. data/lib/jackpot/configuration.rb +33 -0
  67. data/lib/jackpot/cron.rb +22 -0
  68. data/lib/jackpot/engine.rb +14 -0
  69. data/lib/jackpot/errors.rb +18 -0
  70. data/lib/jackpot/factory.rb +26 -0
  71. data/lib/jackpot/version.rb +3 -0
  72. data/lib/tasks/jackpot_tasks.rake +38 -0
  73. data/script/rails +6 -0
  74. data/spec/controllers/jackpot/customers_controller_spec.rb +170 -0
  75. data/spec/controllers/jackpot/payments_controller_spec.rb +47 -0
  76. data/spec/controllers/jackpot/subscriptions_controller_spec.rb +153 -0
  77. data/spec/dummy/.gitignore +1 -0
  78. data/spec/dummy/Rakefile +7 -0
  79. data/spec/dummy/app/assets/javascripts/application.js +9 -0
  80. data/spec/dummy/app/assets/stylesheets/application.css +7 -0
  81. data/spec/dummy/app/controllers/application_controller.rb +3 -0
  82. data/spec/dummy/app/helpers/application_helper.rb +2 -0
  83. data/spec/dummy/app/mailers/.gitkeep +0 -0
  84. data/spec/dummy/app/models/.gitkeep +0 -0
  85. data/spec/dummy/app/views/layouts/application.html.erb +14 -0
  86. data/spec/dummy/config.ru +4 -0
  87. data/spec/dummy/config/application.rb +51 -0
  88. data/spec/dummy/config/boot.rb +10 -0
  89. data/spec/dummy/config/database.yml +17 -0
  90. data/spec/dummy/config/environment.rb +5 -0
  91. data/spec/dummy/config/environments/development.rb +32 -0
  92. data/spec/dummy/config/environments/production.rb +60 -0
  93. data/spec/dummy/config/environments/test.rb +41 -0
  94. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  95. data/spec/dummy/config/initializers/inflections.rb +10 -0
  96. data/spec/dummy/config/initializers/jackpot.rb +13 -0
  97. data/spec/dummy/config/initializers/mime_types.rb +5 -0
  98. data/spec/dummy/config/initializers/secret_token.rb +7 -0
  99. data/spec/dummy/config/initializers/session_store.rb +8 -0
  100. data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
  101. data/spec/dummy/config/locales/en.yml +5 -0
  102. data/spec/dummy/config/routes.rb +3 -0
  103. data/spec/dummy/db/schema.rb +68 -0
  104. data/spec/dummy/lib/assets/.gitkeep +0 -0
  105. data/spec/dummy/public/404.html +26 -0
  106. data/spec/dummy/public/422.html +26 -0
  107. data/spec/dummy/public/500.html +26 -0
  108. data/spec/dummy/public/favicon.ico +0 -0
  109. data/spec/dummy/public/index.html +5 -0
  110. data/spec/dummy/public/payment.html +36 -0
  111. data/spec/dummy/script/rails +6 -0
  112. data/spec/fixtures/vcr/Create_Customers_To_bill_monthly_my_customers_As_a_user_I_want_to_record_their_billing_information_/assigning_credit_card_information_to_customer.yml +34 -0
  113. data/spec/fixtures/vcr/Jackpot_Customer/_update_credit_card_number/when_card_is_valid/.yml +34 -0
  114. data/spec/fixtures/vcr/Jackpot_Customer/_update_credit_card_number/when_card_is_valid/when_persisting/should_NEVER_persist_in_the_database_the_actual_card_number.yml +34 -0
  115. data/spec/fixtures/vcr/Jackpot_Customer/_update_credit_card_number/when_card_is_valid/when_persisting/should_NEVER_persist_in_the_database_the_verification_value.yml +34 -0
  116. data/spec/fixtures/vcr/Jackpot_Customer/_update_credit_card_number/when_card_is_valid/when_persisting/should_persist_in_the_database_the_ONLY_last_four_digits.yml +34 -0
  117. data/spec/fixtures/vcr/Jackpot_Customer/_update_credit_card_number/when_card_is_valid/when_persisting/should_persist_the_card_information.yml +34 -0
  118. data/spec/fixtures/vcr/Jackpot_Customer/_update_credit_card_number/when_card_is_valid/when_persisting/should_store_this_card_at_the_gateway.yml +34 -0
  119. data/spec/fixtures/vcr/Jackpot_Payment/_create/with_valid_token_information/creates_a_new_payment.yml +96 -0
  120. data/spec/fixtures/vcr/Jackpot_Payment/_create/with_valid_token_information/does_not_persist_credit_card_token_information.yml +96 -0
  121. data/spec/fixtures/vcr/Jackpot_Payment/_create/with_valid_token_information/records_the_payment_transaction_id_for_future_reference.yml +96 -0
  122. data/spec/fixtures/vcr/Jackpot_Payment/_create/with_valid_token_information/records_this_payment_information.yml +96 -0
  123. data/spec/fixtures/vcr/Jackpot_Payment/_customer_name/returns_its_customer_email.yml +96 -0
  124. data/spec/fixtures/vcr/jackpot/customer/updatecard.yml +34 -0
  125. data/spec/fixtures/vcr/jackpot/customer_expiration_date.yml +34 -0
  126. data/spec/fixtures/vcr/jackpot/receiving_payments.yml +96 -0
  127. data/spec/helpers/jackpot/customers_helper_spec.rb +16 -0
  128. data/spec/helpers/jackpot/subscriptions_helper_spec.rb +4 -0
  129. data/spec/lib/cron_spec.rb +39 -0
  130. data/spec/lib/factory_spec.rb +40 -0
  131. data/spec/models/jackpot/card_spec.rb +23 -0
  132. data/spec/models/jackpot/customer_spec.rb +140 -0
  133. data/spec/models/jackpot/gateway_spec.rb +22 -0
  134. data/spec/models/jackpot/payment_spec.rb +74 -0
  135. data/spec/models/jackpot/subscription_spec.rb +19 -0
  136. data/spec/requests/jackpot/jackpot_assign_subscription_to_customer_spec.rb +39 -0
  137. data/spec/requests/jackpot/jackpot_create_customer_spec.rb +73 -0
  138. data/spec/requests/jackpot/jackpot_create_subscriptions_spec.rb +27 -0
  139. data/spec/requests/jackpot/jackpot_receive_payments_spec.rb +34 -0
  140. data/spec/spec_helper.rb +41 -0
  141. data/spec/support/active_merchant.rb +1 -0
  142. data/spec/support/capybara.rb +6 -0
  143. data/spec/support/devise.rb +21 -0
  144. data/spec/support/factories/jackpot_customers.rb +36 -0
  145. data/spec/support/factories/jackpot_payments.rb +7 -0
  146. data/spec/support/factories/jackpot_subscriptions.rb +9 -0
  147. data/spec/support/factories/jackpot_users.rb +9 -0
  148. data/spec/support/helpers.rb +16 -0
  149. data/spec/support/routes.rb +3 -0
  150. data/spec/support/vcr.rb +10 -0
  151. data/vendor/assets/images/twitter/bootstrap/glyphicons-halflings-white.png +0 -0
  152. data/vendor/assets/images/twitter/bootstrap/glyphicons-halflings.png +0 -0
  153. data/vendor/assets/javascripts/twitter/bootstrap.js +12 -0
  154. data/vendor/assets/javascripts/twitter/bootstrap/bootstrap-alert.js +91 -0
  155. data/vendor/assets/javascripts/twitter/bootstrap/bootstrap-button.js +98 -0
  156. data/vendor/assets/javascripts/twitter/bootstrap/bootstrap-carousel.js +154 -0
  157. data/vendor/assets/javascripts/twitter/bootstrap/bootstrap-collapse.js +136 -0
  158. data/vendor/assets/javascripts/twitter/bootstrap/bootstrap-dropdown.js +92 -0
  159. data/vendor/assets/javascripts/twitter/bootstrap/bootstrap-modal.js +209 -0
  160. data/vendor/assets/javascripts/twitter/bootstrap/bootstrap-popover.js +95 -0
  161. data/vendor/assets/javascripts/twitter/bootstrap/bootstrap-scrollspy.js +125 -0
  162. data/vendor/assets/javascripts/twitter/bootstrap/bootstrap-tab.js +130 -0
  163. data/vendor/assets/javascripts/twitter/bootstrap/bootstrap-tooltip.js +270 -0
  164. data/vendor/assets/javascripts/twitter/bootstrap/bootstrap-transition.js +51 -0
  165. data/vendor/assets/javascripts/twitter/bootstrap/bootstrap-typeahead.js +271 -0
  166. data/vendor/assets/stylesheets/twitter/bootstrap/bootstrap-responsive.css +567 -0
  167. data/vendor/assets/stylesheets/twitter/bootstrap/bootstrap.css.erb +3366 -0
  168. metadata +351 -0
@@ -0,0 +1,16 @@
1
+ require 'spec_helper'
2
+
3
+ describe Jackpot::CustomersHelper do
4
+ describe "#subscription_name_when_available" do
5
+ it "returns '-' when there is no subscription available" do
6
+ customer = FactoryGirl.build(:customer)
7
+ helper.subscription_name_when_available(customer).should == "-"
8
+ end
9
+
10
+ it "returns the subscription name when it is available" do
11
+ customer = FactoryGirl.build(:customer_with_subscription)
12
+ helper.subscription_name_when_available(customer).should == "Gold"
13
+ end
14
+
15
+ end
16
+ end
@@ -0,0 +1,4 @@
1
+ require 'spec_helper'
2
+
3
+ describe Jackpot::SubscriptionsHelper do
4
+ end
@@ -0,0 +1,39 @@
1
+ require './lib/jackpot/cron'
2
+ require './lib/jackpot/errors'
3
+ require 'rspec'
4
+
5
+ describe Jackpot::Cron do
6
+ let(:logger) { stub(:info => true) }
7
+
8
+ it "finds every overdue customer and bills their cards" do
9
+ customers = [ mock_customer(true), mock_customer(true) ]
10
+ customer_storage = stub(:overdue => customers)
11
+ cron = Jackpot::Cron.new(customer_storage, logger)
12
+ cron.run
13
+ end
14
+
15
+
16
+ context "when something has failed" do
17
+
18
+ it "logs the execption" do
19
+ customers = [ mock_customer(true), failed_customer ]
20
+ customer_storage = stub(:overdue => customers)
21
+ logger.should_receive(:error)
22
+ cron = Jackpot::Cron.new(customer_storage, logger)
23
+ cron.run
24
+ end
25
+ end
26
+
27
+ end
28
+
29
+ def mock_customer(return_value)
30
+ customer = stub(:pay_subscription => return_value)
31
+ customer.should_receive(:pay_subscription).and_return(return_value)
32
+ customer
33
+ end
34
+
35
+ def failed_customer
36
+ customer = Object.new
37
+ customer.stub(:pay_subscription).and_raise(Jackpot::Error.new)
38
+ customer
39
+ end
@@ -0,0 +1,40 @@
1
+ require 'spec_helper'
2
+
3
+ describe Jackpot::Factory do
4
+
5
+ it "creates jackpot gateways" do
6
+ factory = Jackpot::Factory.new("type"=> :braintree)
7
+ factory.build.should be_a(Jackpot::Gateway)
8
+ end
9
+
10
+ it "raises an error upon unsupported gateways" do
11
+ factory = Jackpot::Factory.new("type"=> :notexistinggatway)
12
+ expect { factory.build }.to raise_error(Jackpot::Errors::InvalidGateway)
13
+ end
14
+
15
+ context "supported gateways" do
16
+ before do
17
+ ActiveMerchant::Billing::BraintreeGateway
18
+ .stub(:new).with(:login => 'login',
19
+ :password => 'password',
20
+ :mode => 'test').and_return('braintree')
21
+
22
+ ActiveMerchant::Billing::BogusGateway.stub(:new).and_return('bogus')
23
+
24
+ end
25
+ let(:opts) { { :type => :braintree, :login => 'login', :password => 'password', :mode => 'test' } }
26
+
27
+ it "supports braintree" do
28
+ factory = Jackpot::Factory.new(opts)
29
+ Jackpot::Gateway.should_receive(:new).with('braintree')
30
+ factory.build
31
+ end
32
+
33
+ it "supports bogus for testing" do
34
+ factory = Jackpot::Factory.new(:type => :bogus)
35
+ Jackpot::Gateway.should_receive(:new).with('bogus')
36
+ factory.build
37
+ end
38
+ end
39
+
40
+ end
@@ -0,0 +1,23 @@
1
+ require 'spec_helper'
2
+
3
+ describe Jackpot::Card do
4
+
5
+ describe "#new" do
6
+ subject { Jackpot::Card.new(credit_card_hash) }
7
+
8
+ it { subject.masquerade_number.should == 'XXXX-XXXX-XXXX-4242' }
9
+ it { subject.number.should == '4242424242424242' }
10
+ it { subject.month.should == 1 }
11
+ it { subject.year.should == next_year }
12
+ it { subject.first_name.should == "John" }
13
+ it { subject.last_name.should == "Doe" }
14
+ it { subject.verification_value.should == 123 }
15
+ end
16
+
17
+
18
+ describe ".valid?" do
19
+ it { Jackpot::Card.new(credit_card_hash('987', :year => '2000')).should_not be_valid }
20
+ it { Jackpot::Card.new(credit_card_hash).should be_valid }
21
+ end
22
+
23
+ end
@@ -0,0 +1,140 @@
1
+ require 'spec_helper'
2
+ require 'timecop'
3
+
4
+ describe Jackpot::Customer do
5
+ it { should belong_to :subscription }
6
+ it { should have_many(:payments).through(:subscription) }
7
+
8
+ it { should_not allow_mass_assignment_of :credit_card_number }
9
+ it { should_not allow_mass_assignment_of :credit_card_expiry_year }
10
+ it { should_not allow_mass_assignment_of :credit_card_expiry_month }
11
+ it { should_not allow_mass_assignment_of :credit_card_token }
12
+
13
+ let(:customer) { Jackpot::Customer.new }
14
+ let(:card) { Jackpot::Card.new credit_card_hash }
15
+ let(:invalid_card) { Jackpot::Card.new credit_card_hash('9', :year => '2000') }
16
+
17
+ describe ".expiration_date" , :vcr => { :cassette_name => "jackpot/customer_expiration_date" } do
18
+ it "should return this card expiration date" do
19
+ customer.update_credit_card(card)
20
+ customer.expiration_date.should == "1/#{next_year}"
21
+ end
22
+ end
23
+
24
+
25
+ describe ".overdue" do
26
+ before do
27
+ Timecop.freeze(Date.today) do
28
+ @today = Factory(:customer, :good_until => Date.today)
29
+ @tomorrow = Factory(:customer, :good_until => Date.tomorrow)
30
+ @yesterday = Factory(:customer, :good_until => Date.yesterday)
31
+ end
32
+ end
33
+
34
+ subject { Jackpot::Customer.overdue}
35
+
36
+ it { subject.should include @yesterday }
37
+ it { subject.should_not include @tomorrow }
38
+ it { subject.should_not include @today }
39
+
40
+ end
41
+
42
+ describe ".due_in" do
43
+ before do
44
+ Timecop.freeze(Date.today) do
45
+ @next_week = Factory(:customer, :good_until => 1.week.from_now)
46
+ @thirty_days = Factory(:customer, :good_until => 30.days.from_now)
47
+ @two_days = Factory(:customer, :good_until => 2.days.from_now)
48
+ @tomorrow = Factory(:customer, :good_until => Date.tomorrow)
49
+ end
50
+ end
51
+
52
+ context "two days" do
53
+ subject { Jackpot::Customer.due_in 2}
54
+
55
+ it { subject.should include @tomorrow }
56
+ it { subject.should include @two_days }
57
+ it { subject.should_not include @thirty_days }
58
+ it { subject.should_not include @next_week }
59
+ end
60
+
61
+ end
62
+
63
+
64
+ describe ".pay_subscription" do
65
+ let(:customer) { Factory(:customer_with_subscription,
66
+ :credit_card_token => '42') }
67
+
68
+ let(:customer_with_no_card_saved) { Factory(:customer_with_subscription) }
69
+
70
+ it "fetches charges this customer subscription using his/hers credit card token" do
71
+ customer.subscription.should_receive(:charge).with(customer).and_return(true)
72
+ customer.pay_subscription
73
+ end
74
+
75
+ it "sets this customer as not due until the next billing period" do
76
+ customer.subscription.stub(:charge).with(customer).and_return(true)
77
+ customer.pay_subscription
78
+
79
+ retrieved_customer = Jackpot::Customer.find(customer)
80
+ retrieved_customer.good_until.should == Date.today + 1.month
81
+ end
82
+ it { expect { customer_with_no_card_saved.pay_subscription }.to raise_error(Jackpot::Errors::CustomerHasNoCardSaved) }
83
+ end
84
+
85
+ describe ".update_credit_card_number" do
86
+
87
+ context "when card is invalid" do
88
+ it "raises invalid card exception" do
89
+ expect { customer.update_credit_card(invalid_card)}.to raise_error(Jackpot::Errors::CardIsInvalid)
90
+ end
91
+
92
+ it "shouldn't be persisted" do
93
+ expect { customer.reload }.to raise_error(ActiveRecord::RecordNotFound)
94
+ end
95
+
96
+ end
97
+
98
+ context "when card is valid", :vcr => { :cassette_name => "jackpot/customer/updatecard" } do
99
+ before(:each) do
100
+ customer.update_credit_card(card)
101
+ end
102
+
103
+ it "should masquerade the card number" do
104
+ customer.credit_card_number.should == 'XXXX-XXXX-XXXX-4242'
105
+ end
106
+
107
+ it { customer.credit_card_expiry_month.should == 1 }
108
+ it { customer.credit_card_expiry_year.should == next_year }
109
+
110
+ context "when persisting" do
111
+
112
+ let(:retrieved_customer) { Jackpot::Customer.find customer }
113
+
114
+ it "should store this card at the gateway" do
115
+ # Check corresponding VCR for this magical number
116
+ retrieved_customer.credit_card_token.should == '1979016654'
117
+ end
118
+
119
+ it "should persist the card information" do
120
+ retrieved_customer.credit_card_number.should == 'XXXX-XXXX-XXXX-4242'
121
+ end
122
+
123
+ it "should persist in the database the ONLY last four digits" do
124
+ retrieved_customer.credit_card_number.should == 'XXXX-XXXX-XXXX-4242'
125
+ end
126
+
127
+ it "should NEVER persist in the database the actual card number" do
128
+ retrieved_customer.credit_card_number.should_not == credit_card_hash[:number]
129
+ end
130
+
131
+ it "should NEVER persist in the database the verification value" do
132
+ retrieved_customer.credit_card_verification_value.should_not == 123
133
+ retrieved_customer.credit_card_verification_value.should be_nil
134
+ end
135
+
136
+ end
137
+ end
138
+ end
139
+
140
+ end
@@ -0,0 +1,22 @@
1
+ require 'spec_helper'
2
+
3
+ describe Jackpot::Gateway do
4
+
5
+ let(:gateway_component) { ActiveMerchant::Billing::BogusGateway.new }
6
+ subject { Jackpot::Gateway.new(gateway_component) }
7
+
8
+ it "checks if the gateway component has a method" do
9
+ gateway_component.should_receive(:respond_to?).with('purchase')
10
+ subject.respond_to? 'purchase'
11
+ end
12
+
13
+ it "should not recognize methods this component doesn't respond to" do
14
+ expect { subject.foo }.to raise_error(NoMethodError)
15
+ end
16
+
17
+ it "forwards every call the component knows to gateway component" do
18
+ gateway_component.should_receive(:purchase).with(1000, 'args')
19
+ subject.purchase(1000, 'args')
20
+ end
21
+
22
+ end
@@ -0,0 +1,74 @@
1
+ require 'spec_helper'
2
+
3
+ module Jackpot
4
+ describe Payment , :vcr do
5
+ it { should belong_to :customer }
6
+ it { should belong_to :subscription }
7
+
8
+ let(:fail_response) { stub("success?" => false) }
9
+
10
+ let(:subscription) { Factory(:subscription, :price => 4200) }
11
+ let(:customer) { Factory(:customer_with_valid_card, :email => 'john@doe.com') }
12
+
13
+ let(:invalid_customer) { Factory(:customer, :email => 'john@doe.com',
14
+ :credit_card_token => '1') }
15
+
16
+ let(:payment) { Payment.create(:description => "foo",
17
+ :customer => customer,
18
+ :subscription => subscription) }
19
+
20
+ let(:invalid_payment) { Payment.create(:description => "foo",
21
+ :customer => invalid_customer,
22
+ :subscription => subscription) }
23
+
24
+
25
+ describe ".customer_name" do
26
+ it "returns its customer email" do
27
+ payment.customer_email.should == "john@doe.com"
28
+ end
29
+ end
30
+
31
+ describe "#create" do
32
+ context "with valid token information" do
33
+ let(:retrieved_payment) { Payment.find(payment.id) }
34
+
35
+ it "creates a new payment" do
36
+ expect { payment }.to change(Payment, :count).by(1)
37
+ end
38
+
39
+ it "records the payment transaction id for future reference" do
40
+ retrieved_payment.payment_transaction_token.should == "1561142493"
41
+ end
42
+
43
+ it "records this payment information" do
44
+ retrieved_payment.amount.should == 4200
45
+ retrieved_payment.description.should_not be_nil
46
+ retrieved_payment.subscription.should_not be_nil
47
+ end
48
+
49
+ it "does not persist credit card token information" do
50
+ retrieved_payment.credit_card_token.should be_nil
51
+ end
52
+ end
53
+ context "with invalid token information" do
54
+ before do
55
+ Jackpot::Gateway.any_instance.stub(:authorize)
56
+ .with(4200, '1')
57
+ .and_return(fail_response)
58
+ end
59
+
60
+ it "raises an unauthorized token information" do
61
+ expect { invalid_payment }.to raise_error Jackpot::Errors::UnauthorizedPayment
62
+ end
63
+
64
+ it "must not save an additional payment" do
65
+ begin
66
+ invalid_payment
67
+ rescue Jackpot::Errors::UnauthorizedPayment
68
+ Payment.count.should == 0
69
+ end
70
+ end
71
+ end
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,19 @@
1
+ require 'spec_helper'
2
+
3
+ describe Jackpot::Subscription do
4
+ it { should have_many(:customers) }
5
+ it { should validate_presence_of :name }
6
+ it { should have_many(:payments) }
7
+
8
+
9
+ describe ".charge" do
10
+ let(:customer_to_be_charged) { Factory(:customer_with_subscription) }
11
+ subject { customer_to_be_charged.subscription }
12
+
13
+ it "creates a payment for the given customer" ,
14
+ :vcr => { :cassette_name => "jackpot/subscription_charge" } do
15
+ expect { subject.charge(customer_to_be_charged)}.to change(subject.payments, :count).by(1)
16
+ end
17
+ end
18
+
19
+ end
@@ -0,0 +1,39 @@
1
+ require 'spec_helper'
2
+
3
+
4
+ feature "Assign Subscription to customer", %q{
5
+ To bill my plan's subscribers
6
+ As a user
7
+ I want to record their plan and subscription
8
+ } do
9
+
10
+ let(:user) { Factory(:user) }
11
+
12
+ before do
13
+ sign_in user
14
+
15
+ @subscription = Factory :subscription, :name => "Gold"
16
+ end
17
+
18
+ scenario "creating a customer and assigning a new subscription" do
19
+ visit customers_path
20
+ click_link "New Customer"
21
+
22
+ fill_in "customer[email]", with: "john@doe.net"
23
+ select 'Gold', :from => 'Subscription'
24
+
25
+ click_button "Create Customer"
26
+
27
+ # Customer created successfully
28
+ page.should have_css(".alert.alert-success")
29
+ # Subscription is listed at Customer details
30
+ page.should have_content("Gold")
31
+
32
+ visit subscription_path(@subscription)
33
+ within("#subscribers") do
34
+ page.should have_content("john@doe.net")
35
+ end
36
+
37
+ end
38
+
39
+ end
@@ -0,0 +1,73 @@
1
+ require 'spec_helper'
2
+
3
+
4
+ feature "Create Customers", %q{
5
+ To bill monthly my customers
6
+ As a user
7
+ I want to record their billing information
8
+ } do
9
+
10
+
11
+ let(:user) { Factory(:user) }
12
+
13
+ before do
14
+ sign_in user
15
+ end
16
+
17
+
18
+ scenario "customer creation" do
19
+ visit customers_path
20
+ click_link "New Customer"
21
+
22
+ page.should have_no_css("#credit-card-information")
23
+
24
+ within('form') do
25
+ fill_in "customer[email]" , :with => "foo@bar.com"
26
+ fill_in "customer[description]" , :with => "random description"
27
+
28
+ click_button("Create Customer")
29
+ end
30
+
31
+ # Customer should have been created successfully
32
+ page.should have_css (".alert.alert-success")
33
+ page.should have_content("foo@bar.com" )
34
+ end
35
+
36
+ it "assigning credit card information to customer", :vcr do
37
+ ActiveMerchant::Billing::Base.mode = :test
38
+ Jackpot::Payment.gateway = Jackpot::Gateway.new(ActiveMerchant::Billing::BraintreeGateway.new :login => "demo" , :password => 'password')
39
+
40
+ @customer = FactoryGirl.create("customer", :email => "baz@bar.com")
41
+
42
+
43
+ visit customers_path
44
+ within("#customer-#{@customer.id}") { click_link "Edit" }
45
+
46
+
47
+ page.should have_css ("#credit-card-information" )
48
+ # fill credit card's information
49
+ within("#credit-card-form") do
50
+ fill_in "credit_card[number]" , :with => "5105105105105100"
51
+ fill_in "credit_card[month]" , :with => "5"
52
+ fill_in "credit_card[year]" , :with => next_year
53
+ fill_in "credit_card[first_name]" , :with => 'John'
54
+ fill_in "credit_card[last_name]" , :with => 'Doe'
55
+ fill_in "credit_card[verification_value]" , :with => 123
56
+
57
+ # submit data
58
+
59
+ click_button 'Confirm'
60
+ end
61
+ page.should have_css (".alert.alert-success" )
62
+
63
+ within("#customer") do
64
+ # Not quite what would be expected but this is due Bogus Gateway usage
65
+ page.should have_content ("XXXX-XXXX-XXXX-5100")
66
+ page.should have_content ( next_year )
67
+ page.should have_content ( "5" )
68
+ page.should have_no_content ( "123")
69
+ end
70
+
71
+ end
72
+
73
+ end