pay 2.6.10 → 2.7.2
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.
Potentially problematic release.
This version of pay might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/README.md +93 -54
- data/app/models/pay/application_record.rb +1 -0
- data/app/models/pay/charge.rb +3 -1
- data/app/models/pay/subscription.rb +5 -3
- data/db/migrate/20200603134434_add_data_to_pay_models.rb +2 -18
- data/db/migrate/20210309004259_add_data_to_pay_billable.rb +10 -0
- data/db/migrate/20210406215234_add_currency_to_pay_charges.rb +5 -0
- data/db/migrate/20210406215506_add_application_fee_to_pay_models.rb +7 -0
- data/db/migrate/20210714175351_add_uniqueness_to_pay_models.rb +6 -0
- data/lib/generators/active_record/billable_generator.rb +44 -0
- data/lib/generators/active_record/merchant_generator.rb +44 -0
- data/lib/generators/active_record/templates/billable_migration.rb +17 -0
- data/lib/generators/active_record/templates/merchant_migration.rb +12 -0
- data/lib/generators/pay/{pay_generator.rb → billable_generator.rb} +2 -3
- data/lib/generators/pay/merchant_generator.rb +17 -0
- data/lib/generators/pay/orm_helpers.rb +10 -6
- data/lib/pay.rb +22 -0
- data/lib/pay/adapter.rb +22 -0
- data/lib/pay/billable.rb +4 -0
- data/lib/pay/braintree/billable.rb +8 -1
- data/lib/pay/braintree/subscription.rb +6 -0
- data/lib/pay/env.rb +8 -0
- data/lib/pay/fake_processor/subscription.rb +6 -0
- data/lib/pay/merchant.rb +37 -0
- data/lib/pay/paddle/subscription.rb +9 -0
- data/lib/pay/paddle/webhooks/subscription_payment_succeeded.rb +3 -1
- data/lib/pay/stripe.rb +11 -0
- data/lib/pay/stripe/billable.rb +39 -36
- data/lib/pay/stripe/charge.rb +62 -4
- data/lib/pay/stripe/merchant.rb +66 -0
- data/lib/pay/stripe/subscription.rb +87 -21
- data/lib/pay/stripe/webhooks/account_updated.rb +17 -0
- data/lib/pay/stripe/webhooks/charge_refunded.rb +2 -7
- data/lib/pay/stripe/webhooks/charge_succeeded.rb +2 -8
- data/lib/pay/stripe/webhooks/checkout_session_async_payment_succeeded.rb +13 -0
- data/lib/pay/stripe/webhooks/checkout_session_completed.rb +13 -0
- data/lib/pay/stripe/webhooks/payment_intent_succeeded.rb +2 -8
- data/lib/pay/stripe/webhooks/payment_method_attached.rb +17 -0
- data/lib/pay/stripe/webhooks/payment_method_automatically_updated.rb +17 -0
- data/lib/pay/stripe/webhooks/payment_method_detached.rb +17 -0
- data/lib/pay/stripe/webhooks/subscription_created.rb +1 -35
- data/lib/pay/stripe/webhooks/subscription_deleted.rb +1 -9
- data/lib/pay/stripe/webhooks/subscription_renewing.rb +4 -6
- data/lib/pay/stripe/webhooks/subscription_updated.rb +1 -28
- data/lib/pay/version.rb +1 -1
- metadata +22 -6
- data/lib/generators/active_record/pay_generator.rb +0 -58
- data/lib/generators/active_record/templates/migration.rb +0 -9
| @@ -0,0 +1,17 @@ | |
| 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
         | 
| @@ -0,0 +1,12 @@ | |
| 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
         | 
| @@ -4,13 +4,12 @@ require "rails/generators/named_base" | |
| 4 4 |  | 
| 5 5 | 
             
            module Pay
         | 
| 6 6 | 
             
              module Generators
         | 
| 7 | 
            -
                class  | 
| 7 | 
            +
                class BillableGenerator < Rails::Generators::NamedBase
         | 
| 8 8 | 
             
                  include Rails::Generators::ResourceHelpers
         | 
| 9 9 |  | 
| 10 | 
            -
                  namespace "pay"
         | 
| 11 10 | 
             
                  source_root File.expand_path("../templates", __FILE__)
         | 
| 12 11 |  | 
| 13 | 
            -
                  desc "Generates a migration to add Billable fields to a model."
         | 
| 12 | 
            +
                  desc "Generates a migration to add Pay::Billable fields to a model."
         | 
| 14 13 |  | 
| 15 14 | 
             
                  hook_for :orm
         | 
| 16 15 | 
             
                end
         | 
| @@ -0,0 +1,17 @@ | |
| 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
         | 
| @@ -3,12 +3,6 @@ | |
| 3 3 | 
             
            module Pay
         | 
| 4 4 | 
             
              module Generators
         | 
| 5 5 | 
             
                module OrmHelpers
         | 
| 6 | 
            -
                  def model_contents
         | 
| 7 | 
            -
                    <<-CONTENT
         | 
| 8 | 
            -
              include Pay::Billable
         | 
| 9 | 
            -
                    CONTENT
         | 
| 10 | 
            -
                  end
         | 
| 11 | 
            -
             | 
| 12 6 | 
             
                  private
         | 
| 13 7 |  | 
| 14 8 | 
             
                  def model_exists?
         | 
| @@ -30,6 +24,16 @@ module Pay | |
| 30 24 | 
             
                  def model_path
         | 
| 31 25 | 
             
                    @model_path ||= File.join("app", "models", "#{file_path}.rb")
         | 
| 32 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
         | 
| 33 37 | 
             
                end
         | 
| 34 38 | 
             
              end
         | 
| 35 39 | 
             
            end
         | 
    
        data/lib/pay.rb
    CHANGED
    
    | @@ -1,10 +1,12 @@ | |
| 1 1 | 
             
            require "pay/version"
         | 
| 2 2 | 
             
            require "pay/engine"
         | 
| 3 3 | 
             
            require "pay/errors"
         | 
| 4 | 
            +
            require "pay/adapter"
         | 
| 4 5 |  | 
| 5 6 | 
             
            module Pay
         | 
| 6 7 | 
             
              autoload :Billable, "pay/billable"
         | 
| 7 8 | 
             
              autoload :Env, "pay/env"
         | 
| 9 | 
            +
              autoload :Merchant, "pay/merchant"
         | 
| 8 10 | 
             
              autoload :Payment, "pay/payment"
         | 
| 9 11 | 
             
              autoload :Receipts, "pay/receipts"
         | 
| 10 12 |  | 
| @@ -66,6 +68,26 @@ module Pay | |
| 66 68 | 
             
                Pay::Billable.includers
         | 
| 67 69 | 
             
              end
         | 
| 68 70 |  | 
| 71 | 
            +
              def self.merchant_models
         | 
| 72 | 
            +
                Pay::Merchant.includers
         | 
| 73 | 
            +
              end
         | 
| 74 | 
            +
             | 
| 75 | 
            +
              def self.find_merchant(account_key, account_value)
         | 
| 76 | 
            +
                merchant_models.each do |model|
         | 
| 77 | 
            +
                  case Pay::Adapter.current_adapter
         | 
| 78 | 
            +
                  when "postgresql"
         | 
| 79 | 
            +
                    return model.find_by("pay_data @> ?", {account_key.to_sym => account_value}.to_json)
         | 
| 80 | 
            +
                  when "mysql2"
         | 
| 81 | 
            +
                    return model.find_by("JSON_CONTAINS(pay_data, ?)", {account_key.to_sym => account_value}.to_json)
         | 
| 82 | 
            +
                  when "sqlite3"
         | 
| 83 | 
            +
                    return model.find_by("json_extract(pay_data, ?) =?", "$.#{account_key}", account_value)
         | 
| 84 | 
            +
                  else
         | 
| 85 | 
            +
                    model.find_by(pay_data: {account_key.to_sym => account_value})
         | 
| 86 | 
            +
                  end
         | 
| 87 | 
            +
                end
         | 
| 88 | 
            +
                nil
         | 
| 89 | 
            +
              end
         | 
| 90 | 
            +
             | 
| 69 91 | 
             
              def self.find_billable(processor:, processor_id:)
         | 
| 70 92 | 
             
                billable_models.each do |model|
         | 
| 71 93 | 
             
                  if (record = model.find_by(processor: processor, processor_id: processor_id))
         | 
    
        data/lib/pay/adapter.rb
    ADDED
    
    | @@ -0,0 +1,22 @@ | |
| 1 | 
            +
            module Pay
         | 
| 2 | 
            +
              module Adapter
         | 
| 3 | 
            +
                extend ActiveSupport::Concern
         | 
| 4 | 
            +
             | 
| 5 | 
            +
                def self.current_adapter
         | 
| 6 | 
            +
                  if ActiveRecord::Base.respond_to?(:connection_db_config)
         | 
| 7 | 
            +
                    ActiveRecord::Base.connection_db_config.adapter
         | 
| 8 | 
            +
                  else
         | 
| 9 | 
            +
                    ActiveRecord::Base.connection_config[:adapter]
         | 
| 10 | 
            +
                  end
         | 
| 11 | 
            +
                end
         | 
| 12 | 
            +
             | 
| 13 | 
            +
                def self.json_column_type
         | 
| 14 | 
            +
                  case current_adapter
         | 
| 15 | 
            +
                  when "postgresql"
         | 
| 16 | 
            +
                    :jsonb
         | 
| 17 | 
            +
                  else
         | 
| 18 | 
            +
                    :json
         | 
| 19 | 
            +
                  end
         | 
| 20 | 
            +
                end
         | 
| 21 | 
            +
              end
         | 
| 22 | 
            +
            end
         | 
    
        data/lib/pay/billable.rb
    CHANGED
    
    | @@ -26,6 +26,10 @@ module Pay | |
| 26 26 | 
             
                  attribute :card_token, :string
         | 
| 27 27 | 
             
                  attribute :pay_fake_processor_allowed, :boolean, default: false
         | 
| 28 28 |  | 
| 29 | 
            +
                  # Account(s) for marketplace payments
         | 
| 30 | 
            +
                  store_accessor :pay_data, :stripe_account
         | 
| 31 | 
            +
                  store_accessor :pay_data, :braintree_account
         | 
| 32 | 
            +
             | 
| 29 33 | 
             
                  validate :pay_fake_processor_is_allowed, if: :processor_changed?
         | 
| 30 34 | 
             
                end
         | 
| 31 35 |  | 
| @@ -151,9 +151,16 @@ module Pay | |
| 151 151 | 
             
                    attrs = card_details_for_braintree_transaction(transaction)
         | 
| 152 152 | 
             
                    attrs[:amount] = transaction.amount.to_f * 100
         | 
| 153 153 |  | 
| 154 | 
            +
                    # Associate charge with subscription if we can
         | 
| 155 | 
            +
                    if transaction.subscription_id
         | 
| 156 | 
            +
                      attrs[:subscription] = Pay::Subscription.find_by(processor: :braintree, processor_id: transaction.subscription_id)
         | 
| 157 | 
            +
                    end
         | 
| 158 | 
            +
             | 
| 154 159 | 
             
                    charge = billable.charges.find_or_initialize_by(
         | 
| 155 160 | 
             
                      processor: :braintree,
         | 
| 156 | 
            -
                      processor_id: transaction.id
         | 
| 161 | 
            +
                      processor_id: transaction.id,
         | 
| 162 | 
            +
                      currency: transaction.currency_iso_code,
         | 
| 163 | 
            +
                      application_fee_amount: transaction.service_fee_amount
         | 
| 157 164 | 
             
                    )
         | 
| 158 165 | 
             
                    charge.update(attrs)
         | 
| 159 166 | 
             
                    charge
         | 
| @@ -23,6 +23,10 @@ module Pay | |
| 23 23 | 
             
                    @pay_subscription = pay_subscription
         | 
| 24 24 | 
             
                  end
         | 
| 25 25 |  | 
| 26 | 
            +
                  def subscription(**options)
         | 
| 27 | 
            +
                    gateway.subscription.find(processor_id)
         | 
| 28 | 
            +
                  end
         | 
| 29 | 
            +
             | 
| 26 30 | 
             
                  def cancel
         | 
| 27 31 | 
             
                    subscription = processor_subscription
         | 
| 28 32 |  | 
| @@ -88,6 +92,8 @@ module Pay | |
| 88 92 | 
             
                  end
         | 
| 89 93 |  | 
| 90 94 | 
             
                  def swap(plan)
         | 
| 95 | 
            +
                    raise ArgumentError, "plan must be a string" unless plan.is_a?(String)
         | 
| 96 | 
            +
             | 
| 91 97 | 
             
                    if on_grace_period? && processor_plan == plan
         | 
| 92 98 | 
             
                      resume
         | 
| 93 99 | 
             
                      return
         | 
    
        data/lib/pay/env.rb
    CHANGED
    
    | @@ -17,6 +17,14 @@ module Pay | |
| 17 17 | 
             
                    secrets&.dig(env, scope, name) ||
         | 
| 18 18 | 
             
                    credentials&.dig(scope, name) ||
         | 
| 19 19 | 
             
                    secrets&.dig(scope, name)
         | 
| 20 | 
            +
                rescue ActiveSupport::MessageEncryptor::InvalidMessage
         | 
| 21 | 
            +
                  Rails.logger.error <<~MESSAGE
         | 
| 22 | 
            +
                    Rails was unable to decrypt credentials. Pay checks the Rails credentials to look for API keys for payment processors.
         | 
| 23 | 
            +
             | 
| 24 | 
            +
                    Make sure to set the `RAILS_MASTER_KEY` env variable or in the .key file. To learn more, run "bin/rails credentials:help"
         | 
| 25 | 
            +
             | 
| 26 | 
            +
                    If you're not using Rails credentials, you can delete `config/credentials.yml.enc` and `config/credentials/`.
         | 
| 27 | 
            +
                  MESSAGE
         | 
| 20 28 | 
             
                end
         | 
| 21 29 |  | 
| 22 30 | 
             
                def env
         | 
| @@ -19,6 +19,10 @@ module Pay | |
| 19 19 | 
             
                    @pay_subscription = pay_subscription
         | 
| 20 20 | 
             
                  end
         | 
| 21 21 |  | 
| 22 | 
            +
                  def subscription(**options)
         | 
| 23 | 
            +
                    pay_subscription
         | 
| 24 | 
            +
                  end
         | 
| 25 | 
            +
             | 
| 22 26 | 
             
                  def cancel
         | 
| 23 27 | 
             
                    pay_subscription.update(ends_at: Time.current.end_of_month)
         | 
| 24 28 | 
             
                  end
         | 
| @@ -48,6 +52,8 @@ module Pay | |
| 48 52 | 
             
                  end
         | 
| 49 53 |  | 
| 50 54 | 
             
                  def swap(plan)
         | 
| 55 | 
            +
                    raise ArgumentError, "plan must be a string" unless plan.is_a?(String)
         | 
| 56 | 
            +
             | 
| 51 57 | 
             
                    pay_subscription.update(processor_plan: plan)
         | 
| 52 58 | 
             
                  end
         | 
| 53 59 | 
             
                end
         | 
    
        data/lib/pay/merchant.rb
    ADDED
    
    | @@ -0,0 +1,37 @@ | |
| 1 | 
            +
            module Pay
         | 
| 2 | 
            +
              module Merchant
         | 
| 3 | 
            +
                extend ActiveSupport::Concern
         | 
| 4 | 
            +
             | 
| 5 | 
            +
                # Keep track of which Merchant models we have
         | 
| 6 | 
            +
                class << self
         | 
| 7 | 
            +
                  attr_reader :includers
         | 
| 8 | 
            +
                end
         | 
| 9 | 
            +
             | 
| 10 | 
            +
                def self.included(base = nil, &block)
         | 
| 11 | 
            +
                  @includers ||= []
         | 
| 12 | 
            +
                  @includers << base if base
         | 
| 13 | 
            +
                  super
         | 
| 14 | 
            +
                end
         | 
| 15 | 
            +
             | 
| 16 | 
            +
                included do
         | 
| 17 | 
            +
                  store_accessor :pay_data, :stripe_connect_account_id
         | 
| 18 | 
            +
                  store_accessor :pay_data, :onboarding_complete
         | 
| 19 | 
            +
                end
         | 
| 20 | 
            +
             | 
| 21 | 
            +
                def merchant
         | 
| 22 | 
            +
                  @merchant ||= merchant_processor_for(merchant_processor).new(self)
         | 
| 23 | 
            +
                end
         | 
| 24 | 
            +
             | 
| 25 | 
            +
                def merchant_processor_for(name)
         | 
| 26 | 
            +
                  "Pay::#{name.to_s.classify}::Merchant".constantize
         | 
| 27 | 
            +
                end
         | 
| 28 | 
            +
             | 
| 29 | 
            +
                def stripe_connect_account_id?
         | 
| 30 | 
            +
                  !!stripe_connect_account_id
         | 
| 31 | 
            +
                end
         | 
| 32 | 
            +
             | 
| 33 | 
            +
                def onboarding_complete?
         | 
| 34 | 
            +
                  !!onboarding_complete
         | 
| 35 | 
            +
                end
         | 
| 36 | 
            +
              end
         | 
| 37 | 
            +
            end
         | 
| @@ -24,6 +24,13 @@ module Pay | |
| 24 24 | 
             
                    @pay_subscription = pay_subscription
         | 
| 25 25 | 
             
                  end
         | 
| 26 26 |  | 
| 27 | 
            +
                  def subscription(**options)
         | 
| 28 | 
            +
                    hash = PaddlePay::Subscription::User.list({subscription_id: processor_id}, options).try(:first)
         | 
| 29 | 
            +
                    OpenStruct.new(hash)
         | 
| 30 | 
            +
                  rescue ::PaddlePay::PaddlePayError => e
         | 
| 31 | 
            +
                    raise Pay::Paddle::Error, e
         | 
| 32 | 
            +
                  end
         | 
| 33 | 
            +
             | 
| 27 34 | 
             
                  def cancel
         | 
| 28 35 | 
             
                    subscription = processor_subscription
         | 
| 29 36 | 
             
                    PaddlePay::Subscription::User.cancel(processor_id)
         | 
| @@ -72,6 +79,8 @@ module Pay | |
| 72 79 | 
             
                  end
         | 
| 73 80 |  | 
| 74 81 | 
             
                  def swap(plan)
         | 
| 82 | 
            +
                    raise ArgumentError, "plan must be a string" unless plan.is_a?(String)
         | 
| 83 | 
            +
             | 
| 75 84 | 
             
                    attributes = {plan_id: plan, prorate: prorate}
         | 
| 76 85 | 
             
                    attributes[:quantity] = quantity if quantity?
         | 
| 77 86 | 
             
                    PaddlePay::Subscription::User.update(processor_id, attributes)
         | 
| @@ -30,8 +30,10 @@ module Pay | |
| 30 30 | 
             
                      params = {
         | 
| 31 31 | 
             
                        amount: Integer(event["sale_gross"].to_f * 100),
         | 
| 32 32 | 
             
                        card_type: event["payment_method"],
         | 
| 33 | 
            +
                        created_at: Time.zone.parse(event["event_time"]),
         | 
| 34 | 
            +
                        currency: event["currency"],
         | 
| 33 35 | 
             
                        paddle_receipt_url: event["receipt_url"],
         | 
| 34 | 
            -
                         | 
| 36 | 
            +
                        subscription: Pay::Subscription.find_by(processor: :paddle, processor_id: event["subscription_id"])
         | 
| 35 37 | 
             
                      }
         | 
| 36 38 |  | 
| 37 39 | 
             
                      payment_information = Pay::Paddle::Billable.new(user).payment_information(event["subscription_id"])
         | 
    
        data/lib/pay/stripe.rb
    CHANGED
    
    | @@ -4,10 +4,14 @@ module Pay | |
| 4 4 | 
             
                autoload :Charge, "pay/stripe/charge"
         | 
| 5 5 | 
             
                autoload :Subscription, "pay/stripe/subscription"
         | 
| 6 6 | 
             
                autoload :Error, "pay/stripe/error"
         | 
| 7 | 
            +
                autoload :Merchant, "pay/stripe/merchant"
         | 
| 7 8 |  | 
| 8 9 | 
             
                module Webhooks
         | 
| 10 | 
            +
                  autoload :AccountUpdated, "pay/stripe/webhooks/account_updated"
         | 
| 9 11 | 
             
                  autoload :ChargeRefunded, "pay/stripe/webhooks/charge_refunded"
         | 
| 10 12 | 
             
                  autoload :ChargeSucceeded, "pay/stripe/webhooks/charge_succeeded"
         | 
| 13 | 
            +
                  autoload :CheckoutSessionCompleted, "pay/stripe/webhooks/checkout_session_completed"
         | 
| 14 | 
            +
                  autoload :CheckoutSessionAsyncPaymentSucceeded, "pay/stripe/webhooks/checkout_session_async_payment_succeeded"
         | 
| 11 15 | 
             
                  autoload :CustomerDeleted, "pay/stripe/webhooks/customer_deleted"
         | 
| 12 16 | 
             
                  autoload :CustomerUpdated, "pay/stripe/webhooks/customer_updated"
         | 
| 13 17 | 
             
                  autoload :PaymentActionRequired, "pay/stripe/webhooks/payment_action_required"
         | 
| @@ -81,6 +85,13 @@ module Pay | |
| 81 85 | 
             
                    events.subscribe "stripe.payment_method.updated", Pay::Stripe::Webhooks::PaymentMethodUpdated.new
         | 
| 82 86 | 
             
                    events.subscribe "stripe.payment_method.card_automatically_updated", Pay::Stripe::Webhooks::PaymentMethodUpdated.new
         | 
| 83 87 | 
             
                    events.subscribe "stripe.payment_method.detached", Pay::Stripe::Webhooks::PaymentMethodUpdated.new
         | 
| 88 | 
            +
             | 
| 89 | 
            +
                    # If an account is updated in stripe, we should update it as well
         | 
| 90 | 
            +
                    events.subscribe "stripe.account.updated", Pay::Stripe::Webhooks::AccountUpdated.new
         | 
| 91 | 
            +
             | 
| 92 | 
            +
                    # Handle subscriptions in Stripe Checkout Sessions
         | 
| 93 | 
            +
                    events.subscribe "stripe.checkout.session.completed", Pay::Stripe::Webhooks::CheckoutSessionCompleted.new
         | 
| 94 | 
            +
                    events.subscribe "stripe.checkout.session.async_payment_succeeded", Pay::Stripe::Webhooks::CheckoutSessionAsyncPaymentSucceeded.new
         | 
| 84 95 | 
             
                  end
         | 
| 85 96 | 
             
                end
         | 
| 86 97 | 
             
              end
         | 
    
        data/lib/pay/stripe/billable.rb
    CHANGED
    
    | @@ -10,6 +10,7 @@ module Pay | |
| 10 10 | 
             
                    :email,
         | 
| 11 11 | 
             
                    :customer_name,
         | 
| 12 12 | 
             
                    :card_token,
         | 
| 13 | 
            +
                    :stripe_account,
         | 
| 13 14 | 
             
                    to: :billable
         | 
| 14 15 |  | 
| 15 16 | 
             
                  class << self
         | 
| @@ -27,17 +28,17 @@ module Pay | |
| 27 28 | 
             
                  # Returns Stripe::Customer
         | 
| 28 29 | 
             
                  def customer
         | 
| 29 30 | 
             
                    stripe_customer = if processor_id?
         | 
| 30 | 
            -
                      ::Stripe::Customer.retrieve(processor_id)
         | 
| 31 | 
            +
                      ::Stripe::Customer.retrieve(processor_id, stripe_options)
         | 
| 31 32 | 
             
                    else
         | 
| 32 | 
            -
                      sc = ::Stripe::Customer.create(email: email, name: customer_name)
         | 
| 33 | 
            -
                      billable.update(processor: :stripe, processor_id: sc.id)
         | 
| 33 | 
            +
                      sc = ::Stripe::Customer.create({email: email, name: customer_name}, stripe_options)
         | 
| 34 | 
            +
                      billable.update(processor: :stripe, processor_id: sc.id, stripe_account: stripe_account)
         | 
| 34 35 | 
             
                      sc
         | 
| 35 36 | 
             
                    end
         | 
| 36 37 |  | 
| 37 38 | 
             
                    # Update the user's card on file if a token was passed in
         | 
| 38 39 | 
             
                    if card_token.present?
         | 
| 39 | 
            -
                      payment_method = ::Stripe::PaymentMethod.attach(card_token, customer: stripe_customer.id)
         | 
| 40 | 
            -
                      stripe_customer = ::Stripe::Customer.update(stripe_customer.id, invoice_settings: {default_payment_method: payment_method.id})
         | 
| 40 | 
            +
                      payment_method = ::Stripe::PaymentMethod.attach(card_token, {customer: stripe_customer.id}, stripe_options)
         | 
| 41 | 
            +
                      stripe_customer = ::Stripe::Customer.update(stripe_customer.id, {invoice_settings: {default_payment_method: payment_method.id}}, stripe_options)
         | 
| 41 42 | 
             
                      update_card_on_file(payment_method.card)
         | 
| 42 43 | 
             
                    end
         | 
| 43 44 |  | 
| @@ -60,11 +61,12 @@ module Pay | |
| 60 61 | 
             
                      payment_method: stripe_customer.invoice_settings.default_payment_method
         | 
| 61 62 | 
             
                    }.merge(options)
         | 
| 62 63 |  | 
| 63 | 
            -
                    payment_intent = ::Stripe::PaymentIntent.create(args)
         | 
| 64 | 
            +
                    payment_intent = ::Stripe::PaymentIntent.create(args, stripe_options)
         | 
| 64 65 | 
             
                    Pay::Payment.new(payment_intent).validate
         | 
| 65 66 |  | 
| 66 67 | 
             
                    # Create a new charge object
         | 
| 67 | 
            -
                     | 
| 68 | 
            +
                    charge = payment_intent.charges.first
         | 
| 69 | 
            +
                    Pay::Stripe::Charge.sync(charge.id, object: charge)
         | 
| 68 70 | 
             
                  rescue ::Stripe::StripeError => e
         | 
| 69 71 | 
             
                    raise Pay::Stripe::Error, e
         | 
| 70 72 | 
             
                  end
         | 
| @@ -86,16 +88,15 @@ module Pay | |
| 86 88 | 
             
                    # Load the Stripe customer to verify it exists and update card if needed
         | 
| 87 89 | 
             
                    opts[:customer] = customer.id
         | 
| 88 90 |  | 
| 89 | 
            -
                     | 
| 90 | 
            -
                     | 
| 91 | 
            +
                    # Create subscription on Stripe
         | 
| 92 | 
            +
                    stripe_sub = ::Stripe::Subscription.create(opts, stripe_options)
         | 
| 93 | 
            +
             | 
| 94 | 
            +
                    # Save Pay::Subscription
         | 
| 95 | 
            +
                    subscription = Pay::Stripe::Subscription.sync(stripe_sub.id, object: stripe_sub, name: name)
         | 
| 91 96 |  | 
| 92 97 | 
             
                    # No trial, card requires SCA
         | 
| 93 98 | 
             
                    if subscription.incomplete?
         | 
| 94 99 | 
             
                      Pay::Payment.new(stripe_sub.latest_invoice.payment_intent).validate
         | 
| 95 | 
            -
             | 
| 96 | 
            -
                    # Trial, card requires SCA
         | 
| 97 | 
            -
                    elsif subscription.on_trial? && stripe_sub.pending_setup_intent
         | 
| 98 | 
            -
                      Pay::Payment.new(stripe_sub.pending_setup_intent).validate
         | 
| 99 100 | 
             
                    end
         | 
| 100 101 |  | 
| 101 102 | 
             
                    subscription
         | 
| @@ -111,8 +112,8 @@ module Pay | |
| 111 112 |  | 
| 112 113 | 
             
                    return true if payment_method_id == stripe_customer.invoice_settings.default_payment_method
         | 
| 113 114 |  | 
| 114 | 
            -
                    payment_method = ::Stripe::PaymentMethod.attach(payment_method_id, customer: stripe_customer.id)
         | 
| 115 | 
            -
                    ::Stripe::Customer.update(stripe_customer.id, invoice_settings: {default_payment_method: payment_method.id})
         | 
| 115 | 
            +
                    payment_method = ::Stripe::PaymentMethod.attach(payment_method_id, {customer: stripe_customer.id}, stripe_options)
         | 
| 116 | 
            +
                    ::Stripe::Customer.update(stripe_customer.id, {invoice_settings: {default_payment_method: payment_method.id}}, stripe_options)
         | 
| 116 117 |  | 
| 117 118 | 
             
                    update_card_on_file(payment_method.card)
         | 
| 118 119 | 
             
                    true
         | 
| @@ -121,33 +122,33 @@ module Pay | |
| 121 122 | 
             
                  end
         | 
| 122 123 |  | 
| 123 124 | 
             
                  def update_email!
         | 
| 124 | 
            -
                    ::Stripe::Customer.update(processor_id, {email: email, name: customer_name})
         | 
| 125 | 
            +
                    ::Stripe::Customer.update(processor_id, {email: email, name: customer_name}, stripe_options)
         | 
| 125 126 | 
             
                  end
         | 
| 126 127 |  | 
| 127 128 | 
             
                  def processor_subscription(subscription_id, options = {})
         | 
| 128 | 
            -
                    ::Stripe::Subscription.retrieve(options.merge(id: subscription_id))
         | 
| 129 | 
            +
                    ::Stripe::Subscription.retrieve(options.merge(id: subscription_id), stripe_options)
         | 
| 129 130 | 
             
                  end
         | 
| 130 131 |  | 
| 131 132 | 
             
                  def invoice!(options = {})
         | 
| 132 133 | 
             
                    return unless processor_id?
         | 
| 133 | 
            -
                    ::Stripe::Invoice.create(options.merge(customer: processor_id)).pay
         | 
| 134 | 
            +
                    ::Stripe::Invoice.create(options.merge(customer: processor_id), stripe_options).pay
         | 
| 134 135 | 
             
                  end
         | 
| 135 136 |  | 
| 136 137 | 
             
                  def upcoming_invoice
         | 
| 137 | 
            -
                    ::Stripe::Invoice.upcoming(customer: processor_id)
         | 
| 138 | 
            +
                    ::Stripe::Invoice.upcoming({customer: processor_id}, stripe_options)
         | 
| 138 139 | 
             
                  end
         | 
| 139 140 |  | 
| 140 141 | 
             
                  # Used by webhooks when the customer or source changes
         | 
| 141 142 | 
             
                  def sync_card_from_stripe
         | 
| 142 143 | 
             
                    if (payment_method_id = customer.invoice_settings.default_payment_method)
         | 
| 143 | 
            -
                      update_card_on_file ::Stripe::PaymentMethod.retrieve(payment_method_id).card
         | 
| 144 | 
            +
                      update_card_on_file ::Stripe::PaymentMethod.retrieve(payment_method_id, stripe_options).card
         | 
| 144 145 | 
             
                    else
         | 
| 145 146 | 
             
                      billable.update(card_type: nil, card_last4: nil)
         | 
| 146 147 | 
             
                    end
         | 
| 147 148 | 
             
                  end
         | 
| 148 149 |  | 
| 149 150 | 
             
                  def create_setup_intent
         | 
| 150 | 
            -
                    ::Stripe::SetupIntent.create(customer: processor_id, usage: :off_session)
         | 
| 151 | 
            +
                    ::Stripe::SetupIntent.create({customer: processor_id, usage: :off_session}, stripe_options)
         | 
| 151 152 | 
             
                  end
         | 
| 152 153 |  | 
| 153 154 | 
             
                  def trial_end_date(stripe_sub)
         | 
| @@ -167,19 +168,14 @@ module Pay | |
| 167 168 | 
             
                    billable.card_token = nil
         | 
| 168 169 | 
             
                  end
         | 
| 169 170 |  | 
| 170 | 
            -
                   | 
| 171 | 
            -
             | 
| 172 | 
            -
             | 
| 173 | 
            -
                     | 
| 174 | 
            -
                       | 
| 175 | 
            -
             | 
| 176 | 
            -
             | 
| 177 | 
            -
             | 
| 178 | 
            -
                      card_exp_year: object.payment_method_details.card.exp_year,
         | 
| 179 | 
            -
                      created_at: Time.zone.at(object.created)
         | 
| 180 | 
            -
                    )
         | 
| 181 | 
            -
             | 
| 182 | 
            -
                    charge
         | 
| 171 | 
            +
                  # Syncs a customer's subscriptions from Stripe to the database
         | 
| 172 | 
            +
                  def sync_subscriptions
         | 
| 173 | 
            +
                    subscriptions = ::Stripe::Subscription.list({customer: customer}, stripe_options)
         | 
| 174 | 
            +
                    subscriptions.map do |subscription|
         | 
| 175 | 
            +
                      Pay::Stripe::Subscription.sync(subscription.id)
         | 
| 176 | 
            +
                    end
         | 
| 177 | 
            +
                  rescue ::Stripe::StripeError => e
         | 
| 178 | 
            +
                    raise Pay::Stripe::Error, e
         | 
| 183 179 | 
             
                  end
         | 
| 184 180 |  | 
| 185 181 | 
             
                  # https://stripe.com/docs/api/checkout/sessions/create
         | 
| @@ -213,7 +209,7 @@ module Pay | |
| 213 209 | 
             
                      }
         | 
| 214 210 | 
             
                    end
         | 
| 215 211 |  | 
| 216 | 
            -
                    ::Stripe::Checkout::Session.create(args.merge(options))
         | 
| 212 | 
            +
                    ::Stripe::Checkout::Session.create(args.merge(options), stripe_options)
         | 
| 217 213 | 
             
                  end
         | 
| 218 214 |  | 
| 219 215 | 
             
                  # https://stripe.com/docs/api/checkout/sessions/create
         | 
| @@ -240,7 +236,14 @@ module Pay | |
| 240 236 | 
             
                      customer: processor_id,
         | 
| 241 237 | 
             
                      return_url: options.delete(:return_url) || root_url
         | 
| 242 238 | 
             
                    }
         | 
| 243 | 
            -
                    ::Stripe::BillingPortal::Session.create(args.merge(options))
         | 
| 239 | 
            +
                    ::Stripe::BillingPortal::Session.create(args.merge(options), stripe_options)
         | 
| 240 | 
            +
                  end
         | 
| 241 | 
            +
             | 
| 242 | 
            +
                  private
         | 
| 243 | 
            +
             | 
| 244 | 
            +
                  # Options for Stripe requests
         | 
| 245 | 
            +
                  def stripe_options
         | 
| 246 | 
            +
                    {stripe_account: stripe_account}.compact
         | 
| 244 247 | 
             
                  end
         | 
| 245 248 | 
             
                end
         | 
| 246 249 | 
             
              end
         |