Class: Pay::Stripe::Charge
- Inherits:
-
Charge
- Object
- ApplicationRecord
- Charge
- Pay::Stripe::Charge
- Defined in:
- app/models/pay/stripe/charge.rb
Class Method Summary collapse
Instance Method Summary collapse
- #api_record ⇒ Object
- #capture(**options) ⇒ Object
-
#credit_note!(**options) ⇒ Object
Adds a credit note to a Stripe Invoice.
-
#refund!(amount_to_refund, **options) ⇒ Object
Issues a CreditNote if there’s an invoice, otherwise uses a Refund This allows Tax to be handled properly.
Methods inherited from Charge
#amount_refunded_with_currency, #amount_with_currency, #captured?, #charged_to, find_by_processor_and_id, #full_refund?, #line_items, #partial_refund?, #refunded?
Class Method Details
.sync(charge_id, object: nil, stripe_account: nil, try: 0, retries: 1) ⇒ Object
6 7 8 9 10 11 12 13 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 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 |
# File 'app/models/pay/stripe/charge.rb', line 6 def self.sync(charge_id, object: nil, stripe_account: nil, try: 0, retries: 1) # Skip loading the latest charge details from the API if we already have it 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) if object.customer.blank? Rails.logger.debug "Stripe Charge #{object.id} does not have a customer" return end pay_customer = Pay::Customer.find_by(processor: :stripe, processor_id: object.customer) if pay_customer.blank? Rails.logger.debug "Pay::Customer #{object.customer} is not in the database while syncing Stripe Charge #{object.id}" return end refunds = [] object.refunds.auto_paging_each { |refund| refunds << refund } payment_method = object.payment_method_details.try(object.payment_method_details.type) attrs = { amount: object.amount, amount_captured: object.amount_captured, amount_refunded: object.amount_refunded, application_fee_amount: object.application_fee_amount, bank: payment_method.try(:bank_name) || payment_method.try(:bank), # eps, fpx, ideal, p24, acss_debit, etc brand: payment_method.try(:brand)&.capitalize, created_at: Time.at(object.created), currency: object.currency, discounts: [], exp_month: payment_method.try(:exp_month).to_s, exp_year: payment_method.try(:exp_year).to_s, last4: payment_method.try(:last4).to_s, line_items: [], metadata: object., payment_intent_id: object.payment_intent, payment_method_type: object.payment_method_details.type, stripe_account: pay_customer.stripe_account, stripe_receipt_url: object.receipt_url, total_tax_amounts: [], refunds: refunds.sort_by! { |r| r["created"] } } # Associate charge with subscription if we can if object.invoice 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)) attrs[:invoice_id] = invoice.id attrs[:subscription] = pay_customer.subscriptions.find_by(processor_id: invoice.subscription) attrs[:period_start] = Time.at(invoice.period_start) attrs[:period_end] = Time.at(invoice.period_end) attrs[:subtotal] = invoice.subtotal attrs[:tax] = invoice.tax attrs[:discounts] = invoice.discounts attrs[:total_tax_amounts] = invoice.total_tax_amounts.map(&:to_hash) attrs[:total_discount_amounts] = invoice.total_discount_amounts.map(&:to_hash) invoice.lines.auto_paging_each do |line_item| # Currency is tied to the charge, so storing it would be duplication attrs[:line_items] << { id: line_item.id, description: line_item.description, price_id: line_item.price&.id, quantity: line_item.quantity, unit_amount: line_item.price&.unit_amount, amount: line_item.amount, discounts: line_item.discounts, tax_amounts: line_item.tax_amounts, proration: line_item.proration, period_start: Time.at(line_item.period.start), period_end: Time.at(line_item.period.end) } end # Charges without invoices else attrs[:period_start] = Time.at(object.created) attrs[:period_end] = Time.at(object.created) end # Update or create the charge if (pay_charge = pay_customer.charges.find_by(processor_id: object.id)) pay_charge.with_lock do pay_charge.update!(attrs) end pay_charge else pay_customer.charges.create!(attrs.merge(processor_id: object.id)) end rescue ActiveRecord::RecordInvalid, ActiveRecord::RecordNotUnique try += 1 if try <= retries sleep 0.1 retry else raise end end |
Instance Method Details
#api_record ⇒ Object
102 103 104 105 106 |
# File 'app/models/pay/stripe/charge.rb', line 102 def api_record ::Stripe::Charge.retrieve({id: processor_id, expand: ["customer", "invoice.subscription"]}, ) rescue ::Stripe::StripeError => e raise Pay::Stripe::Error, e end |
#capture(**options) ⇒ Object
stripe.com/docs/payments/capture-later
capture capture(amount_to_capture: 15_00)
144 145 146 147 148 149 150 |
# File 'app/models/pay/stripe/charge.rb', line 144 def capture(**) raise Pay::Stripe::Error, "no payment_intent_id on charge" unless payment_intent_id.present? ::Stripe::PaymentIntent.capture(payment_intent_id, , ) self.class.sync(processor_id) rescue ::Stripe::StripeError => e raise Pay::Stripe::Error, e end |
#credit_note!(**options) ⇒ Object
Adds a credit note to a Stripe Invoice
133 134 135 136 137 138 |
# File 'app/models/pay/stripe/charge.rb', line 133 def credit_note!(**) raise Pay::Stripe::Error, "no Stripe invoice_id on Pay::Charge" if invoice_id.blank? ::Stripe::CreditNote.create({invoice: invoice_id}.merge(), ) rescue ::Stripe::StripeError => e raise Pay::Stripe::Error, e end |
#refund!(amount_to_refund, **options) ⇒ Object
Issues a CreditNote if there’s an invoice, otherwise uses a Refund This allows Tax to be handled properly
stripe.com/docs/api/credit_notes/create stripe.com/docs/api/refunds/create
refund! refund!(5_00) refund!(5_00, refund_application_fee: true)
117 118 119 120 121 122 123 124 125 126 127 128 129 130 |
# File 'app/models/pay/stripe/charge.rb', line 117 def refund!(amount_to_refund, **) amount_to_refund ||= amount if invoice_id.present? description = .delete(:description) || I18n.t("pay.refund") lines = [{type: :custom_line_item, description: description, quantity: 1, unit_amount: amount_to_refund}] credit_note!(**.merge(refund_amount: amount_to_refund, lines: lines)) else ::Stripe::Refund.create(.merge(charge: processor_id, amount: amount_to_refund), ) end update!(amount_refunded: amount_refunded + amount_to_refund) rescue ::Stripe::StripeError => e raise Pay::Stripe::Error, e end |