Class: Pay::PaddleBilling::Subscription
- Inherits:
-
Subscription
- Object
- Subscription
- Pay::PaddleBilling::Subscription
- Extended by:
- Sync
- Defined in:
- app/models/pay/paddle_billing/subscription.rb
Class Method Summary collapse
- .sync(subscription_id, object: nil, name: Pay.default_product_name) ⇒ Object
- .sync_from_transaction(transaction_id) ⇒ Object
Instance Method Summary collapse
- #api_record(**options) ⇒ Object
-
#cancel(**options) ⇒ Object
If a subscription is paused, cancel immediately Otherwise, cancel at period end.
- #cancel_now!(**options) ⇒ Object
- #change_quantity(quantity, **options) ⇒ Object
-
#on_grace_period? ⇒ Boolean
A subscription could be set to cancel or pause in the future It is considered on grace period until the cancel or pause time begins.
- #pause ⇒ Object
- #paused? ⇒ Boolean
-
#payment_method_transaction ⇒ Object
Get a transaction to update payment method.
- #resumable? ⇒ Boolean
- #resume ⇒ Object
- #swap(plan, **options) ⇒ Object
Methods included from Sync
find_pay_customer, pay_processor, sync_with_retries
Class Method Details
.sync(subscription_id, object: nil, name: Pay.default_product_name) ⇒ Object
14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 |
# File 'app/models/pay/paddle_billing/subscription.rb', line 14 def self.sync(subscription_id, object: nil, name: Pay.default_product_name) sync_with_retries do subscription = object || ::Paddle::Subscription.retrieve(id: subscription_id) return unless (pay_customer = find_pay_customer(subscription.customer_id)) attributes = { current_period_end: subscription.current_billing_period&.ends_at, current_period_start: subscription.current_billing_period&.starts_at, ends_at: (subscription.canceled_at ? Time.parse(subscription.canceled_at) : nil), metadata: subscription.custom_data, paddle_cancel_url: subscription.management_urls&.cancel, paddle_update_url: subscription.management_urls&.update_payment_method, pause_starts_at: (subscription.paused_at ? Time.parse(subscription.paused_at) : nil), status: subscription.status } if subscription.items&.first item = subscription.items.first attributes[:processor_plan] = item.price.id attributes[:quantity] = item.quantity end case attributes[:status] when "canceled" # Remove payment methods since customer cannot be reused after cancelling pay_customer.payment_methods.destroy_all when "trialing" attributes[:trial_ends_at] = Time.parse(subscription.next_billed_at) if subscription.next_billed_at when "paused" attributes[:pause_starts_at] = Time.parse(subscription.paused_at) if subscription.paused_at when "active", "past_due" attributes[:trial_ends_at] = nil attributes[:pause_starts_at] = nil attributes[:ends_at] = nil end case subscription.scheduled_change&.action when "cancel" attributes[:ends_at] = Time.parse(subscription.scheduled_change.effective_at) when "pause" attributes[:pause_starts_at] = Time.parse(subscription.scheduled_change.effective_at) when "resume" attributes[:pause_resumes_at] = Time.parse(subscription.scheduled_change.effective_at) end # Update or create the subscription if (pay_subscription = find_by(customer: pay_customer, processor_id: subscription_id)) pay_subscription.with_lock { pay_subscription.update!(attributes) } pay_subscription else create!(attributes.merge(customer: pay_customer, name: name, processor_id: subscription_id)) end end end |
.sync_from_transaction(transaction_id) ⇒ Object
9 10 11 12 |
# File 'app/models/pay/paddle_billing/subscription.rb', line 9 def self.sync_from_transaction(transaction_id) Pay.deprecator.warn "Pay::PaddleBilling::Subscription.sync_from_transaction is deprecated, use Pay::PaddleBilling.sync_transaction instead" Pay::PaddleBilling.sync_transaction(transaction_id) end |
Instance Method Details
#api_record(**options) ⇒ Object
69 70 71 |
# File 'app/models/pay/paddle_billing/subscription.rb', line 69 def api_record(**) @api_record ||= ::Paddle::Subscription.retrieve(id: processor_id, **) end |
#cancel(**options) ⇒ Object
If a subscription is paused, cancel immediately Otherwise, cancel at period end
80 81 82 83 84 85 86 87 88 89 90 91 92 93 |
# File 'app/models/pay/paddle_billing/subscription.rb', line 80 def cancel(**) return if canceled? response = ::Paddle::Subscription.cancel( id: processor_id, effective_from: .fetch(:effective_from, paused? ? "immediately" : "next_billing_period") ) update( status: response.status, ends_at: response.scheduled_change&.effective_at || Time.current ) rescue ::Paddle::Error => e raise Pay::PaddleBilling::Error, e end |
#cancel_now!(**options) ⇒ Object
95 96 97 98 99 |
# File 'app/models/pay/paddle_billing/subscription.rb', line 95 def cancel_now!(**) cancel(**.merge(effective_from: "immediately")) rescue ::Paddle::Error => e raise Pay::PaddleBilling::Error, e end |
#change_quantity(quantity, **options) ⇒ Object
101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 |
# File 'app/models/pay/paddle_billing/subscription.rb', line 101 def change_quantity(quantity, **) items = [{ price_id: processor_plan, quantity: quantity }] ::Paddle::Subscription.update( id: processor_id, items: items, proration_billing_mode: .delete(:proration_billing_mode) || "prorated_immediately" ) update(quantity: quantity) rescue ::Paddle::Error => e raise Pay::PaddleBilling::Error, e end |
#on_grace_period? ⇒ Boolean
A subscription could be set to cancel or pause in the future It is considered on grace period until the cancel or pause time begins
119 120 121 |
# File 'app/models/pay/paddle_billing/subscription.rb', line 119 def on_grace_period? (canceled? && Time.current < ends_at) || (paused? && pause_starts_at? && Time.current < pause_starts_at) end |
#pause ⇒ Object
127 128 129 130 131 132 |
# File 'app/models/pay/paddle_billing/subscription.rb', line 127 def pause response = ::Paddle::Subscription.pause(id: processor_id) update!(status: :paused, pause_starts_at: response.scheduled_change.effective_at) rescue ::Paddle::Error => e raise Pay::PaddleBilling::Error, e end |
#paused? ⇒ Boolean
123 124 125 |
# File 'app/models/pay/paddle_billing/subscription.rb', line 123 def paused? status == "paused" end |
#payment_method_transaction ⇒ Object
Get a transaction to update payment method
74 75 76 |
# File 'app/models/pay/paddle_billing/subscription.rb', line 74 def payment_method_transaction ::Paddle::Subscription.get_transaction(id: processor_id) end |
#resumable? ⇒ Boolean
134 135 136 |
# File 'app/models/pay/paddle_billing/subscription.rb', line 134 def resumable? paused? end |
#resume ⇒ Object
138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 |
# File 'app/models/pay/paddle_billing/subscription.rb', line 138 def resume unless resumable? raise Error, "You can only resume paused subscriptions." end # Paddle Billing API only allows "resuming" subscriptions when they are paused # So cancel the scheduled change if it is in the future if paused? && pause_starts_at? && Time.current < pause_starts_at ::Paddle::Subscription.update(id: processor_id, scheduled_change: nil) else ::Paddle::Subscription.resume(id: processor_id, effective_from: "immediately") end update(ends_at: nil, status: :active, pause_starts_at: nil) rescue ::Paddle::Error => e raise Pay::PaddleBilling::Error, e end |
#swap(plan, **options) ⇒ Object
156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 |
# File 'app/models/pay/paddle_billing/subscription.rb', line 156 def swap(plan, **) raise ArgumentError, "plan must be a string" unless plan.is_a?(String) items = [{ price_id: plan, quantity: quantity || 1 }] ::Paddle::Subscription.update( id: processor_id, items: items, proration_billing_mode: .delete(:proration_billing_mode) || "prorated_immediately" ) update(processor_plan: plan, ends_at: nil, status: :active) end |