Class: Pay::Subscription
- Inherits:
-
ApplicationRecord
- Object
- ApplicationRecord
- Pay::Subscription
- Defined in:
- app/models/pay/subscription.rb
Constant Summary collapse
- STATUSES =
%w[incomplete incomplete_expired trialing active past_due canceled unpaid paused]
Class Method Summary collapse
- .active_without_paused ⇒ Object
- .find_by_processor_and_id(processor, processor_id) ⇒ Object
- .pay_processor_for(name) ⇒ Object
- .with_metered_items ⇒ Object
Instance Method Summary collapse
- #active? ⇒ Boolean
- #canceled? ⇒ Boolean
- #cancelled? ⇒ Boolean
- #change_quantity(quantity) ⇒ Object
- #generic_trial? ⇒ Boolean
- #has_incomplete_payment? ⇒ Boolean
- #incomplete? ⇒ Boolean
- #latest_payment ⇒ Object
- #metered_items? ⇒ Boolean
- #no_prorate ⇒ Object
- #on_trial? ⇒ Boolean
- #paddle_paused_from ⇒ Object
- #past_due? ⇒ Boolean
- #pause_resumes_at ⇒ Object
- #payment_processor ⇒ Object
- #processor_subscription(**options) ⇒ Object
- #resume ⇒ Object
- #skip_trial ⇒ Object
- #swap(plan) ⇒ Object
- #swap_and_invoice(plan) ⇒ Object
- #sync! ⇒ Object
Class Method Details
.active_without_paused ⇒ Object
54 55 56 57 58 59 60 61 62 63 64 |
# File 'app/models/pay/subscription.rb', line 54 def self.active_without_paused case Pay::Adapter.current_adapter when "postgresql", "postgis" active.where("data->>'pause_behavior' IS NULL AND status != 'paused'") when "mysql2" active.where("data->>'$.pause_behavior' IS NULL AND status != 'paused'") when "sqlite3" # sqlite 3.38 supports ->> syntax, however, sqlite 3.37 is what ships with Ubuntu 22.04. active.where("json_extract(data, '$.pause_behavior') IS NULL AND status != 'paused'") end end |
.find_by_processor_and_id(processor, processor_id) ⇒ Object
84 85 86 |
# File 'app/models/pay/subscription.rb', line 84 def self.find_by_processor_and_id(processor, processor_id) joins(:customer).find_by(processor_id: processor_id, pay_customers: {processor: processor}) end |
.pay_processor_for(name) ⇒ Object
88 89 90 |
# File 'app/models/pay/subscription.rb', line 88 def self.pay_processor_for(name) "Pay::#{name.to_s.classify}::Subscription".constantize end |
.with_metered_items ⇒ Object
66 67 68 69 70 71 72 73 74 75 76 77 78 |
# File 'app/models/pay/subscription.rb', line 66 def self.with_metered_items case Pay::Adapter.current_adapter when "sqlite3" where("json_extract(data, '$.\"metered\"') = true") # For SQLite 3.38+ we could use the arrows # where("data->'metered' = ?", "true") when "mysql2" where("data->'$.\"metered\"' = true") when "postgresql", "postgis" # Single quotes are important for json keys apparently where("data->>'metered' = 'true'") end end |
Instance Method Details
#active? ⇒ Boolean
124 125 126 |
# File 'app/models/pay/subscription.rb', line 124 def active? ["trialing", "active", "paused"].include?(status) && (ends_at.nil? || on_grace_period? || on_trial?) end |
#canceled? ⇒ Boolean
116 117 118 |
# File 'app/models/pay/subscription.rb', line 116 def canceled? ends_at? end |
#cancelled? ⇒ Boolean
120 121 122 |
# File 'app/models/pay/subscription.rb', line 120 def cancelled? canceled? end |
#change_quantity(quantity) ⇒ Object
140 141 142 143 |
# File 'app/models/pay/subscription.rb', line 140 def change_quantity(quantity) payment_processor.change_quantity(quantity) update(quantity: quantity) end |
#generic_trial? ⇒ Boolean
108 109 110 |
# File 'app/models/pay/subscription.rb', line 108 def generic_trial? fake_processor? && trial_ends_at? end |
#has_incomplete_payment? ⇒ Boolean
136 137 138 |
# File 'app/models/pay/subscription.rb', line 136 def has_incomplete_payment? past_due? || incomplete? end |
#incomplete? ⇒ Boolean
132 133 134 |
# File 'app/models/pay/subscription.rb', line 132 def incomplete? status == "incomplete" end |
#latest_payment ⇒ Object
166 167 168 |
# File 'app/models/pay/subscription.rb', line 166 def latest_payment processor_subscription(expand: ["latest_invoice.payment_intent"]).latest_invoice.payment_intent end |
#metered_items? ⇒ Boolean
80 81 82 |
# File 'app/models/pay/subscription.rb', line 80 def metered_items? !!metered end |
#no_prorate ⇒ Object
100 101 102 |
# File 'app/models/pay/subscription.rb', line 100 def no_prorate self.prorate = false end |
#on_trial? ⇒ Boolean
112 113 114 |
# File 'app/models/pay/subscription.rb', line 112 def on_trial? trial_ends_at? && Time.zone.now < trial_ends_at end |
#paddle_paused_from ⇒ Object
170 171 172 173 174 |
# File 'app/models/pay/subscription.rb', line 170 def paddle_paused_from if ( = super) Time.zone.parse() end end |
#past_due? ⇒ Boolean
128 129 130 |
# File 'app/models/pay/subscription.rb', line 128 def past_due? status == "past_due" end |
#pause_resumes_at ⇒ Object
176 177 178 179 180 |
# File 'app/models/pay/subscription.rb', line 176 def pause_resumes_at if (resumes_at = super) Time.zone.parse(resumes_at) end end |
#payment_processor ⇒ Object
92 93 94 |
# File 'app/models/pay/subscription.rb', line 92 def payment_processor @payment_processor ||= self.class.pay_processor_for(customer.processor).new(self) end |
#processor_subscription(**options) ⇒ Object
162 163 164 |
# File 'app/models/pay/subscription.rb', line 162 def processor_subscription(**) payment_processor.subscription(**) end |
#resume ⇒ Object
145 146 147 148 149 |
# File 'app/models/pay/subscription.rb', line 145 def resume payment_processor.resume update(ends_at: nil, status: :active) self end |
#skip_trial ⇒ Object
104 105 106 |
# File 'app/models/pay/subscription.rb', line 104 def skip_trial self.trial_ends_at = nil end |
#swap(plan) ⇒ Object
151 152 153 154 155 |
# File 'app/models/pay/subscription.rb', line 151 def swap(plan) raise ArgumentError, "plan must be a string. Got `#{plan.inspect}` instead." unless plan.is_a?(String) payment_processor.swap(plan) update(processor_plan: plan, ends_at: nil, status: :active) end |
#swap_and_invoice(plan) ⇒ Object
157 158 159 160 |
# File 'app/models/pay/subscription.rb', line 157 def swap_and_invoice(plan) swap(plan) owner.invoice!(subscription_id: processor_id) end |
#sync! ⇒ Object
96 97 98 |
# File 'app/models/pay/subscription.rb', line 96 def sync! self.class.pay_processor_for(customer.processor).sync(processor_id) end |