111 lines
4.5 KiB
Ruby
111 lines
4.5 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
# License: AGPL-3.0-or-later WITH WTO-AP-3.0-or-later
|
|
# Full license explanation at https://github.com/houdiniproject/houdini/blob/master/LICENSE
|
|
module Audit
|
|
# Given a list of pairs of nonprofit ids and stripe_account_ids (eg [[4341, 'acct_arst'], [3624, 'acct_arst']])
|
|
# Find all their available balances on both stripe and CC
|
|
# Give all the ones that dont match up with the difference
|
|
# Negative difference = more balance on CC
|
|
# Positive difference = more balance on Stripe
|
|
# Returns an array of pairs of ids with balance difference (eg [[4341, -10], [3624, 100]])
|
|
def self.match_available_balances(nps, date)
|
|
date ||= Time.current
|
|
nps.map do |id, stripe_account_id|
|
|
cc_bal = QueryPayments.get_payout_totals(QueryPayments.ids_for_payout(id, date: date))['net_amount']
|
|
stripe_bal = Stripe::Balance.retrieve(stripe_account: stripe_account_id).available.first.amount
|
|
[id, stripe_bal - cc_bal]
|
|
end
|
|
end
|
|
|
|
# Print a report of whether saved payout balances match up to the sum of the payment records
|
|
def self.payout_check(id)
|
|
p = Payout.find(id)
|
|
gross = p.payments.sum(:gross_amount)
|
|
fees = p.payments.sum(:fee_total)
|
|
net = p.payments.sum(:net_amount)
|
|
puts [
|
|
[p.gross_amount, p.fee_total, p.net_amount].join(', ') + ' -- payout columns',
|
|
[gross, fees, net].join(', ') + ' -- summed from payments',
|
|
[p.gross_amount - gross, p.fee_total - fees, p.net_amount - net].join(', ') + ' -- differences'
|
|
].join("\n")
|
|
end
|
|
|
|
# Return a list of all Stripe transaction objects for an account
|
|
def self.find_all_transactions(np_id)
|
|
logger = ActiveRecord::Base.logger; ActiveRecord::Base.logger = nil
|
|
acct = Nonprofit.find(np_id).stripe_account_id
|
|
starting_after = nil
|
|
transfers = []
|
|
loop do
|
|
new_transfers = Stripe::Transfer.all(limit: 100, starting_after: starting_after, destination: acct).data
|
|
break if new_transfers.empty?
|
|
|
|
transfers += new_transfers
|
|
starting_after = new_transfers.last.id
|
|
end
|
|
ActiveRecord::Base.logger = logger
|
|
transfers
|
|
end
|
|
|
|
# Given a list of Stripe transaction objects, see if any are missing on CommitChange
|
|
def self.find_missing_charges(transfers)
|
|
transfers
|
|
.map { |t| [t.source_transaction, t.amount] }
|
|
.select { |id, amount| Charge.where(stripe_charge_id: id, amount: amount).empty? }
|
|
end
|
|
|
|
# Audit some basic balances for a nonprofit with those on Stripe
|
|
def self.audit_balances(id)
|
|
np = Nonprofit.find(id)
|
|
puts "Stripe Dashboard: https://dashboard.stripe.com/#{np.stripe_account_id}"
|
|
puts "CC Payments: https://commitchange.com/nonprofits/#{id}/payments"
|
|
puts "CC Payouts: https://commitchange.com/nonprofits/#{id}/payouts"
|
|
|
|
begin
|
|
stripe_balances = Stripe::Balance.retrieve(stripe_account: np.stripe_account_id)
|
|
available = stripe_balances['available'].first['amount']
|
|
pending = stripe_balances['pending'].first['amount']
|
|
rescue Exception => e
|
|
available = 0
|
|
pending = 0
|
|
puts "UNRECOGNIZED STRIPE ACCOUNT ID: #{np.stripe_account_id}"
|
|
end
|
|
bal = np_balances(id)
|
|
data = {
|
|
stripe_net: available + pending,
|
|
cc_net: bal['net_amount'],
|
|
diff: bal['net_amount'] - (available + pending)
|
|
}
|
|
data
|
|
end
|
|
|
|
# Get the total gross, net
|
|
# Pretty much duped from QueryPayments
|
|
def self.np_balances(np_id)
|
|
payment_ids_expr = Qx.select('DISTINCT payments.id')
|
|
.from(:payments)
|
|
.left_join(
|
|
[:charges, 'charges.payment_id=payments.id'],
|
|
[:refunds, 'refunds.payment_id=payments.id'],
|
|
[:disputes, 'disputes.payment_id=payments.id']
|
|
)
|
|
.where('payments.nonprofit_id=$id', id: np_id)
|
|
.and_where('refunds.payment_id IS NOT NULL OR charges.payment_id IS NOT NULL OR disputes.payment_id IS NOT NULL')
|
|
.and_where(%(
|
|
(refunds.payment_id IS NOT NULL AND (refunds.disbursed IS NULL OR refunds.disbursed='f'))
|
|
OR (charges.status='available' OR charges.status='pending')
|
|
OR (disputes.status='lost')
|
|
))
|
|
Qx.select(
|
|
'coalesce(SUM(payments.gross_amount), 0) AS gross_amount',
|
|
'coalesce(SUM(payments.fee_total), 0) AS fee_total',
|
|
'coalesce(SUM(payments.net_amount), 0) AS net_amount',
|
|
'COUNT(payments.*) AS count'
|
|
)
|
|
.from(:payments)
|
|
.where('payments.id IN ($ids)', ids: payment_ids_expr)
|
|
.execute
|
|
.first
|
|
end
|
|
end
|