class Pay::Stripe::Billable

Attributes

pay_customer[R]

Public Class Methods

default_url_options() click to toggle source
# File lib/pay/stripe/billable.rb, line 17
def self.default_url_options
  Rails.application.config.action_mailer.default_url_options || {}
end
new(pay_customer) click to toggle source
# File lib/pay/stripe/billable.rb, line 21
def initialize(pay_customer)
  @pay_customer = pay_customer
end

Public Instance Methods

add_payment_method(payment_method_id, default: false) click to toggle source
# File lib/pay/stripe/billable.rb, line 99
def add_payment_method(payment_method_id, default: false)
  customer unless processor_id?
  payment_method = ::Stripe::PaymentMethod.attach(payment_method_id, {customer: processor_id}, stripe_options)

  if default
    ::Stripe::Customer.update(processor_id, {
      invoice_settings: {
        default_payment_method: payment_method.id
      }
    }, stripe_options)
  end

  save_payment_method(payment_method, default: default)
rescue ::Stripe::StripeError => e
  raise Pay::Stripe::Error, e
end
billing_portal(**options) click to toggle source
# File lib/pay/stripe/billable.rb, line 222
def billing_portal(**options)
  customer unless processor_id?
  args = {
    customer: processor_id,
    return_url: options.delete(:return_url) || root_url
  }
  ::Stripe::BillingPortal::Session.create(args.merge(options), stripe_options)
end
charge(amount, options = {}) click to toggle source
# File lib/pay/stripe/billable.rb, line 47
def charge(amount, options = {})
  add_payment_method(payment_method_token, default: true) if payment_method_token?

  payment_method = pay_customer.default_payment_method
  args = {
    amount: amount,
    confirm: true,
    confirmation_method: :automatic,
    currency: "usd",
    customer: processor_id,
    payment_method: payment_method&.processor_id
  }.merge(options)

  payment_intent = ::Stripe::PaymentIntent.create(args, stripe_options)
  Pay::Payment.new(payment_intent).validate

  charge = payment_intent.charges.first
  Pay::Stripe::Charge.sync(charge.id, object: charge)
rescue ::Stripe::StripeError => e
  raise Pay::Stripe::Error, e
end
checkout(**options) click to toggle source

stripe.com/docs/api/checkout/sessions/create

checkout(mode: “payment”) checkout(mode: “setup”) checkout(mode: “subscription”)

checkout(line_items: “price_12345”, quantity: 2) checkout(line_items [{ price: “price_123” }, { price: “price_456” }]) checkout(line_items, “price_12345”, allow_promotion_codes: true)

# File lib/pay/stripe/billable.rb, line 177
def checkout(**options)
  customer unless processor_id?
  args = {
    customer: processor_id,
    payment_method_types: ["card"],
    mode: "payment",
    # These placeholder URLs will be replaced in a following step.
    success_url: options.delete(:success_url) || root_url(session_id: "{CHECKOUT_SESSION_ID}"),
    cancel_url: options.delete(:cancel_url) || root_url(session_id: "{CHECKOUT_SESSION_ID}")
  }

  # Line items are optional
  if (line_items = options.delete(:line_items))
    args[:line_items] = Array.wrap(line_items).map { |item|
      if item.is_a? Hash
        item
      else
        {price: item, quantity: options.fetch(:quantity, 1)}
      end
    }
  end

  ::Stripe::Checkout::Session.create(args.merge(options), stripe_options)
end
checkout_charge(amount:, name:, quantity: 1, **options) click to toggle source

stripe.com/docs/api/checkout/sessions/create

checkout_charge(amount: 15_00, name: “T-shirt”, quantity: 2)

# File lib/pay/stripe/billable.rb, line 206
def checkout_charge(amount:, name:, quantity: 1, **options)
  customer unless processor_id?
  currency = options.delete(:currency) || "usd"
  checkout(
    line_items: {
      price_data: {
        currency: currency,
        product_data: {name: name},
        unit_amount: amount
      },
      quantity: quantity
    },
    **options
  )
end
create_setup_intent() click to toggle source
# File lib/pay/stripe/billable.rb, line 148
def create_setup_intent
  ::Stripe::SetupIntent.create({customer: processor_id, usage: :off_session}, stripe_options)
end
customer() click to toggle source
# File lib/pay/stripe/billable.rb, line 25
def customer
  stripe_customer = if processor_id?
    ::Stripe::Customer.retrieve({id: processor_id}, stripe_options)
  else
    sc = ::Stripe::Customer.create({email: email, name: customer_name}, stripe_options)
    pay_customer.update!(processor_id: sc.id, stripe_account: stripe_account)
    sc
  end

  if payment_method_token?
    payment_method = ::Stripe::PaymentMethod.attach(payment_method_token, {customer: stripe_customer.id}, stripe_options)
    pay_payment_method = save_payment_method(payment_method, default: false)
    pay_payment_method.make_default!

    pay_customer.payment_method_token = nil
  end

  stripe_customer
rescue ::Stripe::StripeError => e
  raise Pay::Stripe::Error, e
end
invoice!(options = {}) click to toggle source
# File lib/pay/stripe/billable.rb, line 139
def invoice!(options = {})
  return unless processor_id?
  ::Stripe::Invoice.create(options.merge(customer: processor_id), stripe_options).pay
end
processor_subscription(subscription_id, options = {}) click to toggle source
# File lib/pay/stripe/billable.rb, line 135
def processor_subscription(subscription_id, options = {})
  ::Stripe::Subscription.retrieve(options.merge(id: subscription_id), stripe_options)
end
save_payment_method(payment_method, default:) click to toggle source

Save the Stripe::PaymentMethod to the database

# File lib/pay/stripe/billable.rb, line 117
def save_payment_method(payment_method, default:)
  pay_payment_method = pay_customer.payment_methods.where(processor_id: payment_method.id).first_or_initialize

  attributes = Pay::Stripe::PaymentMethod.extract_attributes(payment_method).merge(default: default)

  pay_customer.payment_methods.update_all(default: false) if default
  pay_payment_method.update!(attributes)

  # Reload the Rails association
  pay_customer.reload_default_payment_method if default

  pay_payment_method
end
subscribe(name: Pay.default_product_name, plan: Pay.default_plan_name, **options) click to toggle source
# File lib/pay/stripe/billable.rb, line 69
def subscribe(name: Pay.default_product_name, plan: Pay.default_plan_name, **options)
  quantity = options.delete(:quantity) || 1
  opts = {
    expand: ["pending_setup_intent", "latest_invoice.payment_intent", "latest_invoice.charge.invoice"],
    items: [plan: plan, quantity: quantity],
    off_session: true
  }.merge(options)

  # Inherit trial from plan unless trial override was specified
  opts[:trial_from_plan] = true unless opts[:trial_period_days]

  # Load the Stripe customer to verify it exists and update payment method if needed
  opts[:customer] = customer.id

  # Create subscription on Stripe
  stripe_sub = ::Stripe::Subscription.create(opts, stripe_options)

  # Save Pay::Subscription
  subscription = Pay::Stripe::Subscription.sync(stripe_sub.id, object: stripe_sub, name: name)

  # No trial, payment method requires SCA
  if subscription.incomplete?
    Pay::Payment.new(stripe_sub.latest_invoice.payment_intent).validate
  end

  subscription
rescue ::Stripe::StripeError => e
  raise Pay::Stripe::Error, e
end
sync_subscriptions() click to toggle source

Syncs a customer's subscriptions from Stripe to the database

# File lib/pay/stripe/billable.rb, line 158
def sync_subscriptions
  subscriptions = ::Stripe::Subscription.list({customer: customer}, stripe_options)
  subscriptions.map do |subscription|
    Pay::Stripe::Subscription.sync(subscription.id)
  end
rescue ::Stripe::StripeError => e
  raise Pay::Stripe::Error, e
end
trial_end_date(stripe_sub) click to toggle source
# File lib/pay/stripe/billable.rb, line 152
def trial_end_date(stripe_sub)
  # Times in Stripe are returned in UTC
  stripe_sub.trial_end.present? ? Time.at(stripe_sub.trial_end) : nil
end
upcoming_invoice() click to toggle source
# File lib/pay/stripe/billable.rb, line 144
def upcoming_invoice
  ::Stripe::Invoice.upcoming({customer: processor_id}, stripe_options)
end
update_email!() click to toggle source
# File lib/pay/stripe/billable.rb, line 131
def update_email!
  ::Stripe::Customer.update(processor_id, {email: email, name: customer_name}, stripe_options)
end

Private Instance Methods

stripe_options() click to toggle source

Options for Stripe requests

# File lib/pay/stripe/billable.rb, line 234
def stripe_options
  {stripe_account: stripe_account}.compact
end