2019-07-30 21:29:24 +00:00
|
|
|
# frozen_string_literal: true
|
|
|
|
|
2020-06-12 20:03:43 +00:00
|
|
|
# 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
|
2018-03-25 17:30:42 +00:00
|
|
|
require 'rails_helper'
|
|
|
|
require 'support/payments_for_a_payout'
|
|
|
|
|
|
|
|
describe QueryPayments do
|
|
|
|
before :each do
|
2020-04-17 19:02:07 +00:00
|
|
|
@nonprofit = force_create(:nm_justice, name: 'npo1', id: 515152)
|
2019-07-30 21:29:24 +00:00
|
|
|
@supporters = [force_create(:supporter, name: 'supporter-0', nonprofit: @nonprofit),
|
|
|
|
force_create(:supporter, name: 'supporter-1', nonprofit: @nonprofit)]
|
2018-03-25 17:30:42 +00:00
|
|
|
|
2019-07-30 21:29:24 +00:00
|
|
|
@payments = [force_create(:payment, gross_amount: 1000, fee_total: 99, net_amount: 901, supporter: @supporters[0], nonprofit: @nonprofit),
|
|
|
|
force_create(:payment, gross_amount: 2000, fee_total: 22, net_amount: 1978, supporter: @supporters[1], nonprofit: @nonprofit)]
|
2018-03-25 17:30:42 +00:00
|
|
|
@bank_account = force_create(:bank_account, name: 'bank1', nonprofit: @nonprofit)
|
|
|
|
end
|
|
|
|
|
|
|
|
describe '.ids_for_payout' do
|
2019-07-30 21:29:24 +00:00
|
|
|
before(:each) do
|
|
|
|
Timecop.freeze(2020, 5, 5)
|
|
|
|
end
|
|
|
|
after(:each) do
|
2018-03-25 17:30:42 +00:00
|
|
|
Timecop.return
|
2019-07-30 21:29:24 +00:00
|
|
|
end
|
2018-03-25 17:30:42 +00:00
|
|
|
|
|
|
|
describe 'no date provided' do
|
|
|
|
include_context 'payments for a payout' do
|
|
|
|
let(:np) { @nonprofit }
|
2019-07-30 21:29:24 +00:00
|
|
|
let(:date_for_marking) { Time.now }
|
2018-03-25 17:30:42 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
it 'np is invalid' do
|
2019-07-30 21:29:24 +00:00
|
|
|
expect(QueryPayments.ids_for_payout(686_826_812_658_102_751_098_754)).to eq []
|
2018-03-25 17:30:42 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
it 'works without a date provided' do
|
|
|
|
all_payments
|
|
|
|
|
|
|
|
result = QueryPayments.ids_for_payout(np.id)
|
|
|
|
|
2019-07-30 21:29:24 +00:00
|
|
|
payments_for_payout = Set.new
|
|
|
|
@expect_marked[:charges].each do |c|
|
|
|
|
c.reload
|
2018-03-25 17:30:42 +00:00
|
|
|
payments_for_payout.add(c.payment.id)
|
2019-07-30 21:29:24 +00:00
|
|
|
end
|
2018-03-25 17:30:42 +00:00
|
|
|
|
2019-07-30 21:29:24 +00:00
|
|
|
@expect_marked[:disputes].each do |d|
|
|
|
|
d.reload
|
2018-03-25 17:30:42 +00:00
|
|
|
payments_for_payout.add(d.payment.id)
|
2019-07-30 21:29:24 +00:00
|
|
|
end
|
2018-03-25 17:30:42 +00:00
|
|
|
|
2019-07-30 21:29:24 +00:00
|
|
|
@expect_marked[:refunds].each do |r|
|
|
|
|
r.reload
|
2018-03-25 17:30:42 +00:00
|
|
|
payments_for_payout.add(r.payment.id)
|
2019-07-30 21:29:24 +00:00
|
|
|
end
|
2018-03-25 17:30:42 +00:00
|
|
|
|
|
|
|
expect(result).to match_array(payments_for_payout)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
describe 'with date provided' do
|
|
|
|
include_context 'payments for a payout' do
|
|
|
|
let(:np) { @nonprofit }
|
2019-07-30 21:29:24 +00:00
|
|
|
let(:date_for_marking) { Time.now - 1.day }
|
2018-03-25 17:30:42 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
it 'np is invalid' do
|
2019-07-30 21:29:24 +00:00
|
|
|
expect(QueryPayments.ids_for_payout(686_826_812_658_102_751_098_754)).to eq []
|
2018-03-25 17:30:42 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
it 'works with a date provided' do
|
|
|
|
all_payments
|
|
|
|
|
2019-07-30 21:29:24 +00:00
|
|
|
result = QueryPayments.ids_for_payout(np.id, date: Time.now - 1.day)
|
2018-03-25 17:30:42 +00:00
|
|
|
|
2019-07-30 21:29:24 +00:00
|
|
|
payments_for_payout = Set.new
|
|
|
|
@expect_marked[:charges].each do |c|
|
|
|
|
c.reload
|
2018-03-25 17:30:42 +00:00
|
|
|
payments_for_payout.add(c.payment.id)
|
2019-07-30 21:29:24 +00:00
|
|
|
end
|
2018-03-25 17:30:42 +00:00
|
|
|
|
2019-07-30 21:29:24 +00:00
|
|
|
@expect_marked[:disputes].each do |d|
|
|
|
|
d.reload
|
2018-03-25 17:30:42 +00:00
|
|
|
payments_for_payout.add(d.payment.id)
|
2019-07-30 21:29:24 +00:00
|
|
|
end
|
2018-03-25 17:30:42 +00:00
|
|
|
|
2019-07-30 21:29:24 +00:00
|
|
|
@expect_marked[:refunds].each do |r|
|
|
|
|
r.reload
|
2018-03-25 17:30:42 +00:00
|
|
|
payments_for_payout.add(r.payment.id)
|
2019-07-30 21:29:24 +00:00
|
|
|
end
|
2018-03-25 17:30:42 +00:00
|
|
|
|
|
|
|
expect(result).to match_array(payments_for_payout)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2019-07-30 21:29:24 +00:00
|
|
|
describe '.get_payout_total' do
|
2018-03-25 17:30:42 +00:00
|
|
|
include_context 'payments for a payout' do
|
|
|
|
let(:np) { @nonprofit }
|
2019-07-30 21:29:24 +00:00
|
|
|
let(:date_for_marking) { Time.now }
|
2018-03-25 17:30:42 +00:00
|
|
|
end
|
|
|
|
it 'gives empty payout result if no payments provided' do
|
|
|
|
result = QueryPayments.get_payout_totals([])
|
|
|
|
|
2019-07-30 21:29:24 +00:00
|
|
|
expected = { 'gross_amount' => 0, 'fee_total' => 0, 'net_amount' => 0 }
|
2018-03-25 17:30:42 +00:00
|
|
|
expect(result).to eq expected
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'gives correct payout info' do
|
|
|
|
all_payments
|
|
|
|
result = QueryPayments.get_payout_totals(QueryPayments.ids_for_payout(np.id))
|
2019-07-30 21:29:24 +00:00
|
|
|
expected = { gross_amount: 5500, fee_total: -1200, net_amount: 4300, count: 8 }.with_indifferent_access
|
2018-03-25 17:30:42 +00:00
|
|
|
|
|
|
|
expect(result.with_indifferent_access).to eq expected
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
describe '.for_payout' do
|
|
|
|
before(:each) do
|
2019-07-30 21:29:24 +00:00
|
|
|
gross = @payments.map { |h| h['gross_amount'] }.sum
|
|
|
|
fees = @payments.map { |h| h['fee_total'] }.sum
|
|
|
|
net = @payments.map { |h| h['net_amount'] }.sum
|
2018-03-25 17:30:42 +00:00
|
|
|
@payout = force_create(:payout, gross_amount: gross, fee_total: fees, net_amount: net, nonprofit: @nonprofit)
|
2019-07-30 21:29:24 +00:00
|
|
|
@payment_payouts = @payments.map { |p| force_create(:payment_payout, payment: p, payout: @payout) }
|
2018-03-25 17:30:42 +00:00
|
|
|
|
|
|
|
@result = QueryPayments.for_payout(@nonprofit['id'], @payout['id'])
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'sets the correct headers' do
|
2019-07-30 21:29:24 +00:00
|
|
|
expect(@result.first).to eq(%w[date gross_total fee_total net_total bank_name status])
|
2018-03-25 17:30:42 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
it 'sets the correct payout data' do
|
|
|
|
expect(@result[1].count).to eq(6) # TODO
|
|
|
|
end
|
2019-07-30 21:29:24 +00:00
|
|
|
|
|
|
|
it 'sets the payment headers', pending: true do
|
|
|
|
expect(@result[3]).to eq(['Date', 'Gross Amount', 'Fee Total', 'Net Amount', 'Type', 'Payment ID', 'Last Name', 'First Name', 'Full Name', 'Organization', 'Email', 'Phone', 'Address', 'City', 'State', 'Postal Code', 'Country', 'Anonymous?', 'Designation', 'Honorarium/Memorium', 'Comment', 'Campaign', 'Campaign Gift Level', 'Event'])
|
2018-03-25 17:30:42 +00:00
|
|
|
end
|
|
|
|
|
2019-07-30 21:29:24 +00:00
|
|
|
it 'sets the correct payment data', pending: true do
|
2018-03-25 17:30:42 +00:00
|
|
|
expect(@result[4].count).to eq 24
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
describe '.for_export_enumerable' do
|
|
|
|
it 'finishes two payment export' do
|
2019-07-30 21:29:24 +00:00
|
|
|
rows = QueryPayments.for_export_enumerable(@nonprofit.id, {}).to_a
|
2018-03-25 17:30:42 +00:00
|
|
|
|
|
|
|
headers = MockHelpers.payment_export_headers
|
|
|
|
|
|
|
|
expect(rows.length).to eq(3)
|
|
|
|
expect(rows[0]).to eq(headers)
|
|
|
|
end
|
|
|
|
end
|
2018-07-25 18:20:05 +00:00
|
|
|
|
|
|
|
describe '.full_search' do
|
|
|
|
include_context :shared_rd_donation_value_context
|
2019-07-30 21:29:24 +00:00
|
|
|
before(:each) do
|
|
|
|
nonprofit.stripe_account_id = Stripe::Account.create['id']
|
2018-07-25 18:20:05 +00:00
|
|
|
nonprofit.save!
|
|
|
|
card.stripe_customer_id = 'some other id'
|
2019-07-30 21:29:24 +00:00
|
|
|
cust = Stripe::Customer.create
|
2018-07-25 18:20:05 +00:00
|
|
|
card.stripe_customer_id = cust['id']
|
|
|
|
card.save!
|
2019-07-30 21:29:24 +00:00
|
|
|
expect(Stripe::Charge).to receive(:create).exactly(3).times.and_wrap_original { |m, *args|
|
|
|
|
a = m.call(*args)
|
|
|
|
@stripe_charge_id = a['id']
|
|
|
|
a
|
2018-07-25 18:20:05 +00:00
|
|
|
}
|
2019-07-30 21:29:24 +00:00
|
|
|
end
|
2018-07-25 18:20:05 +00:00
|
|
|
|
2019-07-30 21:29:24 +00:00
|
|
|
let(:charge_amount_small) { 200 }
|
|
|
|
let(:charge_amount_medium) { 400 }
|
|
|
|
let(:charge_amount_large) { 600 }
|
2018-07-25 18:20:05 +00:00
|
|
|
|
|
|
|
def generate_donation(h)
|
|
|
|
token = h[:token]
|
|
|
|
date = h[:date]
|
|
|
|
amount = h[:amount]
|
|
|
|
|
2019-07-30 21:29:24 +00:00
|
|
|
input = { amount: amount,
|
|
|
|
nonprofit_id: nonprofit.id,
|
|
|
|
supporter_id: supporter.id,
|
|
|
|
token: token,
|
2018-07-25 18:20:05 +00:00
|
|
|
|
2019-07-30 21:29:24 +00:00
|
|
|
date: date,
|
|
|
|
dedication: 'dedication',
|
|
|
|
designation: 'designation' }
|
|
|
|
input[:event_id] = h[:event_id] if h[:event_id]
|
2018-07-25 18:20:05 +00:00
|
|
|
|
2019-07-30 21:29:24 +00:00
|
|
|
input[:campaign_id] = h[:campaign_id] if h[:campaign_id]
|
2018-07-25 18:20:05 +00:00
|
|
|
|
|
|
|
InsertDonation.with_stripe(input)
|
|
|
|
end
|
|
|
|
|
|
|
|
describe 'general donations' do
|
2019-07-30 21:29:24 +00:00
|
|
|
let(:donation_result_yesterday) do
|
|
|
|
generate_donation(amount: charge_amount_small,
|
2018-07-25 18:20:05 +00:00
|
|
|
|
2019-07-30 21:29:24 +00:00
|
|
|
token: source_tokens[0].token,
|
|
|
|
date: (Time.now - 1.day).to_s)
|
|
|
|
end
|
2018-07-25 18:20:05 +00:00
|
|
|
|
2019-07-30 21:29:24 +00:00
|
|
|
let(:donation_result_today) do
|
|
|
|
generate_donation(amount: charge_amount_medium,
|
2018-07-25 18:20:05 +00:00
|
|
|
|
2019-07-30 21:29:24 +00:00
|
|
|
token: source_tokens[1].token,
|
2018-07-25 18:20:05 +00:00
|
|
|
|
2019-07-30 21:29:24 +00:00
|
|
|
date: Time.now.to_s)
|
|
|
|
end
|
2018-07-25 18:20:05 +00:00
|
|
|
|
2019-07-30 21:29:24 +00:00
|
|
|
let(:donation_result_tomorrow) do
|
|
|
|
generate_donation(amount: charge_amount_large,
|
2018-07-25 18:20:05 +00:00
|
|
|
|
2019-07-30 21:29:24 +00:00
|
|
|
token: source_tokens[2].token,
|
|
|
|
date: (Time.now - 1.day).to_s)
|
|
|
|
end
|
2018-07-25 18:20:05 +00:00
|
|
|
|
2019-07-30 21:29:24 +00:00
|
|
|
let (:first_refund_of_yesterday) do
|
|
|
|
charge = donation_result_yesterday['charge']
|
2018-07-25 18:20:05 +00:00
|
|
|
|
2019-07-30 21:29:24 +00:00
|
|
|
InsertRefunds.with_stripe(charge.attributes, { amount: 100 }.with_indifferent_access)
|
|
|
|
end
|
2018-07-25 18:20:05 +00:00
|
|
|
|
2019-07-30 21:29:24 +00:00
|
|
|
let(:second_refund_of_yesterday) do
|
|
|
|
charge = donation_result_yesterday['charge']
|
2018-07-25 18:20:05 +00:00
|
|
|
|
2019-07-30 21:29:24 +00:00
|
|
|
InsertRefunds.with_stripe(charge.attributes, { amount: 50 }.with_indifferent_access)
|
|
|
|
end
|
2018-07-25 18:20:05 +00:00
|
|
|
|
|
|
|
it 'empty filter returns all' do
|
|
|
|
donation_result_yesterday
|
|
|
|
donation_result_today
|
|
|
|
donation_result_tomorrow
|
|
|
|
first_refund_of_yesterday
|
|
|
|
second_refund_of_yesterday
|
|
|
|
|
2019-07-30 21:29:24 +00:00
|
|
|
result = QueryPayments.full_search(nonprofit.id, {})
|
2018-07-25 18:20:05 +00:00
|
|
|
|
|
|
|
expect(result[:data].count).to eq 5
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
describe 'event donations' do
|
2019-07-30 21:29:24 +00:00
|
|
|
let(:donation_result_yesterday) do
|
2018-07-25 18:20:05 +00:00
|
|
|
generate_donation(amount: charge_amount_small,
|
|
|
|
event_id: event.id,
|
|
|
|
token: source_tokens[0].token,
|
|
|
|
date: (Time.now - 1.day).to_s)
|
2019-07-30 21:29:24 +00:00
|
|
|
end
|
2018-07-25 18:20:05 +00:00
|
|
|
|
2019-07-30 21:29:24 +00:00
|
|
|
let(:donation_result_today) do
|
|
|
|
generate_donation(amount: charge_amount_medium,
|
2018-07-25 18:20:05 +00:00
|
|
|
event_id: event.id,
|
|
|
|
token: source_tokens[1].token,
|
|
|
|
|
2019-07-30 21:29:24 +00:00
|
|
|
date: Time.now.to_s)
|
|
|
|
end
|
2018-07-25 18:20:05 +00:00
|
|
|
|
2019-07-30 21:29:24 +00:00
|
|
|
let(:donation_result_tomorrow) do
|
2018-07-25 18:20:05 +00:00
|
|
|
generate_donation(amount: charge_amount_large,
|
|
|
|
|
|
|
|
token: source_tokens[2].token,
|
2019-07-30 21:29:24 +00:00
|
|
|
date: (Time.now - 1.day).to_s)
|
|
|
|
end
|
2018-07-25 18:20:05 +00:00
|
|
|
|
2019-07-30 21:29:24 +00:00
|
|
|
let (:first_refund_of_yesterday) do
|
|
|
|
charge = donation_result_yesterday['charge']
|
2018-07-25 18:20:05 +00:00
|
|
|
|
2019-07-30 21:29:24 +00:00
|
|
|
InsertRefunds.with_stripe(charge.attributes, { amount: 100 }.with_indifferent_access)
|
|
|
|
end
|
2018-07-25 18:20:05 +00:00
|
|
|
|
2019-07-30 21:29:24 +00:00
|
|
|
let(:second_refund_of_yesterday) do
|
|
|
|
charge = donation_result_yesterday['charge']
|
2018-07-25 18:20:05 +00:00
|
|
|
|
2019-07-30 21:29:24 +00:00
|
|
|
InsertRefunds.with_stripe(charge.attributes, { amount: 50 }.with_indifferent_access)
|
|
|
|
end
|
2018-07-25 18:20:05 +00:00
|
|
|
|
|
|
|
it 'search includes refunds for that event ' do
|
|
|
|
donation_result_yesterday
|
|
|
|
donation_result_today
|
|
|
|
donation_result_tomorrow
|
|
|
|
first_refund_of_yesterday
|
|
|
|
second_refund_of_yesterday
|
|
|
|
|
2019-07-30 21:29:24 +00:00
|
|
|
result = QueryPayments.full_search(nonprofit.id, event_id: event.id)
|
2018-07-25 18:20:05 +00:00
|
|
|
|
|
|
|
expect(result[:data].count).to eq 4
|
2019-07-30 21:29:24 +00:00
|
|
|
expect(result[:data]).to_not satisfy { |i| i.any? { |j| j['id'] == donation_result_tomorrow['payment']['id'] } }
|
2018-07-25 18:20:05 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
describe 'campaign donations' do
|
2019-07-30 21:29:24 +00:00
|
|
|
let(:donation_result_yesterday) do
|
2018-07-25 18:20:05 +00:00
|
|
|
generate_donation(amount: charge_amount_small,
|
2019-07-30 21:29:24 +00:00
|
|
|
campaign_id: campaign.id,
|
2018-07-25 18:20:05 +00:00
|
|
|
token: source_tokens[0].token,
|
|
|
|
date: (Time.now - 1.day).to_s)
|
2019-07-30 21:29:24 +00:00
|
|
|
end
|
2018-07-25 18:20:05 +00:00
|
|
|
|
2019-07-30 21:29:24 +00:00
|
|
|
let(:donation_result_today) do
|
|
|
|
generate_donation(amount: charge_amount_medium,
|
|
|
|
campaign_id: campaign.id,
|
2018-07-25 18:20:05 +00:00
|
|
|
token: source_tokens[1].token,
|
|
|
|
|
2019-07-30 21:29:24 +00:00
|
|
|
date: Time.now.to_s)
|
|
|
|
end
|
2018-07-25 18:20:05 +00:00
|
|
|
|
2019-07-30 21:29:24 +00:00
|
|
|
let(:donation_result_tomorrow) do
|
2018-07-25 18:20:05 +00:00
|
|
|
generate_donation(amount: charge_amount_large,
|
|
|
|
|
|
|
|
token: source_tokens[2].token,
|
2019-07-30 21:29:24 +00:00
|
|
|
date: (Time.now - 1.day).to_s)
|
|
|
|
end
|
2018-07-25 18:20:05 +00:00
|
|
|
|
2019-07-30 21:29:24 +00:00
|
|
|
let (:first_refund_of_yesterday) do
|
|
|
|
charge = donation_result_yesterday['charge']
|
2018-07-25 18:20:05 +00:00
|
|
|
|
2019-07-30 21:29:24 +00:00
|
|
|
InsertRefunds.with_stripe(charge.attributes, { amount: 100 }.with_indifferent_access)
|
|
|
|
end
|
2018-07-25 18:20:05 +00:00
|
|
|
|
2019-07-30 21:29:24 +00:00
|
|
|
let(:second_refund_of_yesterday) do
|
|
|
|
charge = donation_result_yesterday['charge']
|
2018-07-25 18:20:05 +00:00
|
|
|
|
2019-07-30 21:29:24 +00:00
|
|
|
InsertRefunds.with_stripe(charge.attributes, { amount: 50 }.with_indifferent_access)
|
|
|
|
end
|
2018-07-25 18:20:05 +00:00
|
|
|
|
|
|
|
it 'search includes refunds for that campaign ' do
|
|
|
|
donation_result_yesterday
|
|
|
|
donation_result_today
|
|
|
|
donation_result_tomorrow
|
|
|
|
first_refund_of_yesterday
|
|
|
|
second_refund_of_yesterday
|
|
|
|
|
2019-07-30 21:29:24 +00:00
|
|
|
result = QueryPayments.full_search(nonprofit.id, campaign_id: campaign.id)
|
2018-07-25 18:20:05 +00:00
|
|
|
|
|
|
|
expect(result[:data].count).to eq 4
|
2019-07-30 21:29:24 +00:00
|
|
|
expect(result[:data]).to_not satisfy { |i| i.any? { |j| j['id'] == donation_result_tomorrow['payment']['id'] } }
|
2018-07-25 18:20:05 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
2018-03-25 17:30:42 +00:00
|
|
|
end
|