6772312ea7
The primary license of the project is changing to: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later with some specific files to be licensed under the one of two licenses: CC0-1.0 LGPL-3.0-or-later This commit is one of the many steps to relicense the entire codebase. Documentation granting permission for this relicensing (from all past contributors who hold copyrights) is on file with Software Freedom Conservancy, Inc.
534 lines
26 KiB
Ruby
534 lines
26 KiB
Ruby
# License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later
|
|
require 'rails_helper'
|
|
require 'stripe_mock'
|
|
|
|
describe InsertCharge do
|
|
include_context :shared_donation_charge_context
|
|
let!(:donation) {force_create(:donation, id: 555)}
|
|
describe '.with_stripe' do
|
|
before(:each){
|
|
Settings.payment_provider.stripe_connect = true
|
|
}
|
|
describe 'param validation' do
|
|
it 'does basic validation' do
|
|
expect { InsertCharge.with_stripe(nil) }.to(raise_error {|error|
|
|
expect(error).to be_a ParamValidation::ValidationError
|
|
expect_validation_errors(error.data,
|
|
[
|
|
{:key => :amount, :name => :required},
|
|
{:key => :amount, :name => :is_integer},
|
|
{:key => :amount, :name => :min},
|
|
{:key => :nonprofit_id, :name => :required},
|
|
{:key => :nonprofit_id, :name => :is_integer},
|
|
{:key => :supporter_id, :name => :required},
|
|
{:key => :supporter_id, :name => :is_integer},
|
|
{:key => :card_id, :name => :required},
|
|
{:key => :card_id, :name => :is_integer},
|
|
{:key => :statement, :name => :required},
|
|
{:key => :statement, :name => :not_blank}
|
|
])
|
|
})
|
|
end
|
|
|
|
it 'verify the amount minimum works' do
|
|
expect { InsertCharge.with_stripe({amount: -1}) }.to(raise_error {|error|
|
|
expect(error).to be_a ParamValidation::ValidationError
|
|
expect_validation_errors(error.data,
|
|
[
|
|
{:key => :amount, :name => :min},
|
|
{:key => :nonprofit_id, :name => :required},
|
|
{:key => :nonprofit_id, :name => :is_integer},
|
|
{:key => :supporter_id, :name => :required},
|
|
{:key => :supporter_id, :name => :is_integer},
|
|
{:key => :card_id, :name => :required},
|
|
{:key => :card_id, :name => :is_integer},
|
|
{:key => :statement, :name => :required},
|
|
{:key => :statement, :name => :not_blank}
|
|
|
|
])
|
|
})
|
|
end
|
|
|
|
it 'verify that we check for valid nonprofit' do
|
|
expect { InsertCharge.with_stripe({amount: 100,
|
|
:nonprofit_id => 5555,
|
|
:supporter_id => 5555,
|
|
:card_id => 5555,
|
|
:statement => 'our statement'}) }.to(raise_error {|error|
|
|
expect(error).to be_a ParamValidation::ValidationError
|
|
expect_validation_errors(error.data,
|
|
[
|
|
{:key => :nonprofit_id}
|
|
])
|
|
})
|
|
end
|
|
|
|
it 'verify that we check for valid supporter' do
|
|
expect { InsertCharge.with_stripe({amount: 100,
|
|
:nonprofit_id => nonprofit.id,
|
|
:supporter_id => 5555,
|
|
:card_id => 5555,
|
|
:statement => 'our statement'}) }.to(raise_error {|error|
|
|
expect(error).to be_a ParamValidation::ValidationError
|
|
expect_validation_errors(error.data,
|
|
[
|
|
{:key => :supporter_id}
|
|
])
|
|
})
|
|
end
|
|
it 'verify that we check for valid card' do
|
|
expect { InsertCharge.with_stripe({amount: 100,
|
|
:nonprofit_id => nonprofit.id,
|
|
:supporter_id => supporter.id,
|
|
:card_id => 5555,
|
|
:statement => 'our statement'}) }.to(raise_error {|error|
|
|
expect(error).to be_a ParamValidation::ValidationError
|
|
expect_validation_errors(error.data,
|
|
[
|
|
{:key => :card_id}
|
|
])
|
|
})
|
|
end
|
|
|
|
it 'verify that we check that the supporter belongs to the correct nonprofit' do
|
|
expect { InsertCharge.with_stripe({amount: 100,
|
|
:nonprofit_id => other_nonprofit.id,
|
|
:supporter_id => supporter.id,
|
|
:card_id => card.id,
|
|
:statement => 'our statement'}) }.to(raise_error {|error|
|
|
expect(error).to be_a ParamValidation::ValidationError
|
|
expect(error.message).to eq "#{supporter.id} does not belong to this nonprofit #{other_nonprofit.id}"
|
|
expect_validation_errors(error.data,
|
|
[
|
|
{:key => :supporter_id}
|
|
])
|
|
})
|
|
end
|
|
|
|
it 'verify that we check that the card belongs to the correct supporter' do
|
|
expect { InsertCharge.with_stripe({amount: 100,
|
|
:nonprofit_id => nonprofit.id,
|
|
:supporter_id => supporter.id,
|
|
:card_id => card_for_other_supporter.id,
|
|
:statement => 'our statement'}) }.to(raise_error {|error|
|
|
expect(error).to be_a ParamValidation::ValidationError
|
|
expect(error.message).to eq "#{card_for_other_supporter.id} does not belong to this supporter #{supporter.id}"
|
|
expect_validation_errors(error.data,
|
|
[
|
|
{:key => :card_id}
|
|
])
|
|
})
|
|
end
|
|
end
|
|
|
|
describe 'handle StripeAccount Find and Create failure' do
|
|
before(:each){
|
|
StripeMock.prepare_error(Stripe::StripeError.new("chaos"), :new_account)
|
|
}
|
|
it 'does it fail properly' do
|
|
expect{ InsertCharge.with_stripe(amount: 100,
|
|
:nonprofit_id => nonprofit.id,
|
|
:supporter_id => supporter.id,
|
|
:card_id => card.id,
|
|
:statement => 'our statement') }.to( raise_error{|error|
|
|
expect(error).to be_a Stripe::StripeError
|
|
})
|
|
|
|
expect(Charge).to_not be_exists
|
|
expect(Payment).to_not be_exists
|
|
end
|
|
end
|
|
|
|
describe 'charge when customer belongs to client' do
|
|
before(:each){
|
|
nonprofit.stripe_account_id = Stripe::Account.create()['id']
|
|
nonprofit.save!
|
|
card.stripe_customer_id = 'some other id'
|
|
card.save!
|
|
StripeMock.prepare_error(Stripe::StripeError.new("chaos"), :get_customer)
|
|
}
|
|
|
|
it 'handles card error' do
|
|
|
|
expect(Stripe::Charge).to receive(:create).with({application_fee: 33,
|
|
customer: card.stripe_customer_id,
|
|
amount: 100,
|
|
currency: 'usd',
|
|
description: 'our statement<> blah-no-way',
|
|
statement_descriptor: 'our statement blah-n',
|
|
metadata: nil
|
|
}, {stripe_account: nonprofit.stripe_account_id}).and_wrap_original{|m, *args| m.call(*args)}
|
|
StripeMock.prepare_card_error(:card_declined)
|
|
|
|
finished_result = InsertCharge.with_stripe(amount: 100,
|
|
:nonprofit_id => nonprofit.id,
|
|
:supporter_id => supporter.id,
|
|
:card_id => card.id,
|
|
:statement => 'our statement<> blah-no-way')
|
|
|
|
common_expected = {id: Charge.first.id, amount: 100, fee: 33, stripe_charge_id: nil, status: 'failed', failure_message: 'There was an error with your card: The card was declined', created_at: Time.now, updated_at: Time.now, disbursed: nil}
|
|
|
|
|
|
result_expected = common_expected.merge({card_id: card.id, nonprofit_id: nonprofit.id, donation_id: nil, supporter_id: supporter.id, ticket_id: nil, payment_id: nil, profile_id: nil, direct_debit_detail_id: nil}).with_indifferent_access
|
|
|
|
expect(finished_result['charge'].attributes).to eq result_expected
|
|
expect(Charge.first.attributes).to eq result_expected
|
|
|
|
expect(Payment).to_not be_exists
|
|
|
|
|
|
end
|
|
|
|
it 'handles general Stripe error' do
|
|
|
|
expect(Stripe::Charge).to receive(:create).with({application_fee: 33,
|
|
customer: card.stripe_customer_id,
|
|
amount: 100,
|
|
currency: 'usd',
|
|
description: 'our statement<> blah-no-way',
|
|
statement_descriptor: 'our statement blah-n',
|
|
metadata: nil
|
|
}, {stripe_account: nonprofit.stripe_account_id}).and_wrap_original{|m, *args| m.call(*args)}
|
|
StripeMock.prepare_error(Stripe::StripeError.new("blah"), :new_charge)
|
|
|
|
finished_result = InsertCharge.with_stripe(amount: 100,
|
|
:nonprofit_id => nonprofit.id,
|
|
:supporter_id => supporter.id,
|
|
:card_id => card.id,
|
|
:statement => 'our statement<> blah-no-way')
|
|
|
|
common_expected = {id: Charge.first.id, amount: 100, fee: 33, stripe_charge_id: nil, status: 'failed', failure_message: "We're sorry, but something went wrong. We've been notified about this issue.", created_at: Time.now, updated_at: Time.now, disbursed: nil}
|
|
|
|
|
|
result_expected = common_expected.merge({card_id: card.id, nonprofit_id: nonprofit.id, donation_id: nil, supporter_id: supporter.id, ticket_id: nil, payment_id: nil, profile_id: nil, direct_debit_detail_id: nil}).with_indifferent_access
|
|
|
|
|
|
expect(finished_result['charge'].attributes).to eq result_expected
|
|
expect(Charge.first.attributes).to eq result_expected
|
|
|
|
expect(Payment).to_not be_exists
|
|
|
|
end
|
|
describe 'input success' do
|
|
|
|
|
|
let(:valid_input) { {amount: 100,
|
|
:nonprofit_id => nonprofit.id,
|
|
:supporter_id => supporter.id,
|
|
:card_id => card.id,
|
|
:donation_id => 555,
|
|
:towards => 'blah',
|
|
:kind => 'kind',
|
|
:statement => 'our statement<> blah-no-way'} }
|
|
let (:date) { Time.new(2002,10,31)}
|
|
let(:valid_input_with_date) { valid_input.merge(:date => date)}
|
|
|
|
it 'saves the payment and updates the charge' do
|
|
|
|
stripe_charge_id = nil
|
|
expect(Stripe::Charge).to receive(:create).with({application_fee: 33,
|
|
customer: card.stripe_customer_id,
|
|
amount: 100,
|
|
currency: 'usd',
|
|
description: 'our statement<> blah-no-way',
|
|
statement_descriptor: 'our statement blah-n',
|
|
metadata: nil
|
|
}, {stripe_account: nonprofit.stripe_account_id}).and_wrap_original{|m, *args| a= m.call(*args);
|
|
stripe_charge_id = a['id']
|
|
a}
|
|
|
|
|
|
finished_result = InsertCharge.with_stripe(valid_input)
|
|
|
|
common_charge_expected = {id: Charge.first.id, amount: 100, fee: 33, stripe_charge_id:stripe_charge_id, status: 'pending', failure_message: nil, created_at: Time.now, updated_at: Time.now, disbursed: nil}
|
|
|
|
result_charge_expected = common_charge_expected.merge({card_id: card.id, nonprofit_id: nonprofit.id, donation_id: 555, supporter_id: supporter.id, ticket_id: nil, payment_id: Payment.first.id, profile_id: nil, direct_debit_detail_id: nil}).with_indifferent_access
|
|
|
|
expect(finished_result['charge'].attributes).to eq result_charge_expected
|
|
expect(Charge.first.attributes).to eq result_charge_expected
|
|
expect(Charge.count).to eq 1
|
|
|
|
|
|
common_payment_expected = {id: Payment.first.id,
|
|
gross_amount: 100,
|
|
fee_total: -33,
|
|
net_amount: 67,
|
|
towards: 'blah',
|
|
kind: 'kind',
|
|
donation_id: 555,
|
|
nonprofit_id: nonprofit.id,
|
|
supporter_id: supporter.id,
|
|
refund_total: 0,
|
|
date: Time.now,
|
|
created_at: Time.now,
|
|
updated_at: Time.now,
|
|
search_vectors: nil
|
|
}.with_indifferent_access
|
|
|
|
expect(finished_result['payment'].attributes).to eq common_payment_expected
|
|
expect(Payment.first.attributes).to eq common_payment_expected
|
|
expect(Payment.count).to eq 1
|
|
|
|
end
|
|
|
|
it 'saves the payment and updates the charge with passed date' do
|
|
|
|
stripe_charge_id = nil
|
|
expect(Stripe::Charge).to receive(:create).with({application_fee: 33,
|
|
customer: card.stripe_customer_id,
|
|
amount: 100,
|
|
currency: 'usd',
|
|
description: 'our statement<> blah-no-way',
|
|
statement_descriptor: 'our statement blah-n',
|
|
metadata: nil
|
|
}, {stripe_account: nonprofit.stripe_account_id}).and_wrap_original{|m, *args| a= m.call(*args);
|
|
stripe_charge_id = a['id']
|
|
a}
|
|
|
|
|
|
finished_result = InsertCharge.with_stripe(valid_input_with_date)
|
|
|
|
common_charge_expected = {id: Charge.first.id, amount: 100, fee: 33, stripe_charge_id:stripe_charge_id, status: 'pending', failure_message: nil, created_at: Time.now, updated_at: Time.now, disbursed: nil}
|
|
|
|
|
|
result_charge_expected = common_charge_expected.merge({card_id: card.id, nonprofit_id: nonprofit.id, donation_id: 555, supporter_id: supporter.id, ticket_id: nil, payment_id: Payment.first.id, profile_id: nil, direct_debit_detail_id: nil}).with_indifferent_access
|
|
|
|
|
|
expect(finished_result['charge'].attributes).to eq result_charge_expected
|
|
expect(Charge.first.attributes).to eq result_charge_expected
|
|
expect(Charge.count).to eq 1
|
|
|
|
|
|
common_payment_expected = {id: Payment.first.id,
|
|
gross_amount: 100,
|
|
fee_total: -33,
|
|
net_amount: 67,
|
|
towards: 'blah',
|
|
kind: 'kind',
|
|
donation_id: 555,
|
|
nonprofit_id: nonprofit.id,
|
|
supporter_id: supporter.id,
|
|
refund_total: 0,
|
|
date: date,
|
|
created_at: Time.now,
|
|
updated_at: Time.now,
|
|
search_vectors: nil
|
|
}.with_indifferent_access
|
|
|
|
expect(finished_result['payment'].attributes).to eq common_payment_expected
|
|
expect(Payment.first.attributes).to eq common_payment_expected
|
|
expect(Payment.count).to eq 1
|
|
|
|
end
|
|
|
|
end
|
|
end
|
|
|
|
describe 'charge when customer belongs to us' do
|
|
before(:each){
|
|
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!
|
|
new_cust = Stripe::Customer.create()
|
|
card_for_other_supporter.stripe_customer_id = new_cust['id']
|
|
card_for_other_supporter.save!
|
|
# StripeMock.prepare_error(Stripe::StripeError.new("chaos"), :get_customer)
|
|
}
|
|
|
|
|
|
|
|
def create_expected_charge_args(expected_card)
|
|
[{application_fee: 33,
|
|
customer: expected_card.stripe_customer_id,
|
|
amount: 100,
|
|
currency: 'usd',
|
|
description: 'our statement<> blah-no-way',
|
|
statement_descriptor: 'our statement blah-n',
|
|
metadata: nil,
|
|
destination: nonprofit.stripe_account_id
|
|
}, {}]
|
|
end
|
|
|
|
it 'handles card error' do
|
|
|
|
expect(Stripe::Charge).to receive(:create).with(*create_expected_charge_args(card)).and_wrap_original{|m, *args| m.call(*args)}
|
|
StripeMock.prepare_card_error(:card_declined)
|
|
|
|
finished_result = InsertCharge.with_stripe(amount: 100,
|
|
:nonprofit_id => nonprofit.id,
|
|
:supporter_id => supporter.id,
|
|
:card_id => card.id,
|
|
:statement => 'our statement<> blah-no-way')
|
|
|
|
common_expected = {id: Charge.first.id, amount: 100, fee: 33, stripe_charge_id: nil, status: 'failed', failure_message: 'There was an error with your card: The card was declined', created_at: Time.now, updated_at: Time.now, disbursed: nil}
|
|
|
|
|
|
result_expected = common_expected.merge({card_id: card.id, nonprofit_id: nonprofit.id, donation_id: nil, supporter_id: supporter.id, ticket_id: nil, payment_id: nil, profile_id: nil, direct_debit_detail_id: nil}).with_indifferent_access
|
|
|
|
expect(finished_result['charge'].attributes).to eq result_expected
|
|
expect(Charge.first.attributes).to eq result_expected
|
|
|
|
expect(Payment).to_not be_exists
|
|
|
|
|
|
end
|
|
|
|
it 'handles general Stripe error' do
|
|
|
|
expect(Stripe::Charge).to receive(:create).with(*create_expected_charge_args(card)).and_wrap_original{|m, *args| m.call(*args)}
|
|
StripeMock.prepare_error(Stripe::StripeError.new("blah"), :new_charge)
|
|
|
|
finished_result = InsertCharge.with_stripe(amount: 100,
|
|
:nonprofit_id => nonprofit.id,
|
|
:supporter_id => supporter.id,
|
|
:card_id => card.id,
|
|
:statement => 'our statement<> blah-no-way')
|
|
|
|
common_expected = {id: Charge.first.id, amount: 100, fee: 33, stripe_charge_id: nil, status: 'failed', failure_message: "We're sorry, but something went wrong. We've been notified about this issue.", created_at: Time.now, updated_at: Time.now, disbursed: nil}
|
|
|
|
|
|
result_expected = common_expected.merge({card_id: card.id, nonprofit_id: nonprofit.id, donation_id: nil, supporter_id: supporter.id, ticket_id: nil, payment_id: nil, profile_id: nil, direct_debit_detail_id: nil}).with_indifferent_access
|
|
|
|
expect(finished_result['charge'].attributes).to eq result_expected
|
|
expect(Charge.first.attributes).to eq result_expected
|
|
|
|
expect(Payment).to_not be_exists
|
|
|
|
end
|
|
describe 'input success' do
|
|
|
|
|
|
|
|
let (:date) { Time.new(2002,10,31)}
|
|
|
|
|
|
it 'saves the payment and updates the charge' do
|
|
saves_the_payment_updates_the_charge(card)
|
|
end
|
|
|
|
it 'saves the payment and updates the charge, if old rd and using wrong card' do
|
|
saves_the_payment_updates_the_charge(card_for_other_supporter, true)
|
|
end
|
|
|
|
it 'saves the payment and updates the charge with passed date' do
|
|
saves_the_payment_and_updates_the_charge_with_passed_date(card)
|
|
end
|
|
|
|
it 'saves the payment and updates the charge with passed date, if old rd and using wrong card' do
|
|
saves_the_payment_and_updates_the_charge_with_passed_date(card, true)
|
|
end
|
|
|
|
def insert_charge_input(expected_card, pass_old_donation=nil, pass_date=nil)
|
|
inner = {amount: 100,
|
|
:nonprofit_id => nonprofit.id,
|
|
:supporter_id => supporter.id,
|
|
card_id: expected_card.id,
|
|
:donation_id => 555,
|
|
:towards => 'blah',
|
|
:kind => 'kind',
|
|
:statement => 'our statement<> blah-no-way',
|
|
}
|
|
|
|
if pass_old_donation
|
|
inner = inner.merge(old_donation: true)
|
|
end
|
|
|
|
if pass_date
|
|
inner = inner.merge(date: date)
|
|
end
|
|
|
|
inner
|
|
end
|
|
|
|
def saves_the_payment_updates_the_charge(expected_card, pass_old_donation=nil)
|
|
|
|
stripe_charge_id = nil
|
|
expect(Stripe::Charge).to receive(:create).with(*create_expected_charge_args(expected_card)).and_wrap_original{|m, *args| a= m.call(*args);
|
|
stripe_charge_id = a['id']
|
|
a}
|
|
|
|
|
|
finished_result = InsertCharge.with_stripe(insert_charge_input(expected_card, pass_old_donation))
|
|
|
|
common_charge_expected = {id: Charge.first.id, amount: 100, fee: 33, stripe_charge_id:stripe_charge_id, status: 'pending', failure_message: nil, created_at: Time.now, updated_at: Time.now, disbursed: nil}
|
|
|
|
|
|
result_charge_expected = common_charge_expected.merge({card_id: expected_card.id, nonprofit_id: nonprofit.id, donation_id: 555, supporter_id: supporter.id, ticket_id: nil, payment_id: Payment.first.id, profile_id: nil, direct_debit_detail_id: nil}).with_indifferent_access
|
|
|
|
|
|
expect(finished_result['charge'].attributes).to eq result_charge_expected
|
|
expect(Charge.first.attributes).to eq result_charge_expected
|
|
expect(Charge.count).to eq 1
|
|
|
|
|
|
common_payment_expected = {id: Payment.first.id,
|
|
gross_amount: 100,
|
|
fee_total: -33,
|
|
net_amount: 67,
|
|
towards: 'blah',
|
|
kind: 'kind',
|
|
donation_id: 555,
|
|
nonprofit_id: nonprofit.id,
|
|
supporter_id: supporter.id,
|
|
refund_total: 0,
|
|
date: Time.now,
|
|
created_at: Time.now,
|
|
updated_at: Time.now,
|
|
search_vectors: nil
|
|
}.with_indifferent_access
|
|
|
|
expect(finished_result['payment'].attributes).to eq common_payment_expected
|
|
expect(Payment.first.attributes).to eq common_payment_expected
|
|
expect(Payment.count).to eq 1
|
|
|
|
end
|
|
|
|
def saves_the_payment_and_updates_the_charge_with_passed_date(expected_card, pass_old_donation=nil)
|
|
|
|
stripe_charge_id = nil
|
|
expect(Stripe::Charge).to receive(:create).with(*create_expected_charge_args(expected_card)).and_wrap_original{|m, *args| a= m.call(*args);
|
|
stripe_charge_id = a['id']
|
|
a}
|
|
|
|
|
|
finished_result = InsertCharge.with_stripe(insert_charge_input(expected_card, pass_old_donation, true))
|
|
|
|
common_charge_expected = {id: Charge.first.id, amount: 100, fee: 33, stripe_charge_id:stripe_charge_id, status: 'pending', failure_message: nil, created_at: Time.now, updated_at: Time.now, disbursed: nil}
|
|
|
|
|
|
result_charge_expected = common_charge_expected.merge({card_id: card.id, nonprofit_id: nonprofit.id, donation_id: 555, supporter_id: supporter.id, ticket_id: nil, payment_id: Payment.first.id, profile_id: nil, direct_debit_detail_id: nil}).with_indifferent_access
|
|
|
|
|
|
expect(finished_result['charge'].attributes).to eq result_charge_expected
|
|
expect(Charge.first.attributes).to eq result_charge_expected
|
|
expect(Charge.count).to eq 1
|
|
|
|
|
|
common_payment_expected = {id: Payment.first.id,
|
|
gross_amount: 100,
|
|
fee_total: -33,
|
|
net_amount: 67,
|
|
towards: 'blah',
|
|
kind: 'kind',
|
|
donation_id: 555,
|
|
nonprofit_id: nonprofit.id,
|
|
supporter_id: supporter.id,
|
|
refund_total: 0,
|
|
date: date,
|
|
created_at: Time.now,
|
|
updated_at: Time.now,
|
|
search_vectors: nil
|
|
}.with_indifferent_access
|
|
|
|
expect(finished_result['payment'].attributes).to eq common_payment_expected
|
|
expect(Payment.first.attributes).to eq common_payment_expected
|
|
expect(Payment.count).to eq 1
|
|
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|