Module: BetterAuth::Stripe::Utils

Defined in:
lib/better_auth/stripe/utils.rb

Class Method Summary collapse

Class Method Details

.active_or_trialing?(subscription) ⇒ Boolean

Returns:

  • (Boolean)


65
66
67
# File 'lib/better_auth/stripe/utils.rb', line 65

def active_or_trialing?(subscription)
  %w[active trialing].include?(fetch(subscription, "status").to_s)
end

.checkout_line_items(config, plan, price_id, quantity, auto_managed_seats, seat_only_plan) ⇒ Object



107
108
109
110
111
112
113
# File 'lib/better_auth/stripe/utils.rb', line 107

def checkout_line_items(config, plan, price_id, quantity, auto_managed_seats, seat_only_plan)
  items = []
  items << line_item(config, price_id, auto_managed_seats ? 1 : quantity) unless seat_only_plan
  items << {price: plan[:seat_price_id], quantity: quantity} if auto_managed_seats && plan[:seat_price_id]
  items.concat(plan_line_items(plan))
  items
end

.client(config) ⇒ Object



8
9
10
# File 'lib/better_auth/stripe/utils.rb', line 8

def client(config)
  BetterAuth::Plugins.stripe_client(config)
end

.direct_subscription_update?(old_plan, plan, auto_managed_seats) ⇒ Boolean

Returns:

  • (Boolean)


121
122
123
124
125
# File 'lib/better_auth/stripe/utils.rb', line 121

def direct_subscription_update?(old_plan, plan, auto_managed_seats)
  return true if auto_managed_seats && old_plan && old_plan[:seat_price_id] != plan[:seat_price_id]

  plan_line_items(old_plan || {}).map { |item| item[:price] } != plan_line_items(plan).map { |item| item[:price] }
end

.escape_search(value) ⇒ Object



185
186
187
# File 'lib/better_auth/stripe/utils.rb', line 185

def escape_search(value)
  value.to_s.gsub("\"", "\\\"")
end

.fetch(object, key) ⇒ Object



16
17
18
19
20
# File 'lib/better_auth/stripe/utils.rb', line 16

def fetch(object, key)
  return nil unless object.respond_to?(:[])

  object[key] || object[key.to_sym]
end

.id(object) ⇒ Object



12
13
14
# File 'lib/better_auth/stripe/utils.rb', line 12

def id(object)
  fetch(object, "id")
end

.line_item(config, price_id, quantity) ⇒ Object



101
102
103
104
105
# File 'lib/better_auth/stripe/utils.rb', line 101

def line_item(config, price_id, quantity)
  item = {price: price_id}
  item[:quantity] = quantity unless metered_price?(config, price_id)
  item
end

.metered_price?(config, price_id, lookup_key = nil) ⇒ Boolean

Returns:

  • (Boolean)


127
128
129
130
131
# File 'lib/better_auth/stripe/utils.rb', line 127

def metered_price?(config, price_id, lookup_key = nil)
  price = resolve_stripe_price(config, price_id, lookup_key)
  recurring = fetch(price || {}, "recurring") || {}
  fetch(recurring, "usage_type") == "metered"
end

.pending_cancel?(subscription) ⇒ Boolean

Returns:

  • (Boolean)


69
70
71
# File 'lib/better_auth/stripe/utils.rb', line 69

def pending_cancel?(subscription)
  !!(fetch(subscription, "cancelAtPeriodEnd") || fetch(subscription, "cancelAt"))
end

.plan_by_name(config, name) ⇒ Object



43
44
45
# File 'lib/better_auth/stripe/utils.rb', line 43

def plan_by_name(config, name)
  plans(config).find { |plan| plan[:name].to_s.downcase == name.to_s.downcase }
end

.plan_by_price_info(config, price_id, lookup_key = nil) ⇒ Object



47
48
49
50
51
# File 'lib/better_auth/stripe/utils.rb', line 47

def plan_by_price_info(config, price_id, lookup_key = nil)
  plans(config).find do |plan|
    plan[:price_id] == price_id || plan[:annual_discount_price_id] == price_id || (lookup_key && (plan[:lookup_key] == lookup_key || plan[:annual_discount_lookup_key] == lookup_key))
  end
end

.plan_line_items(plan) ⇒ Object



115
116
117
118
119
# File 'lib/better_auth/stripe/utils.rb', line 115

def plan_line_items(plan)
  Array(plan[:line_items]).map do |item|
    item.is_a?(Hash) ? BetterAuth::Plugins.normalize_hash(item) : item
  end
end

.plans(config) ⇒ Object



32
33
34
35
36
37
38
39
40
41
# File 'lib/better_auth/stripe/utils.rb', line 32

def plans(config)
  plans = subscription_options(config)[:plans] || []
  plans = plans.call if plans.respond_to?(:call)
  Array(plans).map do |plan|
    normalized = BetterAuth::Plugins.normalize_hash(plan)
    limits = fetch(plan, "limits")
    normalized[:limits] = limits if limits
    normalized
  end
end

.price_id(config, plan, annual = false) ⇒ Object



53
54
55
# File 'lib/better_auth/stripe/utils.rb', line 53

def price_id(config, plan, annual = false)
  annual ? (plan[:annual_discount_price_id] || resolve_lookup(config, plan[:annual_discount_lookup_key])) : (plan[:price_id] || resolve_lookup(config, plan[:lookup_key]))
end

.redirect?(body) ⇒ Boolean

Returns:

  • (Boolean)


175
176
177
# File 'lib/better_auth/stripe/utils.rb', line 175

def redirect?(body)
  body[:disable_redirect] != true
end

.resolve_lookup(config, lookup_key) ⇒ Object



57
58
59
60
61
62
63
# File 'lib/better_auth/stripe/utils.rb', line 57

def resolve_lookup(config, lookup_key)
  return nil if lookup_key.to_s.empty?
  return nil unless client(config).respond_to?(:prices)

  prices = client(config).prices.list(lookup_keys: [lookup_key], active: true, limit: 1)
  fetch(Array(fetch(prices, "data")).first || {}, "id")
end

.resolve_plan_item(config, subscription) ⇒ Object



81
82
83
84
85
86
87
88
89
90
91
92
# File 'lib/better_auth/stripe/utils.rb', line 81

def resolve_plan_item(config, subscription)
  items = Array(fetch(fetch(subscription, "items") || {}, "data"))
  first = items.first
  return nil unless first

  items.each do |item|
    price = fetch(item, "price") || {}
    plan = plan_by_price_info(config, fetch(price, "id"), fetch(price, "lookup_key"))
    return {item: item, plan: plan} if plan
  end
  {item: first, plan: nil} if items.length == 1
end

.resolve_quantity(subscription, plan_item, plan = nil) ⇒ Object



94
95
96
97
98
99
# File 'lib/better_auth/stripe/utils.rb', line 94

def resolve_quantity(subscription, plan_item, plan = nil)
  items = Array(fetch(fetch(subscription, "items") || {}, "data"))
  seat_price_id = plan && plan[:seat_price_id]
  seat_item = seat_price_id && items.find { |item| fetch(fetch(item, "price") || {}, "id") == seat_price_id }
  fetch(seat_item || plan_item, "quantity") || 1
end

.resolve_stripe_price(config, price_id, lookup_key = nil) ⇒ Object



133
134
135
136
137
138
139
140
141
142
143
144
145
# File 'lib/better_auth/stripe/utils.rb', line 133

def resolve_stripe_price(config, price_id, lookup_key = nil)
  return nil unless client(config).respond_to?(:prices)

  prices = client(config).prices
  if lookup_key
    result = prices.list(lookup_keys: [lookup_key], active: true, limit: 1)
    Array(fetch(result, "data")).first
  elsif price_id && prices.respond_to?(:retrieve)
    prices.retrieve(price_id)
  end
rescue
  nil
end

.schedule_id(subscription) ⇒ Object



167
168
169
170
171
172
173
# File 'lib/better_auth/stripe/utils.rb', line 167

def schedule_id(subscription)
  schedule = fetch(subscription, "schedule")
  return nil if schedule.nil?
  return schedule if schedule.is_a?(String)

  id(schedule) || schedule.to_s
end

.stripe_pending_cancel?(subscription) ⇒ Boolean

Returns:

  • (Boolean)


73
74
75
# File 'lib/better_auth/stripe/utils.rb', line 73

def stripe_pending_cancel?(subscription)
  !!(fetch(subscription, "cancel_at_period_end") || fetch(subscription, "cancel_at"))
end

.subscription_item(subscription) ⇒ Object



77
78
79
# File 'lib/better_auth/stripe/utils.rb', line 77

def subscription_item(subscription)
  Array(fetch(fetch(subscription, "items") || {}, "data")).first
end

.subscription_options(config) ⇒ Object



28
29
30
# File 'lib/better_auth/stripe/utils.rb', line 28

def subscription_options(config)
  BetterAuth::Plugins.normalize_hash(config[:subscription] || {})
end

.subscription_state(subscription, include_status: true, compact: true) ⇒ Object



147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
# File 'lib/better_auth/stripe/utils.rb', line 147

def subscription_state(subscription, include_status: true, compact: true)
  item = subscription_item(subscription)
  price = fetch(item || {}, "price") || {}
  recurring = fetch(price, "recurring") || {}
  state = {
    periodStart: time(fetch(item || subscription, "current_period_start")),
    periodEnd: time(fetch(item || subscription, "current_period_end")),
    cancelAtPeriodEnd: fetch(subscription, "cancel_at_period_end"),
    cancelAt: time(fetch(subscription, "cancel_at")),
    canceledAt: time(fetch(subscription, "canceled_at")),
    endedAt: time(fetch(subscription, "ended_at")),
    trialStart: time(fetch(subscription, "trial_start")),
    trialEnd: time(fetch(subscription, "trial_end")),
    billingInterval: fetch(recurring, "interval"),
    stripeScheduleId: schedule_id(subscription)
  }
  state[:status] = fetch(subscription, "status") if include_status
  compact ? state.compact : state
end

.time(value) ⇒ Object



22
23
24
25
26
# File 'lib/better_auth/stripe/utils.rb', line 22

def time(value)
  return nil unless value

  Time.at(value.to_i)
end

.url(ctx, url) ⇒ Object



179
180
181
182
183
# File 'lib/better_auth/stripe/utils.rb', line 179

def url(ctx, url)
  return url if url.to_s.match?(/\A[a-zA-Z][a-zA-Z0-9+\-.]*:/)

  "#{ctx.context.base_url}#{url.to_s.start_with?("/") ? url : "/#{url}"}"
end