1
0
Fork 0
mirror of https://github.com/maybe-finance/maybe.git synced 2025-07-19 05:09:38 +02:00
Maybe/app/models/family/subscribeable.rb
Zach Gollwitzer 10dd9e061a
Improve account sync performance, handle concurrent market data syncing (#2236)
* PlaidConnectable concern

* Remove bad abstraction

* Put sync implementations in own concerns

* Sync strategies

* Move sync orchestration to Sync class

* Clean up sync class, add state machine

* Basic market data sync cron

* Fix price sync

* Improve sync window column names, add timestamps

* 30 day syncs by default

* Clean up market data methods

* Report high duplicate sync counts to Sentry

* Add sync states throughout app

* account tab session

* Persistent account tab selections

* Remove manual sleep

* Add migration to clear stale syncs on self hosted apps

* Tweak sync states

* Sync completion event broadcasts

* Fix timezones in tests

* Cleanup

* More cleanup

* Plaid item UI broadcasts for sync

* Fix account ID namespace conflict

* Sync broadcasters

* Smoother account sync refreshes

* Remove test sync delay
2025-05-15 10:19:56 -04:00

80 lines
1.9 KiB
Ruby

module Family::Subscribeable
extend ActiveSupport::Concern
included do
has_one :subscription, dependent: :destroy
end
def billing_email
primary_admin = users.admin.order(:created_at).first || users.super_admin.order(:created_at).first
unless primary_admin.present?
raise "No primary admin found for family #{id}. This is an invalid data state and should never occur."
end
primary_admin.email
end
def upgrade_required?
return false if self_hoster?
return false if subscription&.active? || subscription&.trialing?
true
end
def can_start_trial?
subscription&.trial_ends_at.blank?
end
def start_trial_subscription!
create_subscription!(
status: "trialing",
trial_ends_at: Subscription.new_trial_ends_at
)
end
def trialing?
subscription&.trialing? && days_left_in_trial.positive?
end
def has_active_subscription?
subscription&.active?
end
def needs_subscription?
subscription.nil? && !self_hoster?
end
def next_billing_date
subscription&.current_period_ends_at
end
def start_subscription!(stripe_subscription_id)
if subscription.present?
subscription.update!(status: "active", stripe_id: stripe_subscription_id)
else
create_subscription!(status: "active", stripe_id: stripe_subscription_id)
end
end
def days_left_in_trial
return -1 unless subscription.present?
((subscription.trial_ends_at - Time.current).to_i / 86400) + 1
end
def percentage_of_trial_remaining
return 0 unless subscription.present?
(days_left_in_trial.to_f / Subscription::TRIAL_DAYS) * 100
end
def percentage_of_trial_completed
return 0 unless subscription.present?
(1 - days_left_in_trial.to_f / Subscription::TRIAL_DAYS) * 100
end
def sync_trial_status!
if subscription&.status == "trialing" && days_left_in_trial < 0
subscription.update!(status: "paused")
end
end
end