Skip to content

Commit

Permalink
get subscriptions working
Browse files Browse the repository at this point in the history
  • Loading branch information
aaronbrethorst committed Nov 19, 2023
1 parent 212b15c commit c4d3cf4
Show file tree
Hide file tree
Showing 7 changed files with 166 additions and 22 deletions.
27 changes: 11 additions & 16 deletions app/controllers/api/v1/payment_intents_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,18 @@ class Api::V1::PaymentIntentsController < Api::V1::ApiController
skip_before_action :load_region

def create
begin
@intent = Stripe::PaymentIntent.create(
{
amount: params[:donation_amount_in_cents],
currency: 'usd',
# In the latest version of the API, specifying the
# `automatic_payment_methods` parameter is optional
# because Stripe enables its functionality by default.
automatic_payment_methods: { enabled: true },
}
)
respond_to do |format|
format.json
end
rescue Stripe::StripeError => e
logger.error(e.message)
if params[:donation_frequency] == 'recurring'
@recurring_response = Donations::Recurring.new(params[:donation_amount_in_cents]).run
@error = @recurring_response.error
else
@intent, @error = Donations::OneTime.new(params[:donation_amount_in_cents]).run
end

if @error
logger.error(@error.message)
head :internal_server_error
else
respond_to {|format| format.json}
end
end
end
28 changes: 28 additions & 0 deletions app/lib/donations/one_time.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
module Donations
class OneTime
def initialize(donation_amount_in_cents)
@donation_amount_in_cents = donation_amount_in_cents
end

def run
intent, error = [nil, nil]

begin
intent = Stripe::PaymentIntent.create(
{
amount: @donation_amount_in_cents,
currency: 'usd',
# In the latest version of the API, specifying the
# `automatic_payment_methods` parameter is optional
# because Stripe enables its functionality by default.
automatic_payment_methods: { enabled: true },
}
)
rescue Stripe::StripeError => e
error = e
end

[intent, error]
end
end
end
57 changes: 57 additions & 0 deletions app/lib/donations/recurring.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@

module Donations
class Recurring
def initialize(donation_amount_in_cents)
@donation_amount_in_cents = donation_amount_in_cents
end

def run
recurring_response = RecurringResponse.new(@donation_amount_in_cents)

begin
customer = Stripe::Customer.create()
recurring_response.customer_id = customer.id

recurring_response.ephemeral_key = Stripe::EphemeralKey.create(
{customer: recurring_response.customer_id},
{stripe_version: '2023-08-16'}
)
recurring_response.subscription = create_subscription(recurring_response.customer_id)
rescue Stripe::StripeError => e
recurring_response.error = e
end

recurring_response
end

private

def create_subscription(customer_id)
# Create a new price for the custom donation amount
price = Stripe::Price.create(
unit_amount: @donation_amount_in_cents,
currency: 'usd',
recurring: { interval: 'month' },
product: $stripe_recurring_donation_product_id,
)

# Create or update the subscription with the new price
subscription = Stripe::Subscription.create(
customer: customer_id,
items: [{ price: price.id }],
payment_behavior: 'default_incomplete',
expand: ['latest_invoice.payment_intent'],
)

subscription
end
end

class RecurringResponse
attr_accessor :donation_amount_in_cents, :subscription, :ephemeral_key, :error, :customer_id

def initialize(donation_amount_in_cents)
@donation_amount_in_cents = donation_amount_in_cents
end
end
end
9 changes: 8 additions & 1 deletion app/views/api/v1/payment_intents/create.json.jbuilder
Original file line number Diff line number Diff line change
@@ -1,2 +1,9 @@
json.client_secret(@intent.client_secret)
if @recurring_response
json.client_secret(@recurring_response.subscription.latest_invoice.payment_intent.client_secret)
json.customer_id(@recurring_response.customer_id)
json.ephemeral_key(@recurring_response.ephemeral_key.secret)
else
json.client_secret(@intent.client_secret)
end

json.id(SecureRandom.uuid)
12 changes: 7 additions & 5 deletions config/initializers/stripe.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
Stripe.api_key = if Rails.env.production?
Rails.application.credentials.dig(:stripe_secret_key, :production)
else
Rails.application.credentials.dig(:stripe_secret_key, :test)
end
if Rails.env.production?
Stripe.api_key = Rails.application.credentials.dig(:stripe_secret_key, :production)
$stripe_recurring_donation_product_id = "prod_OqlLl6mR66dLVQ"
else
Stripe.api_key = Rails.application.credentials.dig(:stripe_secret_key, :test)
$stripe_recurring_donation_product_id = "prod_P1xUtsgjEfkGgu"
end
Empty file.
55 changes: 55 additions & 0 deletions spec/lib/donations/recurring_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
require 'rails_helper'

describe "Donations::Recurring" do
describe '#initialize' do
it 'sets the donation amount' do
donation = Donations::Recurring.new(500)
expect(donation.instance_variable_get(:@donation_amount_in_cents)).to eq(500)
end
end

describe '#run' do
before do
allow(Stripe::Customer).to receive(:create).and_return(double('Customer', id: 'cus_test'))
allow(Stripe::EphemeralKey).to receive(:create).and_return(double('EphemeralKey'))
allow_any_instance_of(Donations::Recurring).to receive(:create_subscription).and_return(double('Subscription'))
end

it 'creates a new Stripe customer' do
donation = Donations::Recurring.new(500)
donation.run
expect(Stripe::Customer).to have_received(:create)
end

it 'creates a new Stripe ephemeral key' do
donation = Donations::Recurring.new(500)
donation.run
expect(Stripe::EphemeralKey).to have_received(:create)
end

it 'creates or finds a subscription' do
donation = Donations::Recurring.new(500)
donation.run
expect(donation).to have_received(:create_subscription)
end
end

describe '#create_subscription' do
before do
allow(Stripe::Price).to receive(:create).and_return(double('Price', id: 'price_test'))
allow(Stripe::Subscription).to receive(:create).and_return(double('Subscription'))
end

it 'creates a new Stripe price' do
donation = Donations::Recurring.new(500)
donation.send(:create_subscription, 'cus_test')
expect(Stripe::Price).to have_received(:create)
end

it 'creates a new Stripe subscription' do
donation = Donations::Recurring.new(500)
donation.send(:create_subscription, 'cus_test')
expect(Stripe::Subscription).to have_received(:create)
end
end
end

0 comments on commit c4d3cf4

Please sign in to comment.