1
0
Fork 0
mirror of https://github.com/maybe-finance/maybe.git synced 2025-08-04 21:15:19 +02:00

New onboarding, trials, Stripe integration (#2185)
Some checks are pending
Publish Docker image / ci (push) Waiting to run
Publish Docker image / Build docker image (push) Blocked by required conditions

* New onboarding, trials, Stripe integration

* Fix tests

* Lint fixes

* Fix subscription endpoints
This commit is contained in:
Zach Gollwitzer 2025-05-01 16:47:14 -04:00 committed by GitHub
parent 79b4a3769b
commit a51c4d2cba
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
53 changed files with 847 additions and 372 deletions

View file

@ -19,6 +19,15 @@ class Provider::Registry
end
private
def stripe
secret_key = ENV["STRIPE_SECRET_KEY"]
webhook_secret = ENV["STRIPE_WEBHOOK_SECRET"]
return nil unless secret_key.present? && webhook_secret.present?
Provider::Stripe.new(secret_key:, webhook_secret:)
end
def synth
api_key = ENV.fetch("SYNTH_API_KEY", Setting.synth_api_key)

View file

@ -0,0 +1,68 @@
class Provider::Stripe
def initialize(secret_key:, webhook_secret:)
@client = Stripe::StripeClient.new(
secret_key,
stripe_version: "2025-04-30.basil"
)
@webhook_secret = webhook_secret
end
def process_event(event_id)
event = retrieve_event(event_id)
case event.type
when /^customer\.subscription\./
SubscriptionEventProcessor.new(client).process(event)
when /^customer\./
CustomerEventProcessor.new(client).process(event)
else
Rails.logger.info "Unhandled event type: #{event.type}"
end
end
def process_webhook_later(webhook_body, sig_header)
thin_event = client.parse_thin_event(webhook_body, sig_header, webhook_secret)
if thin_event.type.start_with?("customer.")
StripeEventHandlerJob.perform_later(thin_event.id)
else
Rails.logger.info "Unhandled event type: #{thin_event.type}"
end
end
def create_customer(email:, metadata: {})
client.v1.customers.create(
email: email,
metadata: metadata
)
end
def get_checkout_session_url(price_id:, customer_id: nil, success_url: nil, cancel_url: nil)
client.v1.checkout.sessions.create(
customer: customer_id,
line_items: [ { price: price_id, quantity: 1 } ],
mode: "subscription",
allow_promotion_codes: true,
success_url: success_url,
cancel_url: cancel_url
).url
end
def get_billing_portal_session_url(customer_id:, return_url: nil)
client.v1.billing_portal.sessions.create(
customer: customer_id,
return_url: return_url
).url
end
def retrieve_checkout_session(session_id)
client.v1.checkout.sessions.retrieve(session_id)
end
private
attr_reader :client, :webhook_secret
def retrieve_event(event_id)
client.v2.core.events.retrieve(event_id)
end
end

View file

@ -0,0 +1,20 @@
class Provider::Stripe::CustomerEventProcessor < Provider::Stripe::EventProcessor
Error = Class.new(StandardError)
def process
raise Error, "Family not found for Stripe customer ID: #{customer_id}" unless family
family.update(
stripe_customer_id: customer_id
)
end
private
def family
Family.find_by(stripe_customer_id: customer_id)
end
def customer_id
event_data.id
end
end

View file

@ -0,0 +1,17 @@
class Provider::Stripe::EventProcessor
def initialize(event:, client:)
@event = event
@client = client
end
def process
raise NotImplementedError, "Subclasses must implement the process method"
end
private
attr_reader :event, :client
def event_data
event.data.object
end
end

View file

@ -0,0 +1,29 @@
class Provider::Stripe::SubscriptionEventProcessor < Provider::Stripe::EventProcessor
Error = Class.new(StandardError)
def process
raise Error, "Family not found for Stripe customer ID: #{customer_id}" unless family
family.update(
stripe_plan_id: plan_id,
stripe_subscription_status: subscription_status
)
end
private
def family
Family.find_by(stripe_customer_id: customer_id)
end
def customer_id
event_data.customer
end
def plan_id
event_data.plan.id
end
def subscription_status
event_data.status
end
end