diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 4ab192b4..44a94d12 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -2,26 +2,10 @@ class ApplicationController < ActionController::Base include Onboardable, Localize, AutoSync, Authentication, Invitable, SelfHostable, StoreLocation, Impersonatable, Breadcrumbable, FeatureGuardable, Notifiable include Pagy::Backend - helper_method :require_upgrade?, :subscription_pending? - before_action :detect_os before_action :set_default_chat private - def require_upgrade? - return false if self_hosted? - return false unless Current.session - return false if Current.family.subscribed? - return false if subscription_pending? || request.path == settings_billing_path - - true - end - - def subscription_pending? - subscribed_at = Current.session.subscribed_at - subscribed_at.present? && subscribed_at <= Time.current && subscribed_at > 1.hour.ago - end - def detect_os user_agent = request.user_agent @os = case user_agent diff --git a/app/controllers/concerns/onboardable.rb b/app/controllers/concerns/onboardable.rb index d39c228d..804667b4 100644 --- a/app/controllers/concerns/onboardable.rb +++ b/app/controllers/concerns/onboardable.rb @@ -3,16 +3,24 @@ module Onboardable included do before_action :require_onboarding_and_upgrade + helper_method :subscription_pending? end private + # A subscription goes into "pending" mode immediately after checkout, but before webhooks are processed. + def subscription_pending? + subscribed_at = Current.session.subscribed_at + subscribed_at.present? && subscribed_at <= Time.current && subscribed_at > 1.hour.ago + end + + # First, we require onboarding, then once that's complete, we require an upgrade for non-subscribed users. def require_onboarding_and_upgrade return unless Current.user return unless redirectable_path?(request.path) if Current.user.onboarded_at.blank? redirect_to onboarding_path - elsif !Current.family.subscribed? + elsif !Current.family.subscribed? && !Current.family.trialing? redirect_to upgrade_subscription_path end end diff --git a/app/controllers/subscriptions_controller.rb b/app/controllers/subscriptions_controller.rb index 4c110dd6..895c7192 100644 --- a/app/controllers/subscriptions_controller.rb +++ b/app/controllers/subscriptions_controller.rb @@ -38,7 +38,7 @@ class SubscriptionsController < ApplicationController end checkout_session_url = stripe.get_checkout_session_url( - price_id, + price_id: price_id, customer_id: Current.family.stripe_customer_id, success_url: success_subscription_url + "?session_id={CHECKOUT_SESSION_ID}", cancel_url: upgrade_subscription_url(plan: params[:plan]) @@ -49,7 +49,7 @@ class SubscriptionsController < ApplicationController def show portal_session_url = stripe.get_billing_portal_session_url( - Current.family.stripe_customer_id, + customer_id: Current.family.stripe_customer_id, return_url: settings_billing_url ) diff --git a/app/models/demo/generator.rb b/app/models/demo/generator.rb index 5b096b87..a7ce8940 100644 --- a/app/models/demo/generator.rb +++ b/app/models/demo/generator.rb @@ -2,7 +2,7 @@ class Demo::Generator COLORS = %w[#e99537 #4da568 #6471eb #db5a54 #df4e92 #c44fe9 #eb5429 #61c9ea #805dee #6ad28a] # Builds a semi-realistic mirror of what production data might look like - def reset_and_clear_data!(family_names) + def reset_and_clear_data!(family_names, require_onboarding: false) puts "Clearing existing data..." destroy_everything! @@ -10,7 +10,7 @@ class Demo::Generator puts "Data cleared" family_names.each_with_index do |family_name, index| - create_family_and_user!(family_name, "user#{index == 0 ? "" : index + 1}@maybe.local") + create_family_and_user!(family_name, "user#{index == 0 ? "" : index + 1}@maybe.local", require_onboarding: require_onboarding) end puts "Users reset" @@ -152,7 +152,7 @@ class Demo::Generator Security::Price.destroy_all end - def create_family_and_user!(family_name, user_email, currency: "USD", subscription_status: "active") + def create_family_and_user!(family_name, user_email, currency: "USD", require_onboarding: false) base_uuid = "d99e3c6e-d513-4452-8f24-dc263f8528c0" id = Digest::UUID.uuid_v5(base_uuid, family_name) @@ -160,7 +160,7 @@ class Demo::Generator id: id, name: family_name, currency: currency, - stripe_subscription_status: subscription_status, + stripe_subscription_status: require_onboarding ? nil : "active", locale: "en", country: "US", timezone: "America/New_York", @@ -173,7 +173,7 @@ class Demo::Generator last_name: "User", role: "admin", password: "password", - onboarded_at: Time.current + onboarded_at: require_onboarding ? nil : Time.current family.users.create! \ email: "member_#{user_email}", @@ -181,7 +181,7 @@ class Demo::Generator last_name: "User", role: "member", password: "password", - onboarded_at: Time.current + onboarded_at: require_onboarding ? nil : Time.current end def create_rules!(family) diff --git a/app/models/family.rb b/app/models/family.rb index 923a7566..0adb1521 100644 --- a/app/models/family.rb +++ b/app/models/family.rb @@ -128,11 +128,15 @@ class Family < ApplicationRecord end def subscribed? - trialing? || stripe_subscription_status == "active" + stripe_subscription_status == "active" end def trialing? - trial_started_at.present? && trial_started_at <= 14.days.from_now + !subscribed? && trial_started_at.present? && trial_started_at <= 14.days.from_now + end + + def trial_remaining_days + (14 - (Time.current - trial_started_at).to_i / 86400).to_i end def existing_customer? diff --git a/app/models/provider/stripe.rb b/app/models/provider/stripe.rb index 37d59e0a..09c67911 100644 --- a/app/models/provider/stripe.rb +++ b/app/models/provider/stripe.rb @@ -30,14 +30,14 @@ class Provider::Stripe end end - def create_customer(email, metadata: {}) + 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) + 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 } ], @@ -48,7 +48,7 @@ class Provider::Stripe ).url end - def get_billing_portal_session_url(customer_id, return_url: nil) + def get_billing_portal_session_url(customer_id:, return_url: nil) client.v1.billing_portal.sessions.create( customer: customer_id, return_url: return_url diff --git a/app/views/onboardings/show.html.erb b/app/views/onboardings/show.html.erb index 4f58ac51..9a2837e6 100644 --- a/app/views/onboardings/show.html.erb +++ b/app/views/onboardings/show.html.erb @@ -24,23 +24,25 @@
+ Your subscription is pending. You can still use Maybe+ while we process your subscription. +
+ <% elsif @user.family.trialing? %> ++ You are currently trialing Maybe+ + + (<%= @user.family.trial_remaining_days %> days remaining) + +
+ <% elsif @user.family.subscribed? %>You are currently subscribed to Maybe+
<% else %>You are currently not subscribed
@@ -18,7 +31,7 @@Your trial is over
+ <% if Current.family.trialing? %> +Your trial has <%= Current.family.trial_remaining_days %> days remaining
+ <% else %> +Your trial is over
+ <% end %>