pay 3.0.16 → 3.0.20

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of pay might be problematic. Click here for more details.

checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 59b2532c5c7b00afccc1f337f22f89264a5638ce228011166f776c77487b2195
4
- data.tar.gz: b67a36b2fded1ee0a28f6a32efe24c9f2d6a34611b20f6c1a4776d9424f42cfd
3
+ metadata.gz: fc336f11aa6bdd63887622dd48fbec5a3f52b440b41a73d63478a0239d4c787a
4
+ data.tar.gz: 31e98a7bbe5a0c9ba92201964aab99b3a3743cc42f15eac275f6032a9f52293f
5
5
  SHA512:
6
- metadata.gz: c9594441627345f0da762497bb91c465aa37c3c54979c43b47620c5361830add4bb7cf84db1d9e3fbd0bdd8b73997ec676e6ca044a8763a8b4f33757a679c965
7
- data.tar.gz: e0e9918358210d2a8a7cc49e0172c45b0a48884b9d517a73cd19addb0e4c60d4301bb9e33c1deacb8f68941e5ea81f4541c1cb1474c981e8a250f316b59063c6
6
+ metadata.gz: 194be2c0276670440ff121b00048eedba5f91f1a85b53be9bd0145f5147f78d14ab739e57ae90590f6a751c5b3f2013e139650201bfe2b19d455b28c40c896dc
7
+ data.tar.gz: 9cc1c6d63c0360ccd54b2ee0143b933b292279016618e7e3130b97c150c64350756d7663682f1235f86d7a4983c971def19a7fef13d8148124040b1fccf39c63
data/README.md CHANGED
@@ -23,11 +23,11 @@ Our supported payment processors are:
23
23
  - Stripe ([SCA Compatible](https://stripe.com/docs/strong-customer-authentication) using API version `2020-08-27`)
24
24
  - Paddle (SCA Compatible & supports PayPal)
25
25
  - Braintree (supports PayPal)
26
- - [Fake Processor](docs/fake_processor.md) (used for generic trials without cards, free subscriptions, testing, etc)
26
+ - [Fake Processor](docs/fake_processor/1_overview.md) (used for generic trials without cards, free subscriptions, testing, etc)
27
27
 
28
28
  Want to add a new payment provider? Contributions are welcome.
29
29
 
30
- > We make our best attempt to standardize the different payment providers. They function differently so keep that in mind if you plan on doing more complex payments. It would be best to stick witha single payment provider in that case so you don't run into discrepancies.
30
+ > We make our best attempt to standardize the different payment providers. They function differently so keep that in mind if you plan on doing more complex payments. It would be best to stick with a single payment provider in that case so you don't run into discrepancies.
31
31
 
32
32
  ## 📚 Docs
33
33
 
@@ -23,11 +23,7 @@ module Pay
23
23
  private
24
24
 
25
25
  def to
26
- if params[:billable].respond_to?(:customer_name)
27
- "#{params[:billable].customer_name} <#{params[:billable].email}>"
28
- else
29
- params[:billable].email
30
- end
26
+ "#{params[:pay_customer].customer_name} <#{params[:pay_customer].email}>"
31
27
  end
32
28
  end
33
29
  end
@@ -70,6 +70,10 @@ module Pay
70
70
  self.trial_ends_at = nil
71
71
  end
72
72
 
73
+ def generic_trial?
74
+ fake_processor? && trial_ends_at?
75
+ end
76
+
73
77
  def on_trial?
74
78
  trial_ends_at? && Time.zone.now < trial_ends_at
75
79
  end
@@ -128,6 +132,12 @@ module Pay
128
132
  processor_subscription(expand: ["latest_invoice.payment_intent"]).latest_invoice.payment_intent
129
133
  end
130
134
 
135
+ def paddle_paused_from
136
+ if (timestamp = super)
137
+ Time.zone.parse(timestamp)
138
+ end
139
+ end
140
+
131
141
  private
132
142
 
133
143
  def cancel_if_active
@@ -10,7 +10,7 @@ Amount: <%= params[:charge].amount_with_currency %><br/>
10
10
  Charged to: <%= params[:charge].charged_to %><br/>
11
11
  Transaction ID: <%= params[:charge].id %><br/>
12
12
  Date: <%= params[:charge].created_at %><br/>
13
- <% if params[:charge].customer.owner.extra_billing_info? %>
13
+ <% if params[:charge].customer.owner.try(:extra_billing_info?) %>
14
14
  <%= params[:charge].customer.owner.extra_billing_info %><br/>
15
15
  <% end %>
16
16
  <br/>
@@ -11,7 +11,7 @@ Amount: <%= params[:charge].amount_refunded_with_currency %><br/>
11
11
  Refunded to: <%= params[:charge].charged_to %><br/>
12
12
  Transaction ID: <%= params[:charge].id %><br/>
13
13
  Date: <%= params[:charge].created_at %><br/>
14
- <% if params[:charge].customer.owner.extra_billing_info? %>
14
+ <% if params[:charge].customer.owner.try(:extra_billing_info?) %>
15
15
  <%= params[:charge].customer.owner.extra_billing_info %><br/>
16
16
  <% end %>
17
17
  <br/>
@@ -12,10 +12,10 @@ module Pay
12
12
  return unless pay_subscription.present?
13
13
 
14
14
  pay_customer = pay_subscription.customer
15
- charge = Pay::Braintree::Billable.new(pay_customer).save_transaction(subscription.transactions.first)
15
+ pay_charge = Pay::Braintree::Billable.new(pay_customer).save_transaction(subscription.transactions.first)
16
16
 
17
- if Pay.send_emails
18
- Pay::UserMailer.with(billable: pay_customer.owner, charge: charge).receipt.deliver_later
17
+ if pay_charge && Pay.send_emails
18
+ Pay::UserMailer.with(pay_customer: pay_customer, charge: pay_charge).receipt.deliver_later
19
19
  end
20
20
  end
21
21
  end
@@ -11,11 +11,11 @@ module Pay
11
11
  pay_subscription = Pay::Subscription.find_by_processor_and_id(:braintree, subscription.id)
12
12
  return unless pay_subscription.present?
13
13
 
14
- # billable = pay_subscription.owner
15
- # charge = Pay::Braintree::Billable.new(billable).save_transaction(subscription.transactions.first)
14
+ # pay_customer = pay_subscription.customer
15
+ # pay_charge = Pay::Braintree::Billable.new(pay_customer).save_transaction(subscription.transactions.first)
16
16
 
17
17
  # if Pay.send_emails
18
- # Pay::UserMailer.with(billable: billable, charge: charge).receipt.deliver_later
18
+ # Pay::UserMailer.with(pay_customer: pay_charge.customer, charge: pay_charge).receipt.deliver_later
19
19
  # end
20
20
  end
21
21
  end
@@ -75,9 +75,19 @@ module Pay
75
75
  end
76
76
 
77
77
  def cancel
78
- ends_at = on_trial? ? trial_ends_at : processor_subscription.next_payment[:date]
78
+ ends_at = if on_trial?
79
+ trial_ends_at
80
+ elsif paused?
81
+ paddle_paused_from
82
+ else
83
+ processor_subscription.next_payment&.fetch(:date) || Time.current
84
+ end
85
+
79
86
  PaddlePay::Subscription::User.cancel(processor_id)
80
87
  pay_subscription.update(status: :canceled, ends_at: ends_at)
88
+
89
+ # Remove payment methods since customer cannot be reused after cancelling
90
+ Pay::PaymentMethod.where(customer_id: pay_subscription.customer_id).destroy_all
81
91
  rescue ::PaddlePay::PaddlePayError => e
82
92
  raise Pay::Paddle::Error, e
83
93
  end
@@ -85,6 +95,9 @@ module Pay
85
95
  def cancel_now!
86
96
  PaddlePay::Subscription::User.cancel(processor_id)
87
97
  pay_subscription.update(status: :canceled, ends_at: Time.current)
98
+
99
+ # Remove payment methods since customer cannot be reused after cancelling
100
+ Pay::PaymentMethod.where(customer_id: pay_subscription.customer_id).destroy_all
88
101
  rescue ::PaddlePay::PaddlePayError => e
89
102
  raise Pay::Paddle::Error, e
90
103
  end
@@ -100,7 +113,7 @@ module Pay
100
113
  def pause
101
114
  attributes = {pause: true}
102
115
  response = PaddlePay::Subscription::User.update(processor_id, attributes)
103
- pay_subscription.update(paddle_paused_from: Time.zone.parse(response[:next_payment][:date]))
116
+ pay_subscription.update(paddle_paused_from: Time.zone.parse(response.dig(:next_payment, :date)))
104
117
  rescue ::PaddlePay::PaddlePayError => e
105
118
  raise Pay::Paddle::Error, e
106
119
  end
@@ -13,7 +13,7 @@ module Pay
13
13
  pay_subscription.update!(ends_at: Time.zone.parse(event.cancellation_effective_date)) if pay_subscription.ends_at.blank? && event.cancellation_effective_date.present?
14
14
 
15
15
  # Paddle doesn't allow reusing customers, so we should remove their payment methods
16
- pay_subscription.customer.payment_methods.destroy_all
16
+ Pay::PaymentMethod.where(customer_id: pay_subscription.customer_id).destroy_all
17
17
  end
18
18
  end
19
19
  end
@@ -3,16 +3,13 @@ module Pay
3
3
  module Webhooks
4
4
  class SubscriptionPaymentRefunded
5
5
  def call(event)
6
- charge = Pay::Charge.find_by_processor_and_id(:paddle, event.subscription_payment_id)
7
- return unless charge.present?
6
+ pay_charge = Pay::Charge.find_by_processor_and_id(:paddle, event.subscription_payment_id)
7
+ return unless pay_charge.present?
8
8
 
9
- charge.update(amount_refunded: (event.gross_refund.to_f * 100).to_i)
10
- notify_user(charge.customer.owner, charge)
11
- end
9
+ pay_charge.update(amount_refunded: (event.gross_refund.to_f * 100).to_i)
12
10
 
13
- def notify_user(billable, charge)
14
11
  if Pay.send_emails
15
- Pay::UserMailer.with(billable: billable, charge: charge).refund.deliver_later
12
+ Pay::UserMailer.with(pay_customer: pay_charge.customer, charge: pay_charge).refund.deliver_later
16
13
  end
17
14
  end
18
15
  end
@@ -18,7 +18,7 @@ module Pay
18
18
  return if pay_customer.charges.where(processor_id: event.subscription_payment_id).any?
19
19
 
20
20
  charge = create_charge(pay_customer, event)
21
- notify_user(pay_customer.owner, charge)
21
+ notify_user(charge)
22
22
  end
23
23
 
24
24
  def create_charge(pay_customer, event)
@@ -42,9 +42,9 @@ module Pay
42
42
  charge
43
43
  end
44
44
 
45
- def notify_user(billable, charge)
46
- if Pay.send_emails && charge.respond_to?(:receipt)
47
- Pay::UserMailer.with(billable: billable, charge: charge).receipt.deliver_later
45
+ def notify_user(pay_charge)
46
+ if Pay.send_emails
47
+ Pay::UserMailer.with(pay_customer: pay_charge.customer, charge: pay_charge).receipt.deliver_later
48
48
  end
49
49
  end
50
50
  end
data/lib/pay/receipts.rb CHANGED
@@ -21,7 +21,7 @@ module Pay
21
21
  [I18n.t("pay.receipt.amount"), Pay::Currency.format(amount, currency: currency)],
22
22
  [I18n.t("pay.receipt.charged_to"), charged_to]
23
23
  ]
24
- line_items << [I18n.t("pay.receipt.additional_info"), customer.owner.extra_billing_info] if customer.owner.extra_billing_info?
24
+ line_items << [I18n.t("pay.receipt.additional_info"), customer.owner.extra_billing_info] if customer.owner.try(:extra_billing_info?)
25
25
  line_items << [I18n.t("pay.receipt.refunded"), Pay::Currency.format(amount_refunded, currency: currency)] if refunded?
26
26
 
27
27
  defaults = {
@@ -49,7 +49,7 @@ module Pay
49
49
 
50
50
  def invoice_pdf(**options)
51
51
  bill_to = [customer.owner.name]
52
- bill_to += [customer.owner.extra_billing_info] if customer.owner.extra_billing_info?
52
+ bill_to += [customer.owner.extra_billing_info] if customer.owner.try(:extra_billing_info?)
53
53
  bill_to += [nil, customer.owner.email]
54
54
 
55
55
  total = Pay::Currency.format(amount, currency: currency)
@@ -4,12 +4,9 @@ module Pay
4
4
  class ChargeRefunded
5
5
  def call(event)
6
6
  pay_charge = Pay::Stripe::Charge.sync(event.data.object.id, stripe_account: event.try(:account))
7
- notify_user(pay_charge.customer.owner, pay_charge) if pay_charge
8
- end
9
7
 
10
- def notify_user(billable, charge)
11
- if Pay.send_emails
12
- Pay::UserMailer.with(billable: billable, charge: charge).refund.deliver_later
8
+ if pay_charge && Pay.send_emails
9
+ Pay::UserMailer.with(pay_customer: pay_charge.customer, charge: pay_charge).refund.deliver_later
13
10
  end
14
11
  end
15
12
  end
@@ -4,12 +4,9 @@ module Pay
4
4
  class ChargeSucceeded
5
5
  def call(event)
6
6
  pay_charge = Pay::Stripe::Charge.sync(event.data.object.id, stripe_account: event.try(:account))
7
- notify_user(pay_charge.customer.owner, pay_charge) if pay_charge
8
- end
9
7
 
10
- def notify_user(billable, charge)
11
- if Pay.send_emails && charge.respond_to?(:receipt)
12
- Pay::UserMailer.with(billable: billable, charge: charge).receipt.deliver_later
8
+ if pay_charge && Pay.send_emails
9
+ Pay::UserMailer.with(pay_customer: pay_charge.customer, charge: pay_charge).receipt.deliver_later
13
10
  end
14
11
  end
15
12
  end
@@ -10,14 +10,13 @@ module Pay
10
10
 
11
11
  subscription = Pay::Subscription.find_by_processor_and_id(:stripe, object.subscription)
12
12
  return if subscription.nil?
13
- billable = subscription.customer.owner
14
13
 
15
- notify_user(billable, event.data.object.payment_intent, subscription)
16
- end
17
-
18
- def notify_user(billable, payment_intent_id, subscription)
19
14
  if Pay.send_emails
20
- Pay::UserMailer.with(billable: billable, payment_intent_id: payment_intent_id, subscription: subscription).payment_action_required.deliver_later
15
+ Pay::UserMailer.with(
16
+ pay_customer: subscription.customer,
17
+ payment_intent_id: event.data.object.payment_intent,
18
+ subscription: subscription
19
+ ).payment_action_required.deliver_later
21
20
  end
22
21
  end
23
22
  end
@@ -18,12 +18,12 @@ module Pay
18
18
  interval = price.recurring.interval
19
19
  return unless interval == "year"
20
20
 
21
- notify_user(subscription.customer.owner, subscription, Time.zone.at(event.data.object.next_payment_attempt))
22
- end
23
-
24
- def notify_user(billable, subscription, date)
25
21
  if Pay.send_emails
26
- Pay::UserMailer.with(billable: billable, subscription: subscription, date: date).subscription_renewing.deliver_later
22
+ Pay::UserMailer.with(
23
+ pay_customer: subscription.customer,
24
+ subscription: subscription,
25
+ date: Time.zone.at(event.data.object.next_payment_attempt)
26
+ ).subscription_renewing.deliver_later
27
27
  end
28
28
  end
29
29
  end
data/lib/pay/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Pay
2
- VERSION = "3.0.16"
2
+ VERSION = "3.0.20"
3
3
  end
data/lib/pay.rb CHANGED
@@ -54,12 +54,4 @@ module Pay
54
54
  def self.setup
55
55
  yield self
56
56
  end
57
-
58
- def self.receipts_supported?
59
- charge_model.respond_to?(:receipt) &&
60
- application_name.present? &&
61
- business_name &&
62
- business_address &&
63
- support_email
64
- end
65
57
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pay
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.0.16
4
+ version: 3.0.20
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jason Charnes
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2021-09-11 00:00:00.000000000 Z
12
+ date: 2021-09-16 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rails
@@ -123,14 +123,7 @@ files:
123
123
  - config/locales/en.yml
124
124
  - config/routes.rb
125
125
  - db/migrate/1_create_pay_tables.rb
126
- - lib/generators/active_record/billable_generator.rb
127
- - lib/generators/active_record/merchant_generator.rb
128
- - lib/generators/active_record/templates/billable_migration.rb
129
- - lib/generators/active_record/templates/merchant_migration.rb
130
- - lib/generators/pay/billable_generator.rb
131
126
  - lib/generators/pay/email_views_generator.rb
132
- - lib/generators/pay/merchant_generator.rb
133
- - lib/generators/pay/orm_helpers.rb
134
127
  - lib/generators/pay/views_generator.rb
135
128
  - lib/pay.rb
136
129
  - lib/pay/adapter.rb
@@ -1,44 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "rails/generators/active_record"
4
- require "generators/pay/orm_helpers"
5
-
6
- module ActiveRecord
7
- module Generators
8
- class BillableGenerator < ActiveRecord::Generators::Base
9
- include Pay::Generators::OrmHelpers
10
- source_root File.expand_path("../templates", __FILE__)
11
-
12
- def copy_pay_billable_migration
13
- if (behavior == :invoke && model_exists?) || (behavior == :revoke && migration_exists?(table_name))
14
- migration_template "billable_migration.rb", "#{migration_path}/add_pay_billable_to_#{table_name}.rb", migration_version: migration_version
15
- else
16
- say "#{model_path} does not exist.", :red
17
- say "⚠️ Make sure the #{name} model exists before running this generator."
18
- end
19
- end
20
-
21
- # If the file already contains the contents, the user will receive this warning:
22
- #
23
- # File unchanged! The supplied flag value not found!
24
- #
25
- # This can be ignored as it just means the contents already exist and the file is unchanged.
26
- # Thor will be updated to improve this message: https://github.com/rails/thor/issues/706
27
- def inject_pay_billable_content
28
- return unless model_exists?
29
-
30
- content = model_contents
31
- class_path = (namespaced? ? class_name.to_s.split("::") : [class_name])
32
- indent_depth = class_path.size - 1
33
- content = content.split("\n").map { |line| " " * indent_depth + line }.join("\n") << "\n"
34
- inject_into_class(model_path, class_path.last, content)
35
- end
36
-
37
- private
38
-
39
- def model_contents
40
- " include Pay::Billable"
41
- end
42
- end
43
- end
44
- end
@@ -1,44 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "rails/generators/active_record"
4
- require "generators/pay/orm_helpers"
5
-
6
- module ActiveRecord
7
- module Generators
8
- class MerchantGenerator < ActiveRecord::Generators::Base
9
- include Pay::Generators::OrmHelpers
10
- source_root File.expand_path("../templates", __FILE__)
11
-
12
- def copy_pay_merchant_migration
13
- if (behavior == :invoke && model_exists?) || (behavior == :revoke && migration_exists?(table_name))
14
- migration_template "merchant_migration.rb", "#{migration_path}/add_pay_merchant_to_#{table_name}.rb", migration_version: migration_version
15
- else
16
- say "#{model_path} does not exist.", :red
17
- say "⚠️ Make sure the #{name} model exists before running this generator."
18
- end
19
- end
20
-
21
- # If the file already contains the contents, the user will receive this warning:
22
- #
23
- # File unchanged! The supplied flag value not found!
24
- #
25
- # This can be ignored as it just means the contents already exist and the file is unchanged.
26
- # Thor will be updated to improve this message: https://github.com/rails/thor/issues/706
27
- def inject_pay_merchant_content
28
- return unless model_exists?
29
-
30
- content = model_contents
31
- class_path = (namespaced? ? class_name.to_s.split("::") : [class_name])
32
- indent_depth = class_path.size - 1
33
- content = content.split("\n").map { |line| " " * indent_depth + line }.join("\n") << "\n"
34
- inject_into_class(model_path, class_path.last, content)
35
- end
36
-
37
- private
38
-
39
- def model_contents
40
- " include Pay::Merchant"
41
- end
42
- end
43
- end
44
- end
@@ -1,17 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- class AddPayBillableTo<%= table_name.camelize %> < ActiveRecord::Migration<%= migration_version %>
4
- def change
5
- change_table :<%= table_name %>, bulk: true do |t|
6
- t.string :processor
7
- t.string :processor_id
8
- t.public_send(Pay::Adapter.json_column_type, :pay_data)
9
- t.datetime :trial_ends_at
10
- t.string :card_type
11
- t.string :card_last4
12
- t.string :card_exp_month
13
- t.string :card_exp_year
14
- t.text :extra_billing_info
15
- end
16
- end
17
- end
@@ -1,12 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- class AddPayMerchantTo<%= table_name.camelize %> < ActiveRecord::Migration<%= migration_version %>
4
- def change
5
- add_column table_name, :merchant_processor, :string
6
-
7
- # We may already have the pay_data column if a Pay::Billable object is also a Pay::Merchant
8
- unless ActiveRecord::Base.connection.column_exists?(table_name, :pay_data)
9
- add_column :<%= table_name %>, :pay_data, Pay::Adapter.json_column_type
10
- end
11
- end
12
- end
@@ -1,17 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "rails/generators/named_base"
4
-
5
- module Pay
6
- module Generators
7
- class BillableGenerator < Rails::Generators::NamedBase
8
- include Rails::Generators::ResourceHelpers
9
-
10
- source_root File.expand_path("../templates", __FILE__)
11
-
12
- desc "Generates a migration to add Pay::Billable fields to a model."
13
-
14
- hook_for :orm
15
- end
16
- end
17
- end
@@ -1,17 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "rails/generators/named_base"
4
-
5
- module Pay
6
- module Generators
7
- class MerchantGenerator < Rails::Generators::NamedBase
8
- include Rails::Generators::ResourceHelpers
9
-
10
- source_root File.expand_path("../templates", __FILE__)
11
-
12
- desc "Generates a migration to add Pay::Merchant fields to a model."
13
-
14
- hook_for :orm
15
- end
16
- end
17
- end
@@ -1,39 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Pay
4
- module Generators
5
- module OrmHelpers
6
- private
7
-
8
- def model_exists?
9
- File.exist?(File.join(destination_root, model_path))
10
- end
11
-
12
- def migration_exists?(table_name)
13
- Dir.glob("#{File.join(destination_root, migration_path)}/[0-9]*_*.rb").grep(/\d+_add_devise_to_#{table_name}.rb$/).first
14
- end
15
-
16
- def migration_path
17
- if Rails.version >= "5.0.3"
18
- db_migrate_path
19
- else
20
- @migration_path ||= File.join("db", "migrate")
21
- end
22
- end
23
-
24
- def model_path
25
- @model_path ||= File.join("app", "models", "#{file_path}.rb")
26
- end
27
-
28
- def migration_version
29
- if rails5_and_up?
30
- "[#{Rails::VERSION::MAJOR}.#{Rails::VERSION::MINOR}]"
31
- end
32
- end
33
-
34
- def rails5_and_up?
35
- Rails::VERSION::MAJOR >= 5
36
- end
37
- end
38
- end
39
- end