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.
- data/.gitignore +16 -0
- data/.rspec +1 -0
- data/.rvmrc.example +1 -0
- data/.travis.yml +12 -0
- data/Gemfile +9 -0
- data/Gemfile.lock +181 -0
- data/MIT-LICENSE +20 -0
- data/README.md +134 -0
- data/Rakefile +25 -0
- data/app/assets/images/jackpot/.gitkeep +0 -0
- data/app/assets/javascripts/jackpot/application.js +5 -0
- data/app/assets/javascripts/jackpot/bootstrap.js +32 -0
- data/app/assets/javascripts/jackpot/customers.js +2 -0
- data/app/assets/javascripts/jackpot/login.js +1 -0
- data/app/assets/javascripts/jackpot/payments.js +2 -0
- data/app/assets/javascripts/jackpot/subscriptions.js +2 -0
- data/app/assets/stylesheets/jackpot/application.css +9 -0
- data/app/assets/stylesheets/jackpot/customers.css +4 -0
- data/app/assets/stylesheets/jackpot/jackpot.css +10 -0
- data/app/controllers/jackpot/application_controller.rb +4 -0
- data/app/controllers/jackpot/customers_controller.rb +100 -0
- data/app/controllers/jackpot/payments_controller.rb +20 -0
- data/app/controllers/jackpot/subscriptions_controller.rb +86 -0
- data/app/helpers/jackpot/application_helper.rb +27 -0
- data/app/helpers/jackpot/customers_helper.rb +7 -0
- data/app/helpers/jackpot/subscriptions_helper.rb +4 -0
- data/app/models/jackpot/card.rb +29 -0
- data/app/models/jackpot/customer.rb +48 -0
- data/app/models/jackpot/gateway.rb +28 -0
- data/app/models/jackpot/payment.rb +33 -0
- data/app/models/jackpot/subscription.rb +13 -0
- data/app/models/jackpot/user.rb +25 -0
- data/app/views/jackpot/customers/_credit_card_form.html.erb +42 -0
- data/app/views/jackpot/customers/_form.html.erb +17 -0
- data/app/views/jackpot/customers/edit.html.erb +13 -0
- data/app/views/jackpot/customers/index.html.erb +30 -0
- data/app/views/jackpot/customers/new.html.erb +8 -0
- data/app/views/jackpot/customers/show.html.erb +32 -0
- data/app/views/jackpot/payments/create.html.erb +1 -0
- data/app/views/jackpot/payments/index.html.erb +25 -0
- data/app/views/jackpot/shared/_flash_messages.html.erb +6 -0
- data/app/views/jackpot/shared/_navigation.html.erb +5 -0
- data/app/views/jackpot/subscriptions/_form.html.erb +13 -0
- data/app/views/jackpot/subscriptions/edit.html.erb +6 -0
- data/app/views/jackpot/subscriptions/index.html.erb +29 -0
- data/app/views/jackpot/subscriptions/new.html.erb +4 -0
- data/app/views/jackpot/subscriptions/show.html.erb +23 -0
- data/app/views/layouts/devise.html.erb +22 -0
- data/app/views/layouts/jackpot/application.html.erb +39 -0
- data/config/initializers/jackpot_devise.rb +226 -0
- data/config/locales/devise.en.yml +57 -0
- data/config/routes.rb +17 -0
- data/db/migrate/20111221002616_create_jackpot_payments.rb +11 -0
- data/db/migrate/20111230014003_add_customer_information_to_jackpot_payments.rb +5 -0
- data/db/migrate/20120102223341_create_jackpot_subscriptions.rb +10 -0
- data/db/migrate/20120103211153_create_jackpot_customers.rb +11 -0
- data/db/migrate/20120104164830_add_credit_card_number_to_customer.rb +5 -0
- data/db/migrate/20120130173242_add_credit_card_information_to_customers.rb +7 -0
- data/db/migrate/20120208191815_add_billing_period_to_jackpot_subscriptions.rb +5 -0
- data/db/migrate/20120208191934_add_good_until_date_to_jackpot_customers.rb +6 -0
- data/db/migrate/20120209203542_add_subscription_and_customer_to_jackpot_payments.rb +8 -0
- data/db/migrate/20120209212043_rename_column_token_in_jackpot_payments.rb +5 -0
- data/db/migrate/20120210144038_devise_create_jackpot_users.rb +49 -0
- data/jackpot.gemspec +33 -0
- data/lib/jackpot.rb +23 -0
- data/lib/jackpot/configuration.rb +33 -0
- data/lib/jackpot/cron.rb +22 -0
- data/lib/jackpot/engine.rb +14 -0
- data/lib/jackpot/errors.rb +18 -0
- data/lib/jackpot/factory.rb +26 -0
- data/lib/jackpot/version.rb +3 -0
- data/lib/tasks/jackpot_tasks.rake +38 -0
- data/script/rails +6 -0
- data/spec/controllers/jackpot/customers_controller_spec.rb +170 -0
- data/spec/controllers/jackpot/payments_controller_spec.rb +47 -0
- data/spec/controllers/jackpot/subscriptions_controller_spec.rb +153 -0
- data/spec/dummy/.gitignore +1 -0
- data/spec/dummy/Rakefile +7 -0
- data/spec/dummy/app/assets/javascripts/application.js +9 -0
- data/spec/dummy/app/assets/stylesheets/application.css +7 -0
- data/spec/dummy/app/controllers/application_controller.rb +3 -0
- data/spec/dummy/app/helpers/application_helper.rb +2 -0
- data/spec/dummy/app/mailers/.gitkeep +0 -0
- data/spec/dummy/app/models/.gitkeep +0 -0
- data/spec/dummy/app/views/layouts/application.html.erb +14 -0
- data/spec/dummy/config.ru +4 -0
- data/spec/dummy/config/application.rb +51 -0
- data/spec/dummy/config/boot.rb +10 -0
- data/spec/dummy/config/database.yml +17 -0
- data/spec/dummy/config/environment.rb +5 -0
- data/spec/dummy/config/environments/development.rb +32 -0
- data/spec/dummy/config/environments/production.rb +60 -0
- data/spec/dummy/config/environments/test.rb +41 -0
- data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/spec/dummy/config/initializers/inflections.rb +10 -0
- data/spec/dummy/config/initializers/jackpot.rb +13 -0
- data/spec/dummy/config/initializers/mime_types.rb +5 -0
- data/spec/dummy/config/initializers/secret_token.rb +7 -0
- data/spec/dummy/config/initializers/session_store.rb +8 -0
- data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
- data/spec/dummy/config/locales/en.yml +5 -0
- data/spec/dummy/config/routes.rb +3 -0
- data/spec/dummy/db/schema.rb +68 -0
- data/spec/dummy/lib/assets/.gitkeep +0 -0
- data/spec/dummy/public/404.html +26 -0
- data/spec/dummy/public/422.html +26 -0
- data/spec/dummy/public/500.html +26 -0
- data/spec/dummy/public/favicon.ico +0 -0
- data/spec/dummy/public/index.html +5 -0
- data/spec/dummy/public/payment.html +36 -0
- data/spec/dummy/script/rails +6 -0
- 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
- data/spec/fixtures/vcr/Jackpot_Customer/_update_credit_card_number/when_card_is_valid/.yml +34 -0
- 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
- 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
- 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
- data/spec/fixtures/vcr/Jackpot_Customer/_update_credit_card_number/when_card_is_valid/when_persisting/should_persist_the_card_information.yml +34 -0
- 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
- data/spec/fixtures/vcr/Jackpot_Payment/_create/with_valid_token_information/creates_a_new_payment.yml +96 -0
- data/spec/fixtures/vcr/Jackpot_Payment/_create/with_valid_token_information/does_not_persist_credit_card_token_information.yml +96 -0
- data/spec/fixtures/vcr/Jackpot_Payment/_create/with_valid_token_information/records_the_payment_transaction_id_for_future_reference.yml +96 -0
- data/spec/fixtures/vcr/Jackpot_Payment/_create/with_valid_token_information/records_this_payment_information.yml +96 -0
- data/spec/fixtures/vcr/Jackpot_Payment/_customer_name/returns_its_customer_email.yml +96 -0
- data/spec/fixtures/vcr/jackpot/customer/updatecard.yml +34 -0
- data/spec/fixtures/vcr/jackpot/customer_expiration_date.yml +34 -0
- data/spec/fixtures/vcr/jackpot/receiving_payments.yml +96 -0
- data/spec/helpers/jackpot/customers_helper_spec.rb +16 -0
- data/spec/helpers/jackpot/subscriptions_helper_spec.rb +4 -0
- data/spec/lib/cron_spec.rb +39 -0
- data/spec/lib/factory_spec.rb +40 -0
- data/spec/models/jackpot/card_spec.rb +23 -0
- data/spec/models/jackpot/customer_spec.rb +140 -0
- data/spec/models/jackpot/gateway_spec.rb +22 -0
- data/spec/models/jackpot/payment_spec.rb +74 -0
- data/spec/models/jackpot/subscription_spec.rb +19 -0
- data/spec/requests/jackpot/jackpot_assign_subscription_to_customer_spec.rb +39 -0
- data/spec/requests/jackpot/jackpot_create_customer_spec.rb +73 -0
- data/spec/requests/jackpot/jackpot_create_subscriptions_spec.rb +27 -0
- data/spec/requests/jackpot/jackpot_receive_payments_spec.rb +34 -0
- data/spec/spec_helper.rb +41 -0
- data/spec/support/active_merchant.rb +1 -0
- data/spec/support/capybara.rb +6 -0
- data/spec/support/devise.rb +21 -0
- data/spec/support/factories/jackpot_customers.rb +36 -0
- data/spec/support/factories/jackpot_payments.rb +7 -0
- data/spec/support/factories/jackpot_subscriptions.rb +9 -0
- data/spec/support/factories/jackpot_users.rb +9 -0
- data/spec/support/helpers.rb +16 -0
- data/spec/support/routes.rb +3 -0
- data/spec/support/vcr.rb +10 -0
- data/vendor/assets/images/twitter/bootstrap/glyphicons-halflings-white.png +0 -0
- data/vendor/assets/images/twitter/bootstrap/glyphicons-halflings.png +0 -0
- data/vendor/assets/javascripts/twitter/bootstrap.js +12 -0
- data/vendor/assets/javascripts/twitter/bootstrap/bootstrap-alert.js +91 -0
- data/vendor/assets/javascripts/twitter/bootstrap/bootstrap-button.js +98 -0
- data/vendor/assets/javascripts/twitter/bootstrap/bootstrap-carousel.js +154 -0
- data/vendor/assets/javascripts/twitter/bootstrap/bootstrap-collapse.js +136 -0
- data/vendor/assets/javascripts/twitter/bootstrap/bootstrap-dropdown.js +92 -0
- data/vendor/assets/javascripts/twitter/bootstrap/bootstrap-modal.js +209 -0
- data/vendor/assets/javascripts/twitter/bootstrap/bootstrap-popover.js +95 -0
- data/vendor/assets/javascripts/twitter/bootstrap/bootstrap-scrollspy.js +125 -0
- data/vendor/assets/javascripts/twitter/bootstrap/bootstrap-tab.js +130 -0
- data/vendor/assets/javascripts/twitter/bootstrap/bootstrap-tooltip.js +270 -0
- data/vendor/assets/javascripts/twitter/bootstrap/bootstrap-transition.js +51 -0
- data/vendor/assets/javascripts/twitter/bootstrap/bootstrap-typeahead.js +271 -0
- data/vendor/assets/stylesheets/twitter/bootstrap/bootstrap-responsive.css +567 -0
- data/vendor/assets/stylesheets/twitter/bootstrap/bootstrap.css.erb +3366 -0
- 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,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
|