payola-payments 1.2.0 → 1.2.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (44) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/javascripts/payola/checkout_button.js +9 -9
  3. data/app/assets/javascripts/payola/form.js +6 -6
  4. data/app/assets/javascripts/payola/subscription_form.js +6 -6
  5. data/app/controllers/concerns/payola/affiliate_behavior.rb +17 -0
  6. data/app/controllers/concerns/payola/async_behavior.rb +36 -0
  7. data/app/controllers/payola/subscriptions_controller.rb +31 -46
  8. data/app/controllers/payola/transactions_controller.rb +16 -32
  9. data/app/mailers/payola/admin_mailer.rb +7 -15
  10. data/app/mailers/payola/receipt_mailer.rb +2 -0
  11. data/app/models/concerns/payola/guid_behavior.rb +20 -0
  12. data/app/models/concerns/payola/plan.rb +0 -1
  13. data/app/models/payola/sale.rb +6 -12
  14. data/app/models/payola/subscription.rb +9 -12
  15. data/app/services/payola/charge_card.rb +42 -33
  16. data/app/services/payola/create_plan.rb +2 -2
  17. data/app/services/payola/invoice_behavior.rb +55 -0
  18. data/app/services/payola/invoice_failed.rb +4 -29
  19. data/app/services/payola/invoice_paid.rb +4 -31
  20. data/lib/payola.rb +13 -11
  21. data/lib/payola/version.rb +1 -1
  22. data/spec/concerns/plan_spec.rb +0 -5
  23. data/spec/controllers/payola/subscriptions_controller_spec.rb +10 -1
  24. data/spec/controllers/payola/transactions_controller_spec.rb +10 -1
  25. data/spec/dummy/app/models/subscription_plan_without_interval_count.rb +3 -0
  26. data/spec/dummy/config/environments/test.rb +2 -0
  27. data/spec/dummy/db/development.sqlite3 +0 -0
  28. data/spec/dummy/db/migrate/20141120170744_create_subscription_plan_without_interval_counts.rb +12 -0
  29. data/spec/dummy/db/schema.rb +10 -1
  30. data/spec/dummy/db/test.sqlite3 +0 -0
  31. data/spec/dummy/log/development.log +222 -0
  32. data/spec/dummy/log/test.log +15830 -141203
  33. data/spec/factories/subscription_plan.rb +7 -0
  34. data/spec/mailers/payola/admin_mailer_spec.rb +35 -0
  35. data/spec/mailers/payola/receipt_mailer_spec.rb +52 -0
  36. data/spec/models/payola/subscription_spec.rb +21 -0
  37. data/spec/payola_spec.rb +6 -2
  38. data/spec/services/payola/create_plan_spec.rb +9 -0
  39. data/spec/services/payola/process_sale_spec.rb +15 -0
  40. data/spec/services/payola/process_subscription_spec.rb +15 -0
  41. data/spec/services/payola/send_mail_spec.rb +25 -0
  42. data/spec/spec_helper.rb +13 -0
  43. data/spec/worker_spec.rb +55 -0
  44. metadata +40 -8
@@ -7,7 +7,6 @@ module Payola
7
7
  included do
8
8
  validates_presence_of :amount
9
9
  validates_presence_of :interval
10
- validates_presence_of :interval_count
11
10
  validates_presence_of :stripe_id
12
11
  validates_presence_of :name
13
12
 
@@ -2,6 +2,8 @@ require 'aasm'
2
2
 
3
3
  module Payola
4
4
  class Sale < ActiveRecord::Base
5
+ include Payola::GuidBehavior
6
+
5
7
  has_paper_trail if respond_to? :has_paper_trail
6
8
 
7
9
  validates_presence_of :email
@@ -10,10 +12,6 @@ module Payola
10
12
  validates_presence_of :stripe_token
11
13
  validates_presence_of :currency
12
14
 
13
- validates_uniqueness_of :guid
14
-
15
- before_save :populate_guid
16
-
17
15
  belongs_to :product, polymorphic: true
18
16
  belongs_to :owner, polymorphic: true
19
17
  belongs_to :coupon
@@ -74,6 +72,10 @@ module Payola
74
72
  end
75
73
  end
76
74
 
75
+ def redirector
76
+ product
77
+ end
78
+
77
79
  private
78
80
 
79
81
  def charge_card
@@ -107,13 +109,5 @@ module Payola
107
109
  end
108
110
  end
109
111
 
110
- def populate_guid
111
- if new_record?
112
- while !valid? || self.guid.nil?
113
- self.guid = SecureRandom.random_number(1_000_000_000).to_s(32)
114
- end
115
- end
116
- end
117
-
118
112
  end
119
113
  end
@@ -2,6 +2,9 @@ require 'aasm'
2
2
 
3
3
  module Payola
4
4
  class Subscription < ActiveRecord::Base
5
+ include Payola::GuidBehavior
6
+
7
+ has_paper_trail if respond_to? :has_paper_trail
5
8
 
6
9
  validates_presence_of :email
7
10
  validates_presence_of :plan_id
@@ -9,10 +12,6 @@ module Payola
9
12
  validates_presence_of :stripe_token
10
13
  validates_presence_of :currency
11
14
 
12
- validates_uniqueness_of :guid
13
-
14
- before_save :populate_guid
15
-
16
15
  belongs_to :plan, polymorphic: true
17
16
  belongs_to :owner, polymorphic: true
18
17
  belongs_to :affiliate
@@ -98,8 +97,10 @@ module Payola
98
97
  self.ended_at = Time.at(stripe_sub.ended_at) if stripe_sub.ended_at
99
98
  self.trial_start = Time.at(stripe_sub.trial_start) if stripe_sub.trial_start
100
99
  self.trial_end = Time.at(stripe_sub.trial_end) if stripe_sub.trial_end
100
+ self.canceled_at = Time.at(stripe_sub.canceled_at) if stripe_sub.canceled_at
101
101
  self.quantity = stripe_sub.quantity
102
102
  self.stripe_status = stripe_sub.status
103
+ self.cancel_at_period_end = stripe_sub.cancel_at_period_end
103
104
 
104
105
  self.save!
105
106
  self
@@ -115,6 +116,10 @@ module Payola
115
116
  Payola.instrument(instrument_key('plan_changed', false), self)
116
117
  end
117
118
 
119
+ def redirector
120
+ plan
121
+ end
122
+
118
123
  private
119
124
 
120
125
  def start_subscription
@@ -149,13 +154,5 @@ module Payola
149
154
  end
150
155
  end
151
156
 
152
- def populate_guid
153
- if new_record?
154
- while !valid? || self.guid.nil?
155
- self.guid = SecureRandom.random_number(1_000_000_000).to_s(32)
156
- end
157
- end
158
- end
159
-
160
157
  end
161
158
  end
@@ -7,40 +7,13 @@ module Payola
7
7
  begin
8
8
  sale.verify_charge!
9
9
 
10
- customer = Stripe::Customer.create({
11
- card: sale.stripe_token,
12
- email: sale.email
13
- }, secret_key)
14
-
15
- charge_attributes = {
16
- amount: sale.amount,
17
- currency: sale.currency,
18
- customer: customer.id,
19
- description: sale.guid,
20
- }.merge(Payola.additional_charge_attributes.call(sale, customer))
21
-
22
- charge = Stripe::Charge.create(charge_attributes, secret_key)
23
-
24
- if charge.respond_to?(:fee)
25
- fee = charge.fee
26
- else
27
- balance = Stripe::BalanceTransaction.retrieve(charge.balance_transaction, secret_key)
28
- fee = balance.fee
29
- end
30
-
31
- sale.update_attributes(
32
- stripe_id: charge.id,
33
- stripe_customer_id: customer.id,
34
- card_last4: charge.card.last4,
35
- card_expiration: Date.new(charge.card.exp_year, charge.card.exp_month, 1),
36
- card_type: charge.card.respond_to?(:brand) ? charge.card.brand : charge.card.type,
37
- fee_amount: fee
38
- )
10
+ customer = create_customer(sale, secret_key)
11
+ charge = create_charge(sale, customer, secret_key)
12
+
13
+ update_sale(sale, customer, charge, secret_key)
14
+
39
15
  sale.finish!
40
- rescue Stripe::StripeError => e
41
- sale.update_attributes(error: e.message)
42
- sale.fail!
43
- rescue RuntimeError => e
16
+ rescue Stripe::StripeError, RuntimeError => e
44
17
  sale.update_attributes(error: e.message)
45
18
  sale.fail!
46
19
  end
@@ -48,5 +21,41 @@ module Payola
48
21
  sale
49
22
  end
50
23
 
24
+ def self.create_customer(sale, secret_key)
25
+ Stripe::Customer.create({
26
+ card: sale.stripe_token,
27
+ email: sale.email
28
+ }, secret_key)
29
+ end
30
+
31
+ def self.create_charge(sale, customer, secret_key)
32
+ charge_attributes = {
33
+ amount: sale.amount,
34
+ currency: sale.currency,
35
+ customer: customer.id,
36
+ description: sale.guid,
37
+ }.merge(Payola.additional_charge_attributes.call(sale, customer))
38
+
39
+ Stripe::Charge.create(charge_attributes, secret_key)
40
+ end
41
+
42
+ def self.update_sale(sale, customer, charge, secret_key)
43
+ if charge.respond_to?(:fee)
44
+ fee = charge.fee
45
+ else
46
+ balance = Stripe::BalanceTransaction.retrieve(charge.balance_transaction, secret_key)
47
+ fee = balance.fee
48
+ end
49
+
50
+ sale.update_attributes(
51
+ stripe_id: charge.id,
52
+ stripe_customer_id: customer.id,
53
+ card_last4: charge.card.last4,
54
+ card_expiration: Date.new(charge.card.exp_year, charge.card.exp_month, 1),
55
+ card_type: charge.card.respond_to?(:brand) ? charge.card.brand : charge.card.type,
56
+ fee_amount: fee
57
+ )
58
+ end
59
+
51
60
  end
52
61
  end
@@ -7,9 +7,9 @@ module Payola
7
7
  id: plan.stripe_id,
8
8
  amount: plan.amount,
9
9
  interval: plan.interval,
10
- interval_count: plan.interval_count,
11
- currency: plan.respond_to?(:currency) ? plan.currency : Payola.default_currency,
12
10
  name: plan.name,
11
+ interval_count: plan.respond_to?(:interval_count) ? plan.interval_count : nil,
12
+ currency: plan.respond_to?(:currency) ? plan.currency : Payola.default_currency,
13
13
  trial_period_days: plan.respond_to?(:trial_period_days) ? plan.trial_period_days : nil
14
14
  }, secret_key)
15
15
  end
@@ -0,0 +1,55 @@
1
+ require 'active_support/concern'
2
+
3
+ module Payola
4
+ module InvoiceBehavior
5
+ extend ActiveSupport::Concern
6
+
7
+ module ClassMethods
8
+ def create_sale_from_event(event)
9
+ invoice = event.data.object
10
+
11
+ return unless invoice.charge
12
+
13
+ subscription = Payola::Subscription.find_by!(stripe_id: invoice.subscription)
14
+ secret_key = Payola.secret_key_for_sale(subscription)
15
+
16
+ stripe_sub = Stripe::Customer.retrieve(subscription.stripe_customer_id, secret_key).subscriptions.retrieve(invoice.subscription, secret_key)
17
+ subscription.sync_with!(stripe_sub)
18
+
19
+ sale = create_sale(subscription, invoice)
20
+
21
+ charge = Stripe::Charge.retrieve(invoice.charge, secret_key)
22
+
23
+ update_sale_with_charge(sale, charge)
24
+
25
+ return sale, charge
26
+ end
27
+
28
+ def create_sale(subscription, invoice)
29
+ Payola::Sale.new do |s|
30
+ s.email = subscription.email
31
+ s.state = 'processing'
32
+ s.owner = subscription
33
+ s.product = subscription.plan
34
+ s.stripe_token = 'invoice'
35
+ s.amount = invoice.total
36
+ s.currency = invoice.currency
37
+ end
38
+ end
39
+
40
+ def update_sale_with_charge(sale, charge)
41
+ sale.stripe_id = charge.id
42
+ sale.card_type = charge.card.respond_to?(:brand) ? charge.card.brand : charge.card.type
43
+ sale.card_last4 = charge.card.last4
44
+
45
+ if charge.respond_to?(:fee)
46
+ sale.fee_amount = charge.fee
47
+ else
48
+ balance = Stripe::BalanceTransaction.retrieve(charge.balance_transaction, secret_key)
49
+ sale.fee_amount = balance.fee
50
+ end
51
+ end
52
+ end
53
+
54
+ end
55
+ end
@@ -1,36 +1,11 @@
1
1
  module Payola
2
2
  class InvoiceFailed
3
- def self.call(event)
4
- invoice = event.data.object
5
-
6
- subscription = Payola::Subscription.find_by!(stripe_id: invoice.subscription)
7
- secret_key = Payola.secret_key_for_sale(subscription)
8
-
9
- stripe_sub = Stripe::Customer.retrieve(subscription.stripe_customer_id, secret_key).subscriptions.retrieve(invoice.subscription, secret_key)
10
- subscription.sync_with!(stripe_sub)
3
+ include Payola::InvoiceBehavior
11
4
 
12
- sale = Payola::Sale.new do |s|
13
- s.email = subscription.email
14
- s.state = 'processing'
15
- s.owner = subscription
16
- s.product = subscription.plan
17
- s.stripe_token = 'invoice'
18
- s.amount = invoice.total
19
- s.currency = invoice.currency
20
- end
21
-
22
- charge = Stripe::Charge.retrieve(invoice.charge, secret_key)
23
-
24
- sale.stripe_id = charge.id
25
- sale.card_type = charge.card.respond_to?(:brand) ? charge.card.brand : charge.card.type
26
- sale.card_last4 = charge.card.last4
5
+ def self.call(event)
6
+ sale, charge = create_sale_from_event(event)
27
7
 
28
- if charge.respond_to?(:fee)
29
- sale.fee_amount = charge.fee
30
- else
31
- balance = Stripe::BalanceTransaction.retrieve(charge.balance_transaction, secret_key)
32
- sale.fee_amount = balance.fee
33
- end
8
+ return unless sale
34
9
 
35
10
  sale.error = charge.failure_message
36
11
  sale.save!
@@ -1,38 +1,11 @@
1
1
  module Payola
2
2
  class InvoicePaid
3
- def self.call(event)
4
- invoice = event.data.object
5
-
6
- return unless invoice.charge
7
-
8
- subscription = Payola::Subscription.find_by!(stripe_id: invoice.subscription)
9
-
10
- secret_key = Payola.secret_key_for_sale(subscription)
11
- stripe_sub = Stripe::Customer.retrieve(subscription.stripe_customer_id, secret_key).subscriptions.retrieve(invoice.subscription, secret_key)
12
- subscription.sync_with!(stripe_sub)
3
+ include Payola::InvoiceBehavior
13
4
 
14
- sale = Payola::Sale.new do |s|
15
- s.email = subscription.email
16
- s.state = 'processing'
17
- s.owner = subscription
18
- s.product = subscription.plan
19
- s.stripe_token = 'invoice'
20
- s.amount = invoice.total
21
- s.currency = invoice.currency
22
- end
23
-
24
- charge = Stripe::Charge.retrieve(invoice.charge, secret_key)
25
-
26
- sale.stripe_id = charge.id
27
- sale.card_type = charge.card.respond_to?(:brand) ? charge.card.brand : charge.card.type
28
- sale.card_last4 = charge.card.last4
5
+ def self.call(event)
6
+ sale, charge = create_sale_from_event(event)
29
7
 
30
- if charge.respond_to?(:fee)
31
- sale.fee_amount = charge.fee
32
- else
33
- balance = Stripe::BalanceTransaction.retrieve(charge.balance_transaction, secret_key)
34
- sale.fee_amount = balance.fee
35
- end
8
+ return unless sale
36
9
 
37
10
  sale.save!
38
11
  sale.finish!
data/lib/payola.rb CHANGED
@@ -4,6 +4,16 @@ require 'stripe_event'
4
4
  require 'jquery-rails'
5
5
 
6
6
  module Payola
7
+
8
+ DEFAULT_EMAILS = {
9
+ receipt: [ 'payola.sale.finished', 'Payola::ReceiptMailer', :receipt ],
10
+ refund: [ 'charge.refunded', 'Payola::ReceiptMailer', :refund ],
11
+ admin_receipt: [ 'payola.sale.finished', 'Payola::AdminMailer', :receipt ],
12
+ admin_dispute: [ 'dispute.created', 'Payola::AdminMailer', :dispute ],
13
+ admin_refund: [ 'payola.sale.refunded', 'Payola::AdminMailer', :refund ],
14
+ admin_failure: [ 'payola.sale.failed', 'Payola::AdminMailer', :failure ],
15
+ }
16
+
7
17
  class << self
8
18
  attr_accessor :publishable_key,
9
19
  :publishable_key_retriever,
@@ -17,6 +27,7 @@ module Payola
17
27
  :charge_verifier,
18
28
  :default_currency,
19
29
  :additional_charge_attributes,
30
+ :guid_generator,
20
31
  :pdf_receipt
21
32
 
22
33
  def configure(&block)
@@ -74,6 +85,7 @@ module Payola
74
85
  self.subscribables = {}
75
86
  self.additional_charge_attributes = lambda { |sale, customer| { } }
76
87
  self.pdf_receipt = false
88
+ self.guid_generator = lambda { SecureRandom.random_number(1_000_000_000).to_s(32) }
77
89
  end
78
90
 
79
91
  def register_sellable(klass)
@@ -85,20 +97,10 @@ module Payola
85
97
  end
86
98
 
87
99
  def send_email_for(*emails)
88
- possible_emails = {
89
- receipt: [ 'payola.sale.finished', Payola::ReceiptMailer, :receipt ],
90
- refund: [ 'charge.refunded', Payola::ReceiptMailer, :refund ],
91
- admin_receipt: [ 'payola.sale.finished', Payola::AdminMailer, :receipt ],
92
- admin_dispute: [ 'dispute.created', Payola::AdminMailer, :dispute ],
93
- admin_refund: [ 'payola.sale.refunded', Payola::AdminMailer, :refund ],
94
- admin_failure: [ 'payola.sale.failed', Payola::AdminMailer, :failure ],
95
- }
96
-
97
100
  emails.each do |email|
98
- spec = possible_emails[email].dup
101
+ spec = DEFAULT_EMAILS[email].dup
99
102
  if spec
100
103
  Payola.subscribe(spec.shift) do |sale|
101
-
102
104
  if sale.is_a?(Stripe::Event)
103
105
  sale = Payola::Sale.find_by!(stripe_id: sale.data.object.id)
104
106
  end
@@ -1,3 +1,3 @@
1
1
  module Payola
2
- VERSION = "1.2.0"
2
+ VERSION = "1.2.1"
3
3
  end
@@ -18,11 +18,6 @@ module Payola
18
18
  expect(subscription_plan.valid?).to be false
19
19
  end
20
20
 
21
- it "should validate interval_count" do
22
- subscription_plan = build(:subscription_plan, interval_count: nil)
23
- expect(subscription_plan.valid?).to be false
24
- end
25
-
26
21
  it "should validate stripe_id" do
27
22
  subscription_plan = build(:subscription_plan, stripe_id: nil)
28
23
  expect(subscription_plan.valid?).to be false
@@ -13,7 +13,16 @@ module Payola
13
13
  subscription.should_receive(:save).and_return(true)
14
14
  subscription.should_receive(:guid).at_least(1).times.and_return(1)
15
15
 
16
- CreateSubscription.should_receive(:call).and_return(subscription)
16
+ CreateSubscription.should_receive(:call).with(
17
+ 'plan_class' => 'subscription_plan',
18
+ 'plan_id' => @plan.id.to_s,
19
+ 'controller' => 'payola/subscriptions',
20
+ 'action' => 'create',
21
+ 'plan' => @plan,
22
+ 'coupon' => nil,
23
+ 'affiliate' => nil
24
+ ).and_return(subscription)
25
+
17
26
  Payola.should_receive(:queue!)
18
27
  post :create, plan_class: @plan.plan_class, plan_id: @plan.id, use_route: :payola
19
28
 
@@ -13,7 +13,16 @@ module Payola
13
13
  sale.should_receive(:save).and_return(true)
14
14
  sale.should_receive(:guid).at_least(1).times.and_return('blah')
15
15
 
16
- CreateSale.should_receive(:call).and_return(sale)
16
+ CreateSale.should_receive(:call).with(
17
+ 'product_class' => 'product',
18
+ 'permalink' => @product.permalink,
19
+ 'controller' => 'payola/transactions',
20
+ 'action' => 'create',
21
+ 'product' => @product,
22
+ 'coupon' => nil,
23
+ 'affiliate' => nil
24
+ ).and_return(sale)
25
+
17
26
  Payola.should_receive(:queue!)
18
27
  post :create, product_class: @product.product_class, permalink: @product.permalink, use_route: :payola
19
28