pay 7.3.0 → 11.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +8 -4
- data/app/controllers/pay/payments_controller.rb +2 -0
- data/app/controllers/pay/webhooks/lemon_squeezy_controller.rb +45 -0
- data/app/jobs/pay/customer_sync_job.rb +1 -1
- data/app/models/concerns/pay/routing.rb +13 -0
- data/{lib → app/models}/pay/braintree/charge.rb +7 -12
- data/{lib/pay/braintree/billable.rb → app/models/pay/braintree/customer.rb} +33 -71
- data/{lib → app/models}/pay/braintree/payment_method.rb +4 -10
- data/{lib → app/models}/pay/braintree/subscription.rb +23 -61
- data/app/models/pay/charge.rb +16 -45
- data/app/models/pay/customer.rb +5 -16
- data/app/models/pay/fake_processor/charge.rb +19 -0
- data/{lib/pay/fake_processor/billable.rb → app/models/pay/fake_processor/customer.rb} +28 -38
- data/{lib → app/models}/pay/fake_processor/merchant.rb +4 -9
- data/app/models/pay/fake_processor/payment_method.rb +13 -0
- data/app/models/pay/fake_processor/subscription.rb +70 -0
- data/app/models/pay/lemon_squeezy/charge.rb +96 -0
- data/app/models/pay/lemon_squeezy/customer.rb +80 -0
- data/app/models/pay/lemon_squeezy/payment_method.rb +29 -0
- data/app/models/pay/lemon_squeezy/subscription.rb +129 -0
- data/app/models/pay/merchant.rb +2 -11
- data/{lib → app/models}/pay/paddle_billing/charge.rb +15 -13
- data/{lib/pay/paddle_billing/billable.rb → app/models/pay/paddle_billing/customer.rb} +20 -35
- data/{lib → app/models}/pay/paddle_billing/payment_method.rb +13 -13
- data/{lib → app/models}/pay/paddle_billing/subscription.rb +40 -43
- data/{lib → app/models}/pay/paddle_classic/charge.rb +15 -18
- data/{lib/pay/paddle_classic/billable.rb → app/models/pay/paddle_classic/customer.rb} +11 -31
- data/{lib → app/models}/pay/paddle_classic/payment_method.rb +3 -11
- data/{lib → app/models}/pay/paddle_classic/subscription.rb +17 -37
- data/app/models/pay/payment_method.rb +4 -5
- data/app/models/pay/stripe/charge.rb +155 -0
- data/{lib/pay/stripe/billable.rb → app/models/pay/stripe/customer.rb} +78 -111
- data/{lib → app/models}/pay/stripe/merchant.rb +5 -20
- data/{lib → app/models}/pay/stripe/payment_method.rb +11 -17
- data/{lib → app/models}/pay/stripe/subscription.rb +83 -112
- data/app/models/pay/subscription.rb +13 -47
- data/app/models/pay/webhook.rb +5 -1
- data/app/views/pay/user_mailer/payment_action_required.text.erb +9 -0
- data/app/views/pay/user_mailer/payment_failed.text.erb +9 -0
- data/app/views/pay/user_mailer/receipt.text.erb +20 -0
- data/app/views/pay/user_mailer/refund.text.erb +21 -0
- data/app/views/pay/user_mailer/subscription_renewing.text.erb +8 -0
- data/app/views/pay/user_mailer/subscription_trial_ended.text.erb +8 -0
- data/app/views/pay/user_mailer/subscription_trial_will_end.text.erb +8 -0
- data/config/locales/en.yml +1 -0
- data/config/routes.rb +1 -0
- data/db/migrate/20250415151129_add_object_to_pay_models.rb +7 -0
- data/db/migrate/2_add_pay_sti_columns.rb +24 -0
- data/lib/pay/attributes.rb +16 -8
- data/lib/pay/braintree.rb +25 -6
- data/lib/pay/engine.rb +2 -0
- data/lib/pay/fake_processor.rb +2 -6
- data/lib/pay/lemon_squeezy/webhooks/order.rb +11 -0
- data/lib/pay/lemon_squeezy/webhooks/subscription.rb +3 -3
- data/lib/pay/lemon_squeezy/webhooks/subscription_payment.rb +11 -0
- data/lib/pay/lemon_squeezy.rb +58 -104
- data/lib/pay/nano_id.rb +1 -1
- data/lib/pay/paddle_billing.rb +15 -6
- data/lib/pay/paddle_classic/webhooks/signature_verifier.rb +1 -1
- data/lib/pay/paddle_classic.rb +11 -9
- data/lib/pay/receipts.rb +45 -44
- data/lib/pay/stripe/webhooks/charge_updated.rb +11 -0
- data/lib/pay/stripe/webhooks/customer_updated.rb +13 -9
- data/lib/pay/stripe/webhooks/payment_action_required.rb +10 -6
- data/lib/pay/stripe/webhooks/payment_failed.rb +6 -4
- data/lib/pay/stripe/webhooks/subscription_renewing.rb +9 -4
- data/lib/pay/stripe.rb +28 -9
- data/lib/pay/version.rb +1 -1
- data/lib/pay.rb +19 -1
- data/lib/tasks/pay.rake +2 -2
- metadata +45 -43
- data/app/views/pay/stripe/_checkout_button.html.erb +0 -21
- data/lib/pay/braintree/authorization_error.rb +0 -9
- data/lib/pay/braintree/error.rb +0 -23
- data/lib/pay/fake_processor/charge.rb +0 -21
- data/lib/pay/fake_processor/error.rb +0 -6
- data/lib/pay/fake_processor/payment_method.rb +0 -21
- data/lib/pay/fake_processor/subscription.rb +0 -90
- data/lib/pay/lemon_squeezy/billable.rb +0 -90
- data/lib/pay/lemon_squeezy/charge.rb +0 -68
- data/lib/pay/lemon_squeezy/error.rb +0 -7
- data/lib/pay/lemon_squeezy/payment_method.rb +0 -40
- data/lib/pay/lemon_squeezy/subscription.rb +0 -185
- data/lib/pay/lemon_squeezy/webhooks/transaction_completed.rb +0 -11
- data/lib/pay/paddle_billing/error.rb +0 -7
- data/lib/pay/paddle_classic/error.rb +0 -7
- data/lib/pay/stripe/charge.rb +0 -176
- data/lib/pay/stripe/error.rb +0 -7
data/lib/pay/stripe/charge.rb
DELETED
@@ -1,176 +0,0 @@
|
|
1
|
-
module Pay
|
2
|
-
module Stripe
|
3
|
-
class Charge
|
4
|
-
attr_reader :pay_charge
|
5
|
-
|
6
|
-
delegate :amount,
|
7
|
-
:amount_captured,
|
8
|
-
:invoice_id,
|
9
|
-
:line_items,
|
10
|
-
:payment_intent_id,
|
11
|
-
:processor_id,
|
12
|
-
:stripe_account,
|
13
|
-
to: :pay_charge
|
14
|
-
|
15
|
-
def self.sync(charge_id, object: nil, stripe_account: nil, try: 0, retries: 1)
|
16
|
-
# Skip loading the latest charge details from the API if we already have it
|
17
|
-
object ||= ::Stripe::Charge.retrieve({id: charge_id, expand: ["invoice.total_discount_amounts.discount", "invoice.total_tax_amounts.tax_rate", "refunds"]}, {stripe_account: stripe_account}.compact)
|
18
|
-
if object.customer.blank?
|
19
|
-
Rails.logger.debug "Stripe Charge #{object.id} does not have a customer"
|
20
|
-
return
|
21
|
-
end
|
22
|
-
|
23
|
-
pay_customer = Pay::Customer.find_by(processor: :stripe, processor_id: object.customer)
|
24
|
-
if pay_customer.blank?
|
25
|
-
Rails.logger.debug "Pay::Customer #{object.customer} is not in the database while syncing Stripe Charge #{object.id}"
|
26
|
-
return
|
27
|
-
end
|
28
|
-
|
29
|
-
refunds = []
|
30
|
-
object.refunds.auto_paging_each { |refund| refunds << refund }
|
31
|
-
|
32
|
-
payment_method = object.payment_method_details.try(object.payment_method_details.type)
|
33
|
-
attrs = {
|
34
|
-
amount: object.amount,
|
35
|
-
amount_captured: object.amount_captured,
|
36
|
-
amount_refunded: object.amount_refunded,
|
37
|
-
application_fee_amount: object.application_fee_amount,
|
38
|
-
bank: payment_method.try(:bank_name) || payment_method.try(:bank), # eps, fpx, ideal, p24, acss_debit, etc
|
39
|
-
brand: payment_method.try(:brand)&.capitalize,
|
40
|
-
created_at: Time.at(object.created),
|
41
|
-
currency: object.currency,
|
42
|
-
discounts: [],
|
43
|
-
exp_month: payment_method.try(:exp_month).to_s,
|
44
|
-
exp_year: payment_method.try(:exp_year).to_s,
|
45
|
-
last4: payment_method.try(:last4).to_s,
|
46
|
-
line_items: [],
|
47
|
-
metadata: object.metadata,
|
48
|
-
payment_intent_id: object.payment_intent,
|
49
|
-
payment_method_type: object.payment_method_details.type,
|
50
|
-
stripe_account: pay_customer.stripe_account,
|
51
|
-
stripe_receipt_url: object.receipt_url,
|
52
|
-
total_tax_amounts: [],
|
53
|
-
refunds: refunds.sort_by! { |r| r["created"] }
|
54
|
-
}
|
55
|
-
|
56
|
-
# Associate charge with subscription if we can
|
57
|
-
if object.invoice
|
58
|
-
invoice = (object.invoice.is_a?(::Stripe::Invoice) ? object.invoice : ::Stripe::Invoice.retrieve({id: object.invoice, expand: ["total_discount_amounts.discount", "total_tax_amounts.tax_rate"]}, {stripe_account: stripe_account}.compact))
|
59
|
-
attrs[:invoice_id] = invoice.id
|
60
|
-
attrs[:subscription] = pay_customer.subscriptions.find_by(processor_id: invoice.subscription)
|
61
|
-
|
62
|
-
attrs[:period_start] = Time.at(invoice.period_start)
|
63
|
-
attrs[:period_end] = Time.at(invoice.period_end)
|
64
|
-
attrs[:subtotal] = invoice.subtotal
|
65
|
-
attrs[:tax] = invoice.tax
|
66
|
-
attrs[:discounts] = invoice.discounts
|
67
|
-
attrs[:total_tax_amounts] = invoice.total_tax_amounts.map(&:to_hash)
|
68
|
-
attrs[:total_discount_amounts] = invoice.total_discount_amounts.map(&:to_hash)
|
69
|
-
|
70
|
-
invoice.lines.auto_paging_each do |line_item|
|
71
|
-
# Currency is tied to the charge, so storing it would be duplication
|
72
|
-
attrs[:line_items] << {
|
73
|
-
id: line_item.id,
|
74
|
-
description: line_item.description,
|
75
|
-
price_id: line_item.price&.id,
|
76
|
-
quantity: line_item.quantity,
|
77
|
-
unit_amount: line_item.price&.unit_amount,
|
78
|
-
amount: line_item.amount,
|
79
|
-
discounts: line_item.discounts,
|
80
|
-
tax_amounts: line_item.tax_amounts,
|
81
|
-
proration: line_item.proration,
|
82
|
-
period_start: Time.at(line_item.period.start),
|
83
|
-
period_end: Time.at(line_item.period.end)
|
84
|
-
}
|
85
|
-
end
|
86
|
-
# Charges without invoices
|
87
|
-
else
|
88
|
-
attrs[:period_start] = Time.at(object.created)
|
89
|
-
attrs[:period_end] = Time.at(object.created)
|
90
|
-
end
|
91
|
-
|
92
|
-
# Update or create the charge
|
93
|
-
if (pay_charge = pay_customer.charges.find_by(processor_id: object.id))
|
94
|
-
pay_charge.with_lock do
|
95
|
-
pay_charge.update!(attrs)
|
96
|
-
end
|
97
|
-
pay_charge
|
98
|
-
else
|
99
|
-
pay_customer.charges.create!(attrs.merge(processor_id: object.id))
|
100
|
-
end
|
101
|
-
rescue ActiveRecord::RecordInvalid, ActiveRecord::RecordNotUnique
|
102
|
-
try += 1
|
103
|
-
if try <= retries
|
104
|
-
sleep 0.1
|
105
|
-
retry
|
106
|
-
else
|
107
|
-
raise
|
108
|
-
end
|
109
|
-
end
|
110
|
-
|
111
|
-
def initialize(pay_charge)
|
112
|
-
@pay_charge = pay_charge
|
113
|
-
end
|
114
|
-
|
115
|
-
def charge
|
116
|
-
::Stripe::Charge.retrieve({id: processor_id, expand: ["customer", "invoice.subscription"]}, stripe_options)
|
117
|
-
rescue ::Stripe::StripeError => e
|
118
|
-
raise Pay::Stripe::Error, e
|
119
|
-
end
|
120
|
-
|
121
|
-
# Issues a CreditNote if there's an invoice, otherwise uses a Refund
|
122
|
-
# This allows Tax to be handled properly
|
123
|
-
#
|
124
|
-
# https://stripe.com/docs/api/credit_notes/create
|
125
|
-
# https://stripe.com/docs/api/refunds/create
|
126
|
-
#
|
127
|
-
# refund!
|
128
|
-
# refund!(5_00)
|
129
|
-
# refund!(5_00, refund_application_fee: true)
|
130
|
-
def refund!(amount_to_refund, **options)
|
131
|
-
if invoice_id.present?
|
132
|
-
description = options.delete(:description) || I18n.t("pay.refund")
|
133
|
-
lines = [{type: :custom_line_item, description: description, quantity: 1, unit_amount: amount_to_refund}]
|
134
|
-
credit_note!(**options.merge(refund_amount: amount_to_refund, lines: lines))
|
135
|
-
else
|
136
|
-
::Stripe::Refund.create(options.merge(charge: processor_id, amount: amount_to_refund), stripe_options)
|
137
|
-
end
|
138
|
-
pay_charge.update!(amount_refunded: pay_charge.amount_refunded + amount_to_refund)
|
139
|
-
rescue ::Stripe::StripeError => e
|
140
|
-
raise Pay::Stripe::Error, e
|
141
|
-
end
|
142
|
-
|
143
|
-
# Adds a credit note to a Stripe Invoice
|
144
|
-
def credit_note!(**options)
|
145
|
-
raise Pay::Stripe::Error, "no Stripe invoice_id on Pay::Charge" if invoice_id.blank?
|
146
|
-
::Stripe::CreditNote.create({invoice: invoice_id}.merge(options), stripe_options)
|
147
|
-
rescue ::Stripe::StripeError => e
|
148
|
-
raise Pay::Stripe::Error, e
|
149
|
-
end
|
150
|
-
|
151
|
-
def credit_notes(**options)
|
152
|
-
raise Pay::Stripe::Error, "no Stripe invoice_id on Pay::Charge" if invoice_id.blank?
|
153
|
-
::Stripe::CreditNote.list({invoice: invoice_id}.merge(options), stripe_options)
|
154
|
-
end
|
155
|
-
|
156
|
-
# https://stripe.com/docs/payments/capture-later
|
157
|
-
#
|
158
|
-
# capture
|
159
|
-
# capture(amount_to_capture: 15_00)
|
160
|
-
def capture(**options)
|
161
|
-
raise Pay::Stripe::Error, "no payment_intent_id on charge" unless payment_intent_id.present?
|
162
|
-
::Stripe::PaymentIntent.capture(payment_intent_id, options, stripe_options)
|
163
|
-
self.class.sync(processor_id)
|
164
|
-
rescue ::Stripe::StripeError => e
|
165
|
-
raise Pay::Stripe::Error, e
|
166
|
-
end
|
167
|
-
|
168
|
-
private
|
169
|
-
|
170
|
-
# Options for Stripe requests
|
171
|
-
def stripe_options
|
172
|
-
{stripe_account: stripe_account}.compact
|
173
|
-
end
|
174
|
-
end
|
175
|
-
end
|
176
|
-
end
|