457 lines
15 KiB
Ruby
457 lines
15 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
# License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later
|
|
# holy cow, this is confusing
|
|
RSpec.shared_context :shared_rd_donation_value_context do
|
|
include_context :shared_donation_charge_context
|
|
|
|
let(:fake_uuid) { '53a6bc06-0789-11e8-bb3f-f34cac607737' }
|
|
let(:valid_uuid) { 'fcf61bac-078a-11e8-aa53-cba5bdb8dcdd' }
|
|
let(:other_uuid) { 'a713018c-078f-11e8-ae3b-bf5007844fea' }
|
|
let(:source_token) { force_create(:source_token, tokenizable: card, expiration: Time.now + 1.day, max_uses: 1, token: valid_uuid) }
|
|
let(:source_tokens) do
|
|
(0..10).map do |_i|
|
|
force_create(:source_token, tokenizable: card, expiration: Time.now + 1.day, max_uses: 1, token: SecureRandom.uuid)
|
|
end
|
|
end
|
|
|
|
let(:other_source_token) { force_create(:source_token, tokenizable: card_for_other_supporter, expiration: Time.now + 1.day, max_uses: 1, token: other_uuid) }
|
|
|
|
let(:charge_amount) { 100 }
|
|
|
|
let(:default_edit_token) { '7903e34c-10fe-11e8-9ead-d302c690bee4' }
|
|
before(:each) do
|
|
allow_any_instance_of(Event).to receive(:geocode).and_return([1, 1])
|
|
end
|
|
|
|
def generate_expected(donation_id, payment_id, charge_id, card, supporter, nonprofit, stripe_charge_id, data = {})
|
|
payment_stuff = {}
|
|
payment_stuff[:card_id] = card.id if card.is_a? Card
|
|
payment_stuff[:direct_debit_detail_id] = card.id if card.is_a? DirectDebitDetail
|
|
payment_stuff[:provider] = card.is_a?(Card) ? 'credit_card' : 'sepa'
|
|
payment_stuff[:fee] = card.is_a?(Card) ? 33 : 0
|
|
|
|
result = {
|
|
donation: {
|
|
id: donation_id,
|
|
nonprofit_id: nonprofit.id,
|
|
supporter_id: supporter.id,
|
|
|
|
card_id: payment_stuff[:card_id],
|
|
|
|
date: Time.now,
|
|
created_at: Time.now,
|
|
updated_at: Time.now,
|
|
event_id: data[:event] ? event.id : nil,
|
|
campaign_id: data[:campaign] ? campaign.id : nil,
|
|
anonymous: nil,
|
|
amount: charge_amount,
|
|
comment: nil,
|
|
category: nil,
|
|
dedication: 'dedication',
|
|
designation: 'designation',
|
|
imported_at: nil,
|
|
manual: nil,
|
|
offsite: nil,
|
|
recurring: nil,
|
|
recurring_donation_id: nil,
|
|
origin_url: nil,
|
|
payment_id: nil,
|
|
profile_id: nil,
|
|
|
|
charge_id: nil,
|
|
payment_provider: payment_stuff[:provider],
|
|
queued_for_import_at: nil,
|
|
direct_debit_detail_id: payment_stuff[:direct_debit_detail_id]
|
|
}
|
|
|
|
}.with_indifferent_access
|
|
|
|
unless payment_id.nil?
|
|
result[:activity] = {}
|
|
|
|
result[:payment] = {
|
|
date: Time.now,
|
|
donation_id: donation_id,
|
|
fee_total: -payment_stuff[:fee],
|
|
gross_amount: 100,
|
|
id: payment_id || 55_555,
|
|
kind: data[:recurring_donation] ? 'RecurringDonation' : 'Donation',
|
|
net_amount: 100 - payment_stuff[:fee],
|
|
nonprofit_id: nonprofit.id,
|
|
refund_total: 0,
|
|
supporter_id: supporter.id,
|
|
towards: 'designation',
|
|
created_at: Time.now,
|
|
updated_at: Time.now,
|
|
search_vectors: nil
|
|
}
|
|
result[:charge] = {
|
|
id: charge_id || 55_555,
|
|
amount: charge_amount,
|
|
|
|
card_id: payment_stuff[:card_id],
|
|
created_at: Time.now,
|
|
updated_at: Time.now,
|
|
stripe_charge_id: stripe_charge_id,
|
|
fee: payment_stuff[:fee],
|
|
|
|
disbursed: nil,
|
|
failure_message: nil,
|
|
payment_id: payment_id || 55_555,
|
|
nonprofit_id: nonprofit.id,
|
|
status: 'pending',
|
|
profile_id: nil,
|
|
supporter_id: supporter.id,
|
|
ticket_id: nil,
|
|
|
|
donation_id: donation_id,
|
|
direct_debit_detail_id: payment_stuff[:direct_debit_detail_id]
|
|
|
|
}
|
|
end
|
|
|
|
if data[:recurring_donation]
|
|
result[:recurring_donation] = {
|
|
id: data[:recurring_donation].id,
|
|
active: true,
|
|
paydate: data[:recurring_donation_expected][:paydate],
|
|
interval: data[:recurring_donation_expected][:interval],
|
|
time_unit: data[:recurring_donation_expected][:time_unit],
|
|
start_date: data[:recurring_donation_expected][:start_date],
|
|
end_date: nil,
|
|
n_failures: 0,
|
|
edit_token: default_edit_token,
|
|
cancelled_by: nil,
|
|
cancelled_at: nil,
|
|
donation_id: donation_id,
|
|
nonprofit_id: nonprofit.id,
|
|
created_at: Time.now,
|
|
updated_at: Time.now,
|
|
failure_message: nil,
|
|
origin_url: nil,
|
|
amount: charge_amount,
|
|
supporter_id: supporter.id,
|
|
|
|
# removable fields
|
|
card_id: nil,
|
|
campaign_id: nil,
|
|
anonymous: nil,
|
|
email: supporter.email,
|
|
profile_id: nil
|
|
|
|
}
|
|
|
|
end
|
|
|
|
result
|
|
end
|
|
|
|
def generate_expected_refund(_data = {})
|
|
result = {}.with_indifferent_access
|
|
result
|
|
end
|
|
|
|
def validation_unauthorized
|
|
expect(QuerySourceToken).to receive(:get_and_increment_source_token).with(fake_uuid, nil).and_raise(AuthenticationError)
|
|
expect { yield() }.to raise_error { |e|
|
|
expect(e).to be_a(AuthenticationError)
|
|
}
|
|
end
|
|
|
|
def validation_expired
|
|
expect(QuerySourceToken).to receive(:get_and_increment_source_token).with(fake_uuid, nil).and_raise(ExpiredTokenError)
|
|
expect { yield() }.to raise_error { |e|
|
|
expect(e).to be_a(ExpiredTokenError)
|
|
}
|
|
end
|
|
|
|
def validation_basic_validation
|
|
expect { yield() }.to raise_error { |e|
|
|
expect(e).to be_a(ParamValidation::ValidationError)
|
|
expect(e.message).to start_with 'amount'
|
|
expect_validation_errors(e.data, [
|
|
{ key: :amount, name: :required },
|
|
{ key: :amount, name: :is_integer },
|
|
{ key: :nonprofit_id, name: :required },
|
|
{ key: :nonprofit_id, name: :is_reference },
|
|
{ key: :supporter_id, name: :required },
|
|
{ key: :supporter_id, name: :is_reference },
|
|
{ key: :designation, name: :is_a },
|
|
{ key: :dedication, name: :is_a },
|
|
{ key: :campaign_id, name: :is_reference },
|
|
{ key: :event_id, name: :is_reference },
|
|
{ key: :token, name: :required },
|
|
{ key: :token, name: :format }
|
|
])
|
|
}
|
|
end
|
|
|
|
def validation_invalid_token
|
|
expect { yield() }.to raise_error { |e|
|
|
expect(e).to be_a(ParamValidation::ValidationError)
|
|
expect(e.message).to eq "#{fake_uuid} doesn't represent a valid source"
|
|
}
|
|
end
|
|
|
|
def find_error_supporter
|
|
expect { yield() }.to raise_error { |e|
|
|
expect(e).to be_a ParamValidation::ValidationError
|
|
|
|
expect_validation_errors(e.data, [{ key: :supporter_id }])
|
|
}
|
|
end
|
|
|
|
def find_error_nonprofit
|
|
expect { yield() }.to raise_error { |e|
|
|
expect(e).to be_a ParamValidation::ValidationError
|
|
expect_validation_errors(e.data, [{ key: :nonprofit_id }])
|
|
}
|
|
end
|
|
|
|
def find_error_campaign
|
|
expect { yield() }.to raise_error { |e|
|
|
expect(e).to be_a ParamValidation::ValidationError
|
|
|
|
expect_validation_errors(e.data, [{ key: :campaign_id }])
|
|
}
|
|
end
|
|
|
|
def find_error_event
|
|
expect { yield() }.to raise_error { |e|
|
|
expect(e).to be_a ParamValidation::ValidationError
|
|
expect_validation_errors(e.data, [{ key: :event_id }])
|
|
}
|
|
end
|
|
|
|
def find_error_ticket
|
|
expect { yield() }.to raise_error { |e|
|
|
expect(e).to be_a ParamValidation::ValidationError
|
|
expect_validation_errors(e.data, [{ key: :ticket_id }])
|
|
}
|
|
end
|
|
|
|
def find_error_profile
|
|
expect { yield() }.to raise_error { |e|
|
|
expect(e).to be_a ParamValidation::ValidationError
|
|
expect_validation_errors(e.data, [{ key: :profile_id }])
|
|
}
|
|
end
|
|
|
|
def validation_supporter_deleted
|
|
supporter
|
|
supporter.deleted = true
|
|
supporter.save!
|
|
expect { yield }.to raise_error { |e|
|
|
expect(e).to be_a ParamValidation::ValidationError
|
|
expect(e.message).to include 'deleted'
|
|
expect_validation_errors(e.data, [{ key: :supporter_id }])
|
|
}
|
|
end
|
|
|
|
def validation_event_deleted
|
|
event.deleted = true
|
|
event.save!
|
|
|
|
expect { yield }.to raise_error { |error|
|
|
expect(error).to be_a ParamValidation::ValidationError
|
|
expect_validation_errors(error.data, [{ key: :event_id }])
|
|
expect(error.message).to include 'deleted'
|
|
expect(error.message).to include "Event #{event.id}"
|
|
}
|
|
end
|
|
|
|
def validation_campaign_deleted
|
|
campaign.deleted = true
|
|
campaign.save!
|
|
|
|
expect { yield }.to raise_error { |error|
|
|
expect(error).to be_a ParamValidation::ValidationError
|
|
expect_validation_errors(error.data, [{ key: :campaign_id }])
|
|
expect(error.message).to include 'deleted'
|
|
expect(error.message).to include "Campaign #{campaign.id}"
|
|
}
|
|
end
|
|
|
|
def validation_supporter_not_with_nonprofit
|
|
expect { yield }.to raise_error { |e|
|
|
expect(e).to be_a ParamValidation::ValidationError
|
|
expect(e.message).to include 'Supporter'
|
|
expect(e.message).to include 'does not belong to nonprofit'
|
|
expect_validation_errors(e.data, [{ key: :supporter_id }])
|
|
}
|
|
end
|
|
|
|
def validation_campaign_not_with_nonprofit
|
|
expect { yield }.to raise_error { |e|
|
|
expect(e).to be_a ParamValidation::ValidationError
|
|
expect(e.message).to include 'Campaign'
|
|
expect(e.message).to include 'does not belong to nonprofit'
|
|
expect_validation_errors(e.data, [{ key: :campaign_id }])
|
|
}
|
|
end
|
|
|
|
def validation_event_not_with_nonprofit
|
|
expect { yield }.to raise_error { |e|
|
|
expect(e).to be_a ParamValidation::ValidationError
|
|
expect(e.message).to include 'Event'
|
|
expect(e.message).to include 'does not belong to nonprofit'
|
|
expect_validation_errors(e.data, [{ key: :event_id }])
|
|
}
|
|
end
|
|
|
|
def validation_card_not_with_supporter
|
|
expect { yield }.to raise_error { |e|
|
|
expect(e).to be_a ParamValidation::ValidationError
|
|
expect(e.message).to include 'Supporter'
|
|
expect(e.message).to include 'does not own card'
|
|
expect_validation_errors(e.data, [{ key: :token }])
|
|
}
|
|
end
|
|
|
|
def handle_charge_failed
|
|
failure_message = 'failure message'
|
|
|
|
expect(InsertCharge).to receive(:with_stripe).and_return('charge' => { 'status' => 'failed', 'failure_message' => failure_message })
|
|
|
|
expect { yield }.to raise_error { |e|
|
|
expect(e).to be_a ChargeError
|
|
expect(e.message).to eq failure_message
|
|
|
|
expect(Donation.count).to eq 0
|
|
expect(Charge.count).to eq 0
|
|
expect(Activity.count).to eq 0
|
|
expect(Payment.count).to eq 0
|
|
}
|
|
end
|
|
|
|
def before_each_success(expect_charge = true)
|
|
expect(InsertDonation).to receive(:insert_donation).and_wrap_original do |m, *args|
|
|
expect {
|
|
result = m.call(*args)
|
|
}.to have_enqueued_job(PaymentNotificationJob).with(result, supporter.local)
|
|
@donation_id = result.id
|
|
expect_email_queued.with(JobTypes::NonprofitPaymentNotificationJob, @donation_id)
|
|
|
|
expect(QueueDonations).to receive(:execute_for_donation).with(@donation_id)
|
|
|
|
result
|
|
end
|
|
|
|
if expect_charge
|
|
nonprofit.stripe_account_id = Stripe::Account.create['id']
|
|
nonprofit.save!
|
|
card.stripe_customer_id = 'some other id'
|
|
cust = Stripe::Customer.create
|
|
card.stripe_customer_id = cust['id']
|
|
card.save!
|
|
|
|
expect(Stripe::Charge).to receive(:create).and_wrap_original { |m, *args|
|
|
a = m.call(*args)
|
|
@stripe_charge_id = a['id']
|
|
a
|
|
}
|
|
end
|
|
end
|
|
|
|
def before_each_successful_refund
|
|
expect(InsertRefund).to receive(:with_stripe).and_wrap_original do |m, *args|
|
|
result = m.call(*args)
|
|
@all_refunds&.push(result) || @all_refunds = [result]
|
|
@fifo_refunds&.unshift(result) || @fifo_refunds = [result]
|
|
|
|
result
|
|
end
|
|
|
|
expect(Stripe::Refund).to receive(:create).and_wrap_original do |m, *args|
|
|
a = m.call(*args)
|
|
@stripe_refund_ids&.unshift(a['id']) || @stripe_refund_ids = [a['id']]
|
|
a
|
|
end
|
|
end
|
|
|
|
def before_each_sepa_success
|
|
expect(InsertDonation).to receive(:insert_donation).and_wrap_original do |m, *args|
|
|
expect {
|
|
result = m.call(*args)
|
|
}.to have_enqueued_job(DirectDebitCreateJob).with(result.id, supporter.local)
|
|
|
|
|
|
@donation_id = result.id
|
|
expect_email_queued.with(JobTypes::NonprofitPaymentNotificationJob, @donation_id)
|
|
expect(QueueDonations).to receive(:execute_for_donation).with(@donation_id)
|
|
result
|
|
end
|
|
end
|
|
|
|
def process_event_donation(data = {})
|
|
pay_method = data[:sepa] ? direct_debit_detail : card
|
|
result = yield
|
|
expected = generate_expected(@donation_id, result['payment'].id, result['charge'].id, pay_method, supporter, nonprofit, @stripe_charge_id, event: event, recurring_donation_expected: data[:recurring_donation], recurring_donation: result['recurring_donation'])
|
|
|
|
expect(result.count).to eq expected.count
|
|
expect(result['donation'].attributes).to eq expected[:donation]
|
|
expect(result['charge'].attributes).to eq expected[:charge]
|
|
# expect(result[:json]['activity']).to eq expected[:activity]
|
|
expect(result['payment'].attributes).to eq expected[:payment]
|
|
if data[:recurring_donation]
|
|
expect(result['recurring_donation'].attributes).to eq expected[:recurring_donation]
|
|
end
|
|
|
|
result
|
|
end
|
|
|
|
def process_campaign_donation(data = {})
|
|
pay_method = data[:sepa] ? direct_debit_detail : card
|
|
result = yield
|
|
expected = generate_expected(@donation_id, result['payment'].id, result['charge'].id, pay_method, supporter, nonprofit, @stripe_charge_id, campaign: campaign, recurring_donation_expected: data[:recurring_donation], recurring_donation: result['recurring_donation'])
|
|
|
|
expect(result.count).to eq expected.count
|
|
expect(result['donation'].attributes).to eq expected[:donation]
|
|
expect(result['charge'].attributes).to eq expected[:charge]
|
|
# expect(result[:json]['activity']).to eq expected[:activity]
|
|
expect(result['payment'].attributes).to eq expected[:payment]
|
|
if data[:recurring_donation]
|
|
expect(result['recurring_donation'].attributes).to eq expected[:recurring_donation]
|
|
end
|
|
result
|
|
end
|
|
|
|
def process_general_donation(data = {})
|
|
pay_method = data[:sepa] ? direct_debit_detail : card
|
|
result = yield
|
|
expect_payment = nil_or_true(data[:expect_payment])
|
|
expect_charge = nil_or_true(data[:expect_charge])
|
|
|
|
expected = generate_expected(@donation_id, nil_or_true(data[:expect_payment]) ? result['payment'].id : nil, nil_or_true(data[:expect_payment]) ? result['charge'].id : nil, pay_method, supporter, nonprofit, @stripe_charge_id, recurring_donation_expected: data[:recurring_donation], recurring_donation: result['recurring_donation'])
|
|
|
|
expected['donation'][:profile_id] = profile.id
|
|
expect(result.count).to eq expected.count
|
|
expect(result['donation'].attributes).to eq expected[:donation]
|
|
expect(result['charge'].attributes).to eq expected[:charge] if expect_charge
|
|
# expect(result[:json]['activity']).to eq expected[:activity]
|
|
|
|
if expect_payment
|
|
expect(result['payment'].attributes).to eq expected[:payment]
|
|
end
|
|
|
|
if data[:recurring_donation]
|
|
expect(result['recurring_donation'].attributes).to eq expected[:recurring_donation]
|
|
end
|
|
result
|
|
end
|
|
|
|
def process_general_refund(_data = {})
|
|
result = yield
|
|
|
|
expected = generate_expected_refund
|
|
|
|
expect(result['payment']).to eq expected[:payment]
|
|
expect(result['refund']).to eq expected[:refund]
|
|
result
|
|
end
|
|
|
|
def nil_or_true(item)
|
|
item.nil? || item
|
|
end
|
|
end
|