payola-payments 1.1.4 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (87) hide show
  1. checksums.yaml +5 -13
  2. data/app/assets/javascripts/payola/form.js +1 -0
  3. data/app/assets/javascripts/payola/subscription_form.js +74 -0
  4. data/app/controllers/payola/application_controller.rb +1 -2
  5. data/app/controllers/payola/subscriptions_controller.rb +94 -0
  6. data/app/models/concerns/payola/plan.rb +50 -0
  7. data/app/models/payola/subscription.rb +161 -0
  8. data/app/services/payola/cancel_subscription.rb +12 -0
  9. data/app/services/payola/change_subscription_plan.rb +29 -0
  10. data/app/services/payola/create_plan.rb +17 -0
  11. data/app/services/payola/create_subscription.rb +20 -0
  12. data/app/services/payola/invoice_failed.rb +42 -0
  13. data/app/services/payola/invoice_paid.rb +43 -0
  14. data/app/services/payola/process_subscription.rb +7 -0
  15. data/app/services/payola/start_subscription.rb +41 -0
  16. data/app/services/payola/sync_subscription.rb +11 -0
  17. data/app/services/payola/update_card.rb +27 -0
  18. data/app/services/payola/update_subscription.rb +11 -0
  19. data/app/views/payola/subscriptions/_cancel.html.erb +10 -0
  20. data/app/views/payola/subscriptions/_change_plan.html.erb +10 -0
  21. data/config/routes.rb +7 -0
  22. data/db/migrate/20141105043439_create_payola_subscriptions.rb +31 -0
  23. data/db/migrate/20141106034610_add_currency_to_payola_subscriptions.rb +6 -0
  24. data/db/migrate/20141107025420_add_guid_to_payola_subscriptions.rb +6 -0
  25. data/db/migrate/20141109203101_add_stripe_status_to_payola_subscription.rb +5 -0
  26. data/db/migrate/20141112024805_add_affiliate_id_to_payola_subscriptions.rb +5 -0
  27. data/db/migrate/20141114032013_add_coupon_code_to_payola_subscriptions.rb +5 -0
  28. data/db/migrate/20141114154223_add_signed_custom_fields_to_payola_subscription.rb +5 -0
  29. data/db/migrate/20141114163841_add_addresses_to_payola_subscription.rb +6 -0
  30. data/lib/payola.rb +11 -0
  31. data/lib/payola/engine.rb +10 -2
  32. data/lib/payola/version.rb +1 -1
  33. data/spec/concerns/plan_spec.rb +43 -0
  34. data/spec/controllers/payola/subscriptions_controller_spec.rb +148 -0
  35. data/spec/dummy/app/controllers/application_controller.rb +4 -0
  36. data/spec/dummy/app/controllers/home_controller.rb +6 -0
  37. data/spec/dummy/app/controllers/subscribe_controller.rb +11 -0
  38. data/spec/dummy/app/models/subscription_plan.rb +3 -0
  39. data/spec/dummy/app/views/home/index.html.erb +7 -0
  40. data/spec/dummy/app/views/subscribe/index.html.erb +21 -0
  41. data/spec/dummy/app/views/subscribe/show.html.erb +4 -0
  42. data/spec/dummy/config/initializers/payola.rb +4 -0
  43. data/spec/dummy/config/routes.rb +4 -0
  44. data/spec/dummy/db/development.sqlite3 +0 -0
  45. data/spec/dummy/db/migrate/20141105010234_create_subscription_plans.rb +14 -0
  46. data/spec/dummy/db/schema.rb +51 -1
  47. data/spec/dummy/db/test.sqlite3 +0 -0
  48. data/spec/dummy/log/development.log +275 -0
  49. data/spec/dummy/log/test.log +109420 -0
  50. data/spec/dummy/tmp/cache/assets/development/sprockets/0e585aeb88c1555ae8f5292f7c7a9068 +0 -0
  51. data/spec/dummy/tmp/cache/assets/development/sprockets/13fe41fee1fe35b49d145bcc06610705 +0 -0
  52. data/spec/dummy/tmp/cache/assets/development/sprockets/1b54952339cbc96811097cee5f8923b4 +0 -0
  53. data/spec/dummy/tmp/cache/assets/development/sprockets/2f5173deea6c795b8fdde723bb4b63af +0 -0
  54. data/spec/dummy/tmp/cache/assets/development/sprockets/357970feca3ac29060c1e3861e2c0953 +0 -0
  55. data/spec/dummy/tmp/cache/assets/development/sprockets/5afa4bc970e0bc781b3500c696ba25ff +0 -0
  56. data/spec/dummy/tmp/cache/assets/development/sprockets/664efeb51d1b486dcfc30d142db56f3c +0 -0
  57. data/spec/dummy/tmp/cache/assets/development/sprockets/68a3bbdc64a0729b5896fa1e33fce4b1 +0 -0
  58. data/spec/dummy/tmp/cache/assets/development/sprockets/96b1ccdc193a02b2bbea195310262fa5 +0 -0
  59. data/spec/dummy/tmp/cache/assets/development/sprockets/aea159adbc0944b120d91d5b578612ba +0 -0
  60. data/spec/dummy/tmp/cache/assets/development/sprockets/b20dab973e971c61bc7e334a38453ae0 +0 -0
  61. data/spec/dummy/tmp/cache/assets/development/sprockets/b83da90cb58011313e13a97a4a41cb6e +0 -0
  62. data/spec/dummy/tmp/cache/assets/development/sprockets/c0b954b40f2881a6d286061bc069643e +0 -0
  63. data/spec/dummy/tmp/cache/assets/development/sprockets/c5b3877d49b39932a7557611cefca9a6 +0 -0
  64. data/spec/dummy/tmp/cache/assets/development/sprockets/ca491e325ff6948be9292f701aa4ce64 +0 -0
  65. data/spec/dummy/tmp/cache/assets/development/sprockets/cffd775d018f68ce5dba1ee0d951a994 +0 -0
  66. data/spec/dummy/tmp/cache/assets/development/sprockets/d3f4b67cc032016dfeebc71f2148b9dc +0 -0
  67. data/spec/dummy/tmp/cache/assets/development/sprockets/d771ace226fc8215a3572e0aa35bb0d6 +0 -0
  68. data/spec/dummy/tmp/cache/assets/development/sprockets/d9856638a3c7b9cfd9d1b884e3b33982 +0 -0
  69. data/spec/dummy/tmp/cache/assets/development/sprockets/ddba6e841f28d3005e828fbfffd18b74 +0 -0
  70. data/spec/dummy/tmp/cache/assets/development/sprockets/df935e399019055729aa968bd7062096 +0 -0
  71. data/spec/dummy/tmp/cache/assets/development/sprockets/ef82c31948061751bb026663b54484e1 +0 -0
  72. data/spec/dummy/tmp/cache/assets/development/sprockets/f0b5d4bea0c6cdd1904e1e9a0a45532f +0 -0
  73. data/spec/dummy/tmp/cache/assets/development/sprockets/f7cbd26ba1d28d48de824f0e94586655 +0 -0
  74. data/spec/factories/payola_subscriptions.rb +25 -0
  75. data/spec/factories/subscription_plan.rb +9 -0
  76. data/spec/models/payola/subscription_spec.rb +50 -0
  77. data/spec/services/payola/cancel_subscription_spec.rb +29 -0
  78. data/spec/services/payola/change_subscription_plan_spec.rb +31 -0
  79. data/spec/services/payola/charge_card_spec.rb +9 -5
  80. data/spec/services/payola/create_plan_spec.rb +24 -0
  81. data/spec/services/payola/create_subscription_spec.rb +65 -0
  82. data/spec/services/payola/invoice_failed_spec.rb +29 -0
  83. data/spec/services/payola/invoice_paid_spec.rb +49 -0
  84. data/spec/services/payola/start_subscription_spec.rb +36 -0
  85. data/spec/services/payola/sync_subscription_spec.rb +14 -0
  86. data/spec/services/payola/update_card_spec.rb +26 -0
  87. metadata +95 -30
@@ -0,0 +1,25 @@
1
+ # Read about factories at https://github.com/thoughtbot/factory_girl
2
+
3
+ FactoryGirl.define do
4
+ factory :subscription, :class => 'Payola::Subscription' do
5
+ plan_type "SubscriptionPlan"
6
+ plan_id 1
7
+ start "2014-11-04 22:34:39"
8
+ status "MyString"
9
+ owner_type "Owner"
10
+ owner_id 1
11
+ stripe_customer_id "MyString"
12
+ cancel_at_period_end false
13
+ current_period_start "2014-11-04 22:34:39"
14
+ current_period_end "2014-11-04 22:34:39"
15
+ ended_at "2014-11-04 22:34:39"
16
+ trial_start "2014-11-04 22:34:39"
17
+ trial_end "2014-11-04 22:34:39"
18
+ canceled_at "2014-11-04 22:34:39"
19
+ email "jeremy@octolabs.com"
20
+ stripe_token "yyz123"
21
+ currency 'usd'
22
+ quantity 1
23
+ stripe_id 'sub_123456'
24
+ end
25
+ end
@@ -0,0 +1,9 @@
1
+ FactoryGirl.define do
2
+ factory :subscription_plan do
3
+ sequence(:name) { |n| "Foo #{n}" }
4
+ sequence(:stripe_id) { |n| "foo-#{n}" }
5
+ amount 100
6
+ interval "month"
7
+ interval_count 1
8
+ end
9
+ end
@@ -0,0 +1,50 @@
1
+ require 'spec_helper'
2
+
3
+ module Payola
4
+ describe Subscription do
5
+
6
+ describe "validations" do
7
+ it "should validate" do
8
+ subscription = build(:subscription)
9
+ expect(subscription.valid?).to be true
10
+ end
11
+
12
+ it "should validate plan" do
13
+ subscription = build(:subscription, plan: nil)
14
+ expect(subscription.valid?).to be false
15
+ end
16
+
17
+ it "should validate lack of email" do
18
+ sale = build(:sale, email: nil)
19
+ expect(sale.valid?).to be false
20
+ end
21
+
22
+ it "should validate stripe_token" do
23
+ sale = build(:sale, stripe_token: nil)
24
+ expect(sale.valid?).to be false
25
+ end
26
+
27
+ end
28
+
29
+ describe "#sync_with!" do
30
+ it "should sync timestamps" do
31
+ plan = create(:subscription_plan)
32
+ subscription = build(:subscription, plan: plan)
33
+ stripe_sub = Stripe::Customer.create.subscriptions.create(plan: plan.stripe_id, card: StripeMock.generate_card_token(last4: '1234', exp_year: Time.now.year + 1))
34
+ old_start = subscription.current_period_start
35
+ old_end = subscription.current_period_end
36
+ trial_start = subscription.trial_start
37
+ trial_end = subscription.trial_end
38
+
39
+ subscription.sync_with!(stripe_sub)
40
+
41
+ subscription.reload
42
+
43
+ expect(subscription.current_period_start).to eq Time.at(stripe_sub.current_period_start)
44
+ expect(subscription.current_period_start).to_not eq old_start
45
+ expect(subscription.current_period_end).to eq Time.at(stripe_sub.current_period_end)
46
+ expect(subscription.current_period_end).to_not eq old_end
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,29 @@
1
+ require 'spec_helper'
2
+
3
+ module Payola
4
+ describe CancelSubscription do
5
+ let(:stripe_helper) { StripeMock.create_test_helper }
6
+ let(:token){ StripeMock.generate_card_token({}) }
7
+ describe "#call" do
8
+ before :each do
9
+ plan = create(:subscription_plan)
10
+ @subscription = create(:subscription, plan: plan, stripe_token: token)
11
+ @subscription.process!
12
+ end
13
+ it "should cancel a subscription" do
14
+ CancelSubscription.call(@subscription)
15
+ expect(@subscription.reload.state).to eq 'canceled'
16
+ end
17
+ it "should not change the state if an error occurs" do
18
+ custom_error = StandardError.new("Customer not found")
19
+ StripeMock.prepare_error(custom_error, :get_customer)
20
+ expect { CancelSubscription.call(@subscription) }.to raise_error
21
+
22
+ expect(@subscription.reload.state).to eq 'active'
23
+ end
24
+ end
25
+ end
26
+ end
27
+
28
+
29
+
@@ -0,0 +1,31 @@
1
+ require 'spec_helper'
2
+
3
+ module Payola
4
+ describe ChangeSubscriptionPlan do
5
+ let(:stripe_helper) { StripeMock.create_test_helper }
6
+
7
+ describe "#call" do
8
+ before do
9
+ @plan1 = create(:subscription_plan)
10
+ @plan2 = create(:subscription_plan)
11
+
12
+ token = StripeMock.generate_card_token({})
13
+ @subscription = create(:subscription, plan: @plan1, stripe_token: token)
14
+ StartSubscription.call(@subscription)
15
+ Payola::ChangeSubscriptionPlan.call(@subscription, @plan2)
16
+ end
17
+
18
+ it "should change the plan on the stripe subscription" do
19
+ customer = Stripe::Customer.retrieve(@subscription.stripe_customer_id)
20
+ sub = customer.subscriptions.retrieve(@subscription.stripe_id)
21
+
22
+ expect(sub.plan.id).to eq @plan2.stripe_id
23
+ end
24
+
25
+ it "should change the plan on the payola subscription" do
26
+ Payola::ChangeSubscriptionPlan.call(@subscription, @plan2)
27
+ expect(@subscription.reload.plan).to eq @plan2
28
+ end
29
+ end
30
+ end
31
+ end
@@ -2,29 +2,34 @@ require 'spec_helper'
2
2
 
3
3
  module Payola
4
4
  describe ChargeCard do
5
+ let(:stripe_helper) { StripeMock.create_test_helper }
5
6
  describe "#call" do
6
7
  it "should create a customer" do
7
- sale = create(:sale, state: 'processing')
8
+ sale = create(:sale, state: 'processing', stripe_token: stripe_helper.generate_card_token)
8
9
  ChargeCard.call(sale)
9
10
  expect(sale.reload.stripe_customer_id).to_not be_nil
10
11
  end
12
+
11
13
  it "should create a charge" do
12
- sale = create(:sale, state: 'processing')
14
+ sale = create(:sale, state: 'processing', stripe_token: stripe_helper.generate_card_token)
13
15
  ChargeCard.call(sale)
14
16
  expect(sale.reload.stripe_id).to_not be_nil
15
17
  expect(sale.reload.card_last4).to_not be_nil
16
18
  expect(sale.reload.card_expiration).to_not be_nil
17
19
  expect(sale.reload.card_type).to_not be_nil
18
20
  end
21
+
19
22
  it "should get the fee from the balance transaction" do
20
- sale = create(:sale, state: 'processing')
23
+ sale = create(:sale, state: 'processing', stripe_token: stripe_helper.generate_card_token)
21
24
  ChargeCard.call(sale)
22
25
  expect(sale.reload.fee_amount).to_not be_nil
23
26
  end
27
+
24
28
  describe "on error" do
25
29
  it "should update the error attribute" do
30
+
26
31
  StripeMock.prepare_card_error(:card_declined)
27
- sale = create(:sale, state: 'processing')
32
+ sale = create(:sale, state: 'processing', stripe_token: stripe_helper.generate_card_token)
28
33
  ChargeCard.call(sale)
29
34
  expect(sale.reload.error).to_not be_nil
30
35
  expect(sale.errored?).to be true
@@ -34,4 +39,3 @@ module Payola
34
39
  end
35
40
  end
36
41
 
37
-
@@ -0,0 +1,24 @@
1
+ require 'spec_helper'
2
+
3
+ module Payola
4
+ describe CreatePlan do
5
+ before do
6
+ @subscription_plan = create(:subscription_plan)
7
+ end
8
+
9
+ describe "#call" do
10
+ it "should create a plan at Stripe" do
11
+ plan = Stripe::Plan.retrieve(@subscription_plan.stripe_id)
12
+
13
+ expect(plan.name).to eq @subscription_plan.name
14
+ expect(plan.amount).to eq @subscription_plan.amount
15
+ expect(plan.id).to eq @subscription_plan.stripe_id
16
+ expect(plan.interval).to eq @subscription_plan.interval
17
+ expect(plan.interval_count).to eq @subscription_plan.interval_count
18
+ expect(plan.currency).to eq 'usd'
19
+ expect(plan.trial_period_days).to eq @subscription_plan.trial_period_days
20
+ end
21
+ end
22
+
23
+ end
24
+ end
@@ -0,0 +1,65 @@
1
+ require 'spec_helper'
2
+
3
+ module Payola
4
+ describe CreateSubscription do
5
+ before do
6
+ @plan = create(:subscription_plan)
7
+ end
8
+
9
+ describe "#call" do
10
+ it "should create a sale" do
11
+ sale = CreateSubscription.call(
12
+ stripeEmail: 'pete@bugsplat.info',
13
+ stripeToken: 'test_tok',
14
+ plan: @plan
15
+ )
16
+
17
+ expect(sale.email).to eq 'pete@bugsplat.info'
18
+ expect(sale.stripe_token).to eq 'test_tok'
19
+ expect(sale.plan_id).to eq @plan.id
20
+ expect(sale.plan).to eq @plan
21
+ expect(sale.plan_type).to eq 'SubscriptionPlan'
22
+ expect(sale.currency).to eq 'usd'
23
+ end
24
+
25
+ it "should include the affiliate if given" do
26
+ affiliate = create(:payola_affiliate)
27
+ sale = CreateSubscription.call(
28
+ email: 'pete@bugsplat.info',
29
+ stripeToken: 'test_tok',
30
+ plan: @plan,
31
+ affiliate: affiliate
32
+ )
33
+
34
+ expect(sale.affiliate).to eq affiliate
35
+ end
36
+
37
+ #describe "with coupon" do
38
+ #it "should include the coupon" do
39
+ #coupon = create(:payola_coupon)
40
+
41
+ #sale = CreateSubscription.call(
42
+ #email: 'pete@bugsplat.info',
43
+ #stripeToken: 'test_tok',
44
+ #product: @plan,
45
+ #coupon: coupon
46
+ #)
47
+
48
+ #expect(sale.coupon).to eq coupon
49
+ #end
50
+ #it "should set the price correctly" do
51
+ #coupon = create(:payola_coupon)
52
+
53
+ #sale = CreateSubscription.call(
54
+ #email: 'pete@bugsplat.info',
55
+ #stripeToken: 'test_tok',
56
+ #product: @plan,
57
+ #coupon: coupon
58
+ #)
59
+
60
+ #expect(sale.amount).to eq 99
61
+ #end
62
+ #end
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,29 @@
1
+ require 'spec_helper'
2
+
3
+ module Payola
4
+ describe InvoiceFailed do
5
+ let(:stripe_helper) { StripeMock.create_test_helper }
6
+ it "should create a failed sale" do
7
+ plan = create(:subscription_plan)
8
+
9
+ customer = Stripe::Customer.create(
10
+ email: 'foo',
11
+ card: stripe_helper.generate_card_token,
12
+ plan: plan.stripe_id
13
+ )
14
+
15
+ sub = create(:subscription, plan: plan, stripe_customer_id: customer.id, stripe_id: customer.subscriptions.first.id)
16
+
17
+ charge = Stripe::Charge.create(failure_message: 'Failed! OMG!')
18
+ event = StripeMock.mock_webhook_event('invoice.payment_failed', subscription: sub.stripe_id, charge: charge.id)
19
+
20
+ count = Payola::Sale.count
21
+ sale = Payola::InvoiceFailed.call(event)
22
+
23
+ expect(Payola::Sale.count).to eq count + 1
24
+
25
+ expect(sale.errored?).to be true
26
+ expect(sale.error).to eq 'Failed! OMG!'
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,49 @@
1
+ require 'spec_helper'
2
+
3
+ module Payola
4
+ describe InvoicePaid do
5
+ let(:stripe_helper) { StripeMock.create_test_helper }
6
+ it "should do nothing if the invoice has no charge" do
7
+ # create a Payola::Subscription
8
+ plan = create(:subscription_plan)
9
+
10
+ customer = Stripe::Customer.create(
11
+ email: 'foo',
12
+ card: stripe_helper.generate_card_token,
13
+ plan: plan.stripe_id
14
+ )
15
+
16
+ sub = create(:subscription, plan: plan, stripe_customer_id: customer.id, stripe_id: customer.subscriptions.first.id)
17
+
18
+ event = StripeMock.mock_webhook_event('invoice.payment_succeeded', subscription: sub.stripe_id, charge: nil)
19
+
20
+ count = Payola::Sale.count
21
+
22
+ Payola::InvoicePaid.call(event)
23
+
24
+ expect(Payola::Sale.count).to eq count
25
+ end
26
+
27
+ it "should create a sale" do
28
+ plan = create(:subscription_plan)
29
+ customer = Stripe::Customer.create(
30
+ email: 'foo',
31
+ card: stripe_helper.generate_card_token,
32
+ plan: plan.stripe_id
33
+ )
34
+
35
+ sub = create(:subscription, plan: plan, stripe_customer_id: customer.id, stripe_id: customer.subscriptions.first.id)
36
+
37
+ charge = Stripe::Charge.create
38
+ event = StripeMock.mock_webhook_event('invoice.payment_succeeded', subscription: sub.stripe_id, charge: charge.id)
39
+
40
+ count = Payola::Sale.count
41
+
42
+ sale = Payola::InvoicePaid.call(event)
43
+
44
+ expect(Payola::Sale.count).to eq count + 1
45
+
46
+ expect(sale.finished?).to be true
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,36 @@
1
+ require 'spec_helper'
2
+
3
+ module Payola
4
+ describe StartSubscription do
5
+ let(:stripe_helper) { StripeMock.create_test_helper }
6
+ let(:token){ StripeMock.generate_card_token({}) }
7
+ describe "#call" do
8
+ it "should create a customer" do
9
+ plan = create(:subscription_plan)
10
+ subscription = create(:subscription, state: 'processing', plan: plan, stripe_token: token)
11
+ StartSubscription.call(subscription)
12
+ expect(subscription.reload.stripe_customer_id).to_not be_nil
13
+ end
14
+ it "should capture credit card info" do
15
+ plan = create(:subscription_plan)
16
+ subscription = create(:subscription, state: 'processing', plan: plan, stripe_token: token)
17
+ StartSubscription.call(subscription)
18
+ expect(subscription.reload.stripe_id).to_not be_nil
19
+ expect(subscription.reload.card_last4).to_not be_nil
20
+ expect(subscription.reload.card_expiration).to_not be_nil
21
+ expect(subscription.reload.card_type).to_not be_nil
22
+ end
23
+ describe "on error" do
24
+ it "should update the error attribute" do
25
+ StripeMock.prepare_card_error(:card_declined, :new_customer)
26
+ plan = create(:subscription_plan)
27
+ subscription = create(:subscription, state: 'processing', plan: plan, stripe_token: token)
28
+ StartSubscription.call(subscription)
29
+ expect(subscription.reload.error).to_not be_nil
30
+ expect(subscription.errored?).to be true
31
+ end
32
+ end
33
+
34
+ end
35
+ end
36
+ end