mirror of
https://gh.wpcy.net/https://github.com/discourse/discourse.git
synced 2026-05-23 09:41:10 +08:00
118 lines
4.2 KiB
Ruby
Vendored
118 lines
4.2 KiB
Ruby
Vendored
# frozen_string_literal: true
|
|
|
|
module DiscourseSubscriptions
|
|
module User
|
|
class PaymentsController < ::ApplicationController
|
|
include DiscourseSubscriptions::Stripe
|
|
|
|
requires_plugin DiscourseSubscriptions::PLUGIN_NAME
|
|
|
|
before_action :set_api_key
|
|
requires_login
|
|
|
|
def index
|
|
begin
|
|
customer = Customer.where(user_id: current_user.id)
|
|
customer_ids = customer.map { |c| c.customer_id } if customer
|
|
product_ids = Product.all.pluck(:external_id)
|
|
|
|
data = []
|
|
|
|
if customer_ids.present? && product_ids.present?
|
|
customer_ids.each do |customer_id|
|
|
# lots of matching because the Stripe API doesn't make it easy to match products => payments except from invoices
|
|
all_invoices = ::Stripe::Invoice.list(customer: customer_id)
|
|
invoices_with_products = parse_invoices(all_invoices, product_ids)
|
|
invoice_ids = invoices_with_products.map { |invoice| invoice[:id] }
|
|
payments = ::Stripe::PaymentIntent.list(customer: customer_id)
|
|
payments_from_invoices =
|
|
payments[:data].select { |payment| invoice_ids.include?(payment[:invoice]) }
|
|
|
|
if SiteSetting.discourse_subscriptions_enable_verbose_logging
|
|
Rails.logger.warn("Payments from invoices: #{payments_from_invoices}")
|
|
end
|
|
|
|
# Pricing table one-off purchases do not have invoices
|
|
payments_without_invoices =
|
|
payments[:data].select { |payment| payment[:invoice].nil? }
|
|
|
|
if SiteSetting.discourse_subscriptions_enable_verbose_logging
|
|
Rails.logger.warn("Payments without invoices: #{payments_without_invoices}")
|
|
end
|
|
|
|
data = data | payments_from_invoices | payments_without_invoices
|
|
end
|
|
end
|
|
|
|
if SiteSetting.discourse_subscriptions_pricing_table_enabled && current_user.email
|
|
related_guest_payments = fetch_guest_payments(current_user.email)
|
|
if SiteSetting.discourse_subscriptions_enable_verbose_logging
|
|
Rails.logger.warn("Related guest payments: #{related_guest_payments}")
|
|
end
|
|
data = data | related_guest_payments
|
|
end
|
|
|
|
data = data.sort_by { |pmt| pmt[:created] }.reverse
|
|
|
|
render_json_dump data
|
|
rescue ::Stripe::InvalidRequestError => e
|
|
render_json_error e.message
|
|
end
|
|
end
|
|
|
|
private
|
|
|
|
def parse_invoices(all_invoices, product_ids)
|
|
all_invoices[:data].select do |invoice|
|
|
invoice_lines = invoice[:lines][:data][0] if invoice[:lines] && invoice[:lines][:data]
|
|
if invoice_lines
|
|
invoice_product_id = parse_invoice_lines(invoice_lines)
|
|
product_ids.include?(invoice_product_id)
|
|
end
|
|
end
|
|
end
|
|
|
|
def parse_invoice_lines(invoice_lines)
|
|
invoice_product_id = invoice_lines[:price][:product] if invoice_lines[:price] &&
|
|
invoice_lines[:price][:product]
|
|
invoice_product_id = invoice_lines[:plan][:product] if invoice_lines[:plan] &&
|
|
invoice_lines[:plan][:product]
|
|
invoice_product_id
|
|
end
|
|
|
|
def fetch_guest_payments(email)
|
|
guest_payments = []
|
|
starting_after = nil
|
|
|
|
begin
|
|
loop do
|
|
# Fetch charges in batches of 100, using pagination with starting_after
|
|
charges =
|
|
::Stripe::Charge.list(
|
|
limit: 100,
|
|
starting_after: starting_after,
|
|
expand: ["data.payment_intent"],
|
|
)
|
|
|
|
charges[:data].each do |charge|
|
|
# Check if the charge is associated with the given email and has no customer ID
|
|
if charge[:billing_details][:email] == email && charge[:customer].nil?
|
|
guest_payments << charge
|
|
end
|
|
end
|
|
|
|
# Check if there are more charges to fetch
|
|
break if charges[:data].count < 100
|
|
|
|
# Set starting_after to the last charge's ID for the next batch
|
|
starting_after = charges[:data].last[:id]
|
|
end
|
|
rescue ::Stripe::StripeError => e
|
|
render_json_error e.message
|
|
end
|
|
|
|
guest_payments
|
|
end
|
|
end
|
|
end
|
|
end
|